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.
pub fn read_lines(path string) ?[]string {
buf := read_file(path) or {
return err
return error(err)
}
return buf.split_into_lines()
}
fn read_ulines(path string) ?[]ustring {
lines := read_lines(path) or {
return err
return error(err)
}
// mut ulines := new_array(0, lines.len, sizeof(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 {
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
if struct_init.fields.len == 0 {
// 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) {
if ast.expr_is_blank_ident(assign_expr.left) {
return
}
left_type := c.expr(assign_expr.left)
c.expected_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')
right_type := c.expr(assign_expr.val)
assign_expr.right_type = right_type
if ast.expr_is_blank_ident(assign_expr.left) {
return
}
if !c.table.check(right_type, left_type) {
left_type_sym := c.table.get_type_symbol(left_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 {
fn_name := call_expr.name
c.stmts(call_expr.or_block.stmts)
// TODO: impl typeof properly (probably not going to be a fn call)
if fn_name == 'typeof' {
return table.string_type
}
// start hack: until v1 is fixed and c definitions are added for these
if fn_name == 'C.calloc' {
return table.byteptr_type
}
else if fn_name == 'C.exit' {
return table.void_type
}
else if fn_name == 'C.free' {
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' {
return table.byteptr_type
}
return table.void_type
}
// end hack
@ -224,6 +224,7 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
}
if !found {
c.error('unknown fn: $fn_name', call_expr.pos)
return table.void_type
}
call_expr.return_type = f.return_type
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
typ_sym := c.table.get_type_symbol(typ)
name := method_call_expr.name
c.stmts(method_call_expr.or_block.stmts)
// println('method call $name $method_call_expr.pos.line_nr')
if typ_sym.kind == .array && name in ['filter', 'clone', 'repeat'] {
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
})
}
else if name == 'repeat' {
c.expr(method_call_expr.args[0].expr)
for i, arg in method_call_expr.args {
c.expr(arg.expr)
}
// need to return `array_xxx` instead of `array`
method_call_expr.return_type = typ
// method_call_expr.receiver_type = typ
return typ
}
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]
if array_init.exprs.len > 0 && array_init.elem_type == table.void_type {
for i, expr in array_init.exprs {
c.expr(expr)
typ := c.expr(expr)
// The first element's type
if i == 0 {

View File

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

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
if p.tok.kind == .key_orelse {
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{
name: fn_name
args: args
// tok: tok
pos: tok.position()
is_c: is_c
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 {
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)
mut stmts := []ast.Stmt
if p.tok.kind != .rcbr {
@ -205,9 +213,6 @@ pub fn (p mut Parser) parse_block() []ast.Stmt {
}
}
p.check(.rcbr)
// println('parse block')
p.close_scope()
// println('nr exprs in block = $exprs.len')
return stmts
}
@ -945,15 +950,21 @@ fn (p mut Parser) dot_expr(left ast.Expr) ast.Expr {
// p.close_scope()
// }
}
// Method call
pos := p.tok.position()
// Method call
if p.tok.kind == .lpar {
p.next()
args := p.call_args()
mut or_stmts := []ast.Stmt
if p.tok.kind == .key_orelse {
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{
expr: left