checker/gen: add unchecked exprs & small fixes

pull/4055/head
Joe Conigliaro 2020-03-18 19:56:19 +11:00
parent a011b8951a
commit 126ef0f5c2
5 changed files with 58 additions and 40 deletions

View File

@ -235,14 +235,14 @@ fn vfopen(path, mode string) &C.FILE {
// read_lines reads the file in `path` into an array of lines. // read_lines reads the file in `path` into an array of lines.
pub fn read_lines(path string) ?[]string { pub fn read_lines(path string) ?[]string {
buf := read_file(path) or { buf := read_file(path) or {
return err return error(err)
} }
return buf.split_into_lines() return buf.split_into_lines()
} }
fn read_ulines(path string) ?[]ustring { fn read_ulines(path string) ?[]ustring {
lines := read_lines(path) or { lines := read_lines(path) or {
return err return error(err)
} }
// mut ulines := new_array(0, lines.len, sizeof(ustring)) // mut ulines := new_array(0, lines.len, sizeof(ustring))
mut ulines := []ustring mut ulines := []ustring

View File

@ -82,7 +82,8 @@ pub fn (c mut Checker) check_struct_init(struct_init ast.StructInit) table.Type
.placeholder { .placeholder {
c.error('unknown struct: $typ_sym.name', struct_init.pos) c.error('unknown struct: $typ_sym.name', struct_init.pos)
} }
.struct_ { // string & array are also structs but .kind of string/array
.struct_, .string, .array {
info := typ_sym.info as table.Struct info := typ_sym.info as table.Struct
if struct_init.fields.len == 0 { if struct_init.fields.len == 0 {
// Short syntax TODO check // Short syntax TODO check
@ -154,17 +155,15 @@ pub fn (c mut Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
} }
fn (c mut Checker) assign_expr(assign_expr mut ast.AssignExpr) { fn (c mut Checker) assign_expr(assign_expr mut ast.AssignExpr) {
if ast.expr_is_blank_ident(assign_expr.left) {
return
}
left_type := c.expr(assign_expr.left) left_type := c.expr(assign_expr.left)
c.expected_type = left_type c.expected_type = left_type
assign_expr.left_type = left_type assign_expr.left_type = left_type
// assign_expr.left_type = left_type
// t := c.table.get_type_symbol(left_type)
// println('setting exp type to $c.expected_type $t.name') // println('setting exp type to $c.expected_type $t.name')
right_type := c.expr(assign_expr.val) right_type := c.expr(assign_expr.val)
assign_expr.right_type = right_type assign_expr.right_type = right_type
if ast.expr_is_blank_ident(assign_expr.left) {
return
}
if !c.table.check(right_type, left_type) { if !c.table.check(right_type, left_type) {
left_type_sym := c.table.get_type_symbol(left_type) left_type_sym := c.table.get_type_symbol(left_type)
right_type_sym := c.table.get_type_symbol(right_type) right_type_sym := c.table.get_type_symbol(right_type)
@ -174,18 +173,19 @@ fn (c mut Checker) assign_expr(assign_expr mut ast.AssignExpr) {
pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type { pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
fn_name := call_expr.name fn_name := call_expr.name
c.stmts(call_expr.or_block.stmts)
// TODO: impl typeof properly (probably not going to be a fn call) // TODO: impl typeof properly (probably not going to be a fn call)
if fn_name == 'typeof' { if fn_name == 'typeof' {
return table.string_type return table.string_type
} }
// start hack: until v1 is fixed and c definitions are added for these // start hack: until v1 is fixed and c definitions are added for these
if fn_name in ['C.calloc', 'C.exit', 'C.free'] {
for arg in call_expr.args {
c.expr(arg.expr)
}
if fn_name == 'C.calloc' { if fn_name == 'C.calloc' {
return table.byteptr_type return table.byteptr_type
} }
else if fn_name == 'C.exit' {
return table.void_type
}
else if fn_name == 'C.free' {
return table.void_type return table.void_type
} }
// end hack // end hack
@ -224,6 +224,7 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
} }
if !found { if !found {
c.error('unknown fn: $fn_name', call_expr.pos) c.error('unknown fn: $fn_name', call_expr.pos)
return table.void_type
} }
call_expr.return_type = f.return_type call_expr.return_type = f.return_type
if f.is_c || call_expr.is_c { if f.is_c || call_expr.is_c {
@ -275,6 +276,7 @@ pub fn (c mut Checker) method_call_expr(method_call_expr mut ast.MethodCallExpr)
method_call_expr.expr_type = typ method_call_expr.expr_type = typ
typ_sym := c.table.get_type_symbol(typ) typ_sym := c.table.get_type_symbol(typ)
name := method_call_expr.name name := method_call_expr.name
c.stmts(method_call_expr.or_block.stmts)
// println('method call $name $method_call_expr.pos.line_nr') // println('method call $name $method_call_expr.pos.line_nr')
if typ_sym.kind == .array && name in ['filter', 'clone', 'repeat'] { if typ_sym.kind == .array && name in ['filter', 'clone', 'repeat'] {
if name == 'filter' { if name == 'filter' {
@ -285,12 +287,11 @@ pub fn (c mut Checker) method_call_expr(method_call_expr mut ast.MethodCallExpr)
typ: array_info.elem_type typ: array_info.elem_type
}) })
} }
else if name == 'repeat' { for i, arg in method_call_expr.args {
c.expr(method_call_expr.args[0].expr) c.expr(arg.expr)
} }
// need to return `array_xxx` instead of `array` // need to return `array_xxx` instead of `array`
method_call_expr.return_type = typ method_call_expr.return_type = typ
// method_call_expr.receiver_type = typ
return typ return typ
} }
else if typ_sym.kind == .array && name in ['first', 'last'] { else if typ_sym.kind == .array && name in ['first', 'last'] {
@ -466,7 +467,6 @@ pub fn (c mut Checker) array_init(array_init mut ast.ArrayInit) table.Type {
// [1,2,3] // [1,2,3]
if array_init.exprs.len > 0 && array_init.elem_type == table.void_type { if array_init.exprs.len > 0 && array_init.elem_type == table.void_type {
for i, expr in array_init.exprs { for i, expr in array_init.exprs {
c.expr(expr)
typ := c.expr(expr) typ := c.expr(expr)
// The first element's type // The first element's type
if i == 0 { if i == 0 {

View File

@ -412,7 +412,7 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
else { else {
g.write('{$styp _ = ') g.write('{$styp _ = ')
g.expr(val) g.expr(val)
g.writeln('}') g.writeln(';}')
} }
} }
else { else {
@ -575,7 +575,7 @@ fn (g mut Gen) expr(node ast.Expr) {
else { else {
g.write('{${g.typ(it.left_type)} _ = ') g.write('{${g.typ(it.left_type)} _ = ')
g.expr(it.val) g.expr(it.val)
g.writeln('}') g.writeln(';}')
} }
} }
else { else {
@ -732,12 +732,13 @@ fn (g mut Gen) expr(node ast.Expr) {
} }
} }
ast.MethodCallExpr { ast.MethodCallExpr {
mut receiver_name := 'TODO'
// TODO: there are still due to unchecked exprs (opt/some fn arg) // TODO: there are still due to unchecked exprs (opt/some fn arg)
if it.expr_type != 0 { if it.expr_type == 0 {
verror('method receiver type is 0, this means there are some uchecked exprs')
}
typ_sym := g.table.get_type_symbol(it.expr_type) typ_sym := g.table.get_type_symbol(it.expr_type)
// rec_sym := g.table.get_type_symbol(it.receiver_type) // rec_sym := g.table.get_type_symbol(it.receiver_type)
receiver_name = typ_sym.name mut receiver_name := typ_sym.name
if typ_sym.kind == .array && it.name in if typ_sym.kind == .array && it.name in
// TODO performance, detect `array` method differently // TODO performance, detect `array` method differently
['repeat', 'sort_with_compare', 'free', 'push_many', 'trim', 'first', 'clone'] { ['repeat', 'sort_with_compare', 'free', 'push_many', 'trim', 'first', 'clone'] {
@ -746,7 +747,6 @@ fn (g mut Gen) expr(node ast.Expr) {
// `array_byte_clone` => `array_clone` // `array_byte_clone` => `array_clone`
receiver_name = 'array' receiver_name = 'array'
} }
}
name := '${receiver_name}_$it.name'.replace('.', '__') name := '${receiver_name}_$it.name'.replace('.', '__')
// if it.receiver_type != 0 { // if it.receiver_type != 0 {
// g.write('/*${g.typ(it.receiver_type)}*/') // g.write('/*${g.typ(it.receiver_type)}*/')

View File

@ -17,12 +17,19 @@ pub fn (p mut Parser) call_expr(is_c bool, mod string) ast.CallExpr {
mut or_stmts := []ast.Stmt mut or_stmts := []ast.Stmt
if p.tok.kind == .key_orelse { if p.tok.kind == .key_orelse {
p.next() p.next()
or_stmts = p.parse_block() p.open_scope()
p.scope.register_var(ast.Var{
name: 'err'
typ: table.type_to_optional(table.string_type)
})
or_stmts = p.parse_block_no_scope()
p.close_scope()
} }
node := ast.CallExpr{ node := ast.CallExpr{
name: fn_name name: fn_name
args: args args: args
// tok: tok // tok: tok
pos: tok.position() pos: tok.position()
is_c: is_c is_c: is_c
or_block: ast.OrExpr{ or_block: ast.OrExpr{

View File

@ -193,6 +193,14 @@ pub fn (p mut Parser) close_scope() {
pub fn (p mut Parser) parse_block() []ast.Stmt { pub fn (p mut Parser) parse_block() []ast.Stmt {
p.open_scope() p.open_scope()
// println('parse block')
stmts := p.parse_block_no_scope()
p.close_scope()
// println('nr exprs in block = $exprs.len')
return stmts
}
pub fn (p mut Parser) parse_block_no_scope() []ast.Stmt {
p.check(.lcbr) p.check(.lcbr)
mut stmts := []ast.Stmt mut stmts := []ast.Stmt
if p.tok.kind != .rcbr { if p.tok.kind != .rcbr {
@ -205,9 +213,6 @@ pub fn (p mut Parser) parse_block() []ast.Stmt {
} }
} }
p.check(.rcbr) p.check(.rcbr)
// println('parse block')
p.close_scope()
// println('nr exprs in block = $exprs.len')
return stmts return stmts
} }
@ -945,15 +950,21 @@ fn (p mut Parser) dot_expr(left ast.Expr) ast.Expr {
// p.close_scope() // p.close_scope()
// } // }
} }
// Method call
pos := p.tok.position() pos := p.tok.position()
// Method call
if p.tok.kind == .lpar { if p.tok.kind == .lpar {
p.next() p.next()
args := p.call_args() args := p.call_args()
mut or_stmts := []ast.Stmt mut or_stmts := []ast.Stmt
if p.tok.kind == .key_orelse { if p.tok.kind == .key_orelse {
p.next() p.next()
or_stmts = p.parse_block() p.open_scope()
p.scope.register_var(ast.Var{
name: 'err'
typ: table.type_to_optional(table.string_type)
})
or_stmts = p.parse_block_no_scope()
p.close_scope()
} }
mcall_expr := ast.MethodCallExpr{ mcall_expr := ast.MethodCallExpr{
expr: left expr: left