all: add UnsafeExpr (#5793)

pull/5814/head
Nick Treleaven 2020-07-12 11:58:33 +01:00 committed by GitHub
parent cad816a19d
commit 53023c1ca9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 78 additions and 2 deletions

View File

@ -13,7 +13,7 @@ pub type Expr = AnonFn | ArrayInit | AsCast | Assoc | BoolLiteral | CallExpr | C
CharLiteral | ComptimeCall | ConcatExpr | EnumVal | FloatLiteral | Ident | IfExpr | IfGuardExpr |
IndexExpr | InfixExpr | IntegerLiteral | Likely | LockExpr | MapInit | MatchExpr | None |
OrExpr | ParExpr | PostfixExpr | PrefixExpr | RangeExpr | SelectorExpr | SizeOf | SqlExpr |
StringInterLiteral | StringLiteral | StructInit | Type | TypeOf
StringInterLiteral | StringLiteral | StructInit | Type | TypeOf | UnsafeExpr
pub type Stmt = AssertStmt | AssignStmt | Attr | Block | BranchStmt | Comment | CompFor |
CompIf | ConstDecl | DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt |
@ -446,6 +446,12 @@ pub mut:
left_as_name string // only used in x is SumType check
}
pub struct UnsafeExpr {
pub:
stmts []Stmt
pos token.Position
}
pub struct LockExpr {
pub:
stmts []Stmt

View File

@ -254,6 +254,9 @@ pub fn (x Expr) str() string {
Likely {
return '_likely_(${it.expr.str()})'
}
UnsafeExpr {
return 'unsafe { $it.stmts.len stmts }'
}
else {
return '[unhandled expr type ${typeof(x)}]'
}

View File

@ -2031,6 +2031,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
c.type_decl(node)
}
ast.UnsafeStmt {
assert !c.inside_unsafe
c.inside_unsafe = true
c.stmts(node.stmts)
c.inside_unsafe = false
@ -2291,6 +2292,9 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
node.expr_type = c.expr(node.expr)
return table.string_type
}
ast.UnsafeExpr {
return c.unsafe_expr(mut node)
}
ast.Likely {
ltype := c.expr(node.expr)
if !c.check_types(ltype, table.bool_type) {
@ -2630,6 +2634,34 @@ pub fn (mut c Checker) lock_expr(mut node ast.LockExpr) table.Type {
return table.void_type
}
pub fn (mut c Checker) unsafe_expr(mut node ast.UnsafeExpr) table.Type {
slen := node.stmts.len
if slen > 1 {
c.error('FIXME: unsafe expression block should support multiple statements',
node.pos)
return table.none_type
}
if slen == 0 {
c.error('unsafe expression does not yield an expression', node.pos)
return table.none_type
}
assert !c.inside_unsafe
c.inside_unsafe = true
defer {
c.inside_unsafe = false
}
if slen > 1 {
c.stmts(node.stmts[0..slen - 1])
}
last := node.stmts[0]
if last is ast.ExprStmt {
t := c.expr(last.expr)
return t
}
c.error('unsafe expression does not yield an expression', node.pos)
return table.none_type
}
pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
mut expr_required := false
if c.expected_type != table.void_type {

View File

@ -1051,6 +1051,11 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
f.expr(node.expr)
f.write(')')
}
ast.UnsafeExpr {
f.writeln('unsafe {')
f.stmts(it.stmts)
f.writeln('}')
}
}
}

View File

@ -1837,6 +1837,10 @@ fn (mut g Gen) expr(node ast.Expr) {
g.expr(node.expr)
g.write(')')
}
ast.UnsafeExpr {
es := node.stmts[0] as ast.ExprStmt
g.expr(es.expr)
}
}
}

View File

@ -633,6 +633,10 @@ fn (mut g JsGen) expr(node ast.Expr) {
ast.ComptimeCall {
// TODO
}
ast.UnsafeExpr {
es := it.stmts[0] as ast.ExprStmt
g.expr(es.expr)
}
}
}

View File

@ -572,6 +572,7 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
}
.key_unsafe {
p.next()
assert !p.inside_unsafe
p.inside_unsafe = true
stmts := p.parse_block()
p.inside_unsafe = false

View File

@ -79,6 +79,18 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
.key_if {
node = p.if_expr()
}
.key_unsafe {
p.next()
pos := p.tok.position()
assert !p.inside_unsafe
p.inside_unsafe = true
stmts := p.parse_block()
p.inside_unsafe = false
node = ast.UnsafeExpr {
stmts: stmts
pos: pos
}
}
.key_lock, .key_rlock {
node = p.lock_expr()
}

View File

@ -6,11 +6,20 @@ fn test_ptr_arithmetic(){
p += 2
p = p - 1
}
assert p == unsafe {&v + 2}
p = unsafe { p + 1 }
assert p == unsafe {&v + 3}
r := unsafe { p++ }
assert r == unsafe {&v + 3}
assert p == unsafe {&v + 4}
// byteptr, voidptr, charptr are handled differently
mut q := byteptr(1)
mut q := byteptr(10)
unsafe {
q -= 2
q = q + 1
}
assert q == byteptr(9)
s := unsafe { q - 1 }
assert s == byteptr(8)
}