diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 7369c99adc..bc4f6e0b11 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -20,7 +20,7 @@ HashStmt pub struct ExprStmt { pub: expr Expr - ti table.Type + typ table.TypeRef } pub struct IntegerLiteral { @@ -69,7 +69,7 @@ pub struct Field { pub: name string // type_idx int - typ table.Type + typ table.TypeRef } pub struct ConstDecl { @@ -89,7 +89,7 @@ pub: pub struct StructInit { pub: pos token.Position - ti table.Type + typ table.TypeRef fields []string exprs []Expr } @@ -105,7 +105,7 @@ pub: pub struct Arg { pub: - ti table.Type + typ table.TypeRef name string } @@ -113,7 +113,7 @@ pub struct FnDecl { pub: name string stmts []Stmt - ti table.Type + typ table.TypeRef args []Arg is_pub bool receiver Field @@ -145,9 +145,9 @@ pub: pub struct Return { pub: - pos token.Position - expected_ti table.Type // TODO: remove once checker updated - exprs []Expr + pos token.Position + expected_type table.TypeRef // TODO: remove once checker updated + exprs []Expr } /* @@ -172,7 +172,7 @@ pub: expr Expr is_mut bool mut: - typ table.Type + typ table.TypeRef pos token.Position } @@ -181,7 +181,7 @@ pub: name string expr Expr mut: - typ table.Type + typ table.TypeRef } pub struct File { @@ -194,9 +194,9 @@ pub: } pub struct IdentVar { -pub: - typ table.Type - // name string +pub mut: + typ table.TypeRef + //name string } type IdentInfo = IdentVar @@ -225,9 +225,9 @@ pub: op token.Kind pos token.Position left Expr - left_type table.Type + left_type table.TypeRef right Expr - right_type table.Type + right_type table.TypeRef } /* @@ -241,7 +241,6 @@ pub: } */ - pub struct PostfixExpr { pub: op token.Kind @@ -270,7 +269,7 @@ pub: cond Expr stmts []Stmt else_stmts []Stmt - ti table.Type + typ table.TypeRef left Expr // `a` in `a := if ...` pos token.Position } @@ -354,7 +353,8 @@ pub struct ArrayInit { pub: pos token.Position exprs []Expr - ti table.Type +mut: + typ table.TypeRef } // s[10..20] diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index c325388d66..6de8cf0863 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -14,7 +14,7 @@ pub struct Checker { mut: file_name string unresolved []ast.Expr - resolved []table.Type + resolved []table.TypeRef } pub fn new_checker(table &table.Table) Checker { @@ -39,59 +39,88 @@ pub fn (c mut Checker) check_files(ast_files []ast.File) { } fn (c mut Checker) resolve_types() { + // resolve type of unresolved expressions for x in c.unresolved { c.resolved << c.expr(x) } + // update any types with unresolved sub types + for idx, t in c.table.types { + if t.kind == .array { + mut info := t.info as table.Array + if info.elem_type.typ.kind == .unresolved { + info.elem_type = c.resolved[info.elem_type.idx] + mut t1 := &c.table.types[idx] + t1.name = table.array_name(&info.elem_type, info.nr_dims) + t1.info = info + } + } + else if t.kind == .map { + mut info := t.info as table.Map + mut updated := false + if info.key_type.typ.kind == .unresolved { + info.key_type = c.resolved[info.key_type.idx] + updated = true + } + if info.value_type.typ.kind == .unresolved { + info.value_type = c.resolved[info.value_type.idx] + updated = true + } + if updated { + mut t1 := &c.table.types[idx] + t1.name = table.map_name(&info.key_type, &info.value_type) + t1.info = info + } + } + } } -pub fn (c &Checker) check_struct_init(struct_init ast.StructInit) table.Type { - typ := c.table.find_type(struct_init.ti.name) or { - c.error('unknown struct: $struct_init.ti.name', struct_init.pos) +pub fn (c &Checker) check_struct_init(struct_init ast.StructInit) table.TypeRef { + typ := c.table.find_type(struct_init.typ.typ.name) or { + c.error('unknown struct: $struct_init.typ.typ.name', struct_init.pos) panic('') } match typ.kind { .placeholder { - c.error('unknown struct: $struct_init.ti.name', struct_init.pos) + c.error('unknown struct: $struct_init.typ.typ.name', struct_init.pos) } .struct_ { info := typ.info as table.Struct for i, expr in struct_init.exprs { field := info.fields[i] - // expr_ti := c.expr(expr) field_type := c.expr(expr) - if !c.table.check(field_type, field.ti) { - c.error('cannot assign $field_type.name as $field.ti.name for field $field.name', struct_init.pos) + if !c.table.check(field_type, field.typ) { + c.error('cannot assign $field_type.typ.name as $field.typ.typ.name for field $field.name', struct_init.pos) } } } else {} } - return struct_init.ti + return struct_init.typ } -pub fn (c &Checker) infix_expr(infix_expr ast.InfixExpr) table.Type { - left_ti := c.expr(infix_expr.left) - right_ti := c.expr(infix_expr.right) - if !c.table.check(&right_ti, &left_ti) { +pub fn (c &Checker) infix_expr(infix_expr ast.InfixExpr) table.TypeRef { + left_type := c.expr(infix_expr.left) + right_type := c.expr(infix_expr.right) + if !c.table.check(&right_type, &left_type) { // if !c.table.check(&infix_expr.right_type, &infix_expr.right_type) { // c.error('infix expr: cannot use `$infix_expr.right_type.name` as `$infix_expr.left_type.name`', infix_expr.pos) - c.error('infix expr: cannot use `$left_ti.name` as `$right_ti.name`', infix_expr.pos) + c.error('infix expr: cannot use `$left_type.typ.name` as `$right_type.typ.name`', infix_expr.pos) } if infix_expr.op.is_relational() { - return table.bool_type + return c.table.type_ref(table.bool_type_idx) } - return left_ti + return left_type } fn (c &Checker) check_assign_expr(assign_expr ast.AssignExpr) { - left_ti := c.expr(assign_expr.left) - right_ti := c.expr(assign_expr.val) - if !c.table.check(right_ti, left_ti) { - c.error('cannot assign $right_ti.name to $left_ti.name', assign_expr.pos) + left_type := c.expr(assign_expr.left) + right_type := c.expr(assign_expr.val) + if !c.table.check(right_type, left_type) { + c.error('cannot assign $right_type.typ.name to $left_type.typ.name', assign_expr.pos) } } -pub fn (c &Checker) call_expr(call_expr ast.CallExpr) table.Type { +pub fn (c &Checker) call_expr(call_expr ast.CallExpr) table.TypeRef { fn_name := call_expr.name if f := c.table.find_fn(fn_name) { // return_ti := f.return_ti @@ -103,9 +132,9 @@ pub fn (c &Checker) call_expr(call_expr ast.CallExpr) table.Type { } for i, arg in f.args { arg_expr := call_expr.args[i] - ti := c.expr(arg_expr) - if !c.table.check(&ti, &arg.typ) { - c.error('!cannot use type `$ti.name` as type `$arg.typ.name` in argument to `$fn_name`', call_expr.pos) + typ := c.expr(arg_expr) + if !c.table.check(&typ, &arg.typ) { + c.error('!cannot use type `$typ.typ.name` as type `$arg.typ.typ.name` in argument to `$fn_name`', call_expr.pos) } } return f.return_type @@ -114,83 +143,75 @@ pub fn (c &Checker) call_expr(call_expr ast.CallExpr) table.Type { exit(1) } -pub fn (c &Checker) check_method_call_expr(method_call_expr ast.MethodCallExpr) table.Type { - ti := c.expr(method_call_expr.expr) - if method := c.table.find_method(ti.idx, method_call_expr.name) { +pub fn (c &Checker) check_method_call_expr(method_call_expr ast.MethodCallExpr) table.TypeRef { + typ := c.expr(method_call_expr.expr) + if method := typ.typ.find_method(method_call_expr.name) { return method.return_type } - c.error('type `$ti.name` has no method `$method_call_expr.name`', method_call_expr.pos) + c.error('type `$typ.typ.name` has no method `$method_call_expr.name`', method_call_expr.pos) exit(1) } -pub fn (c &Checker) selector_expr(selector_expr ast.SelectorExpr) table.Type { - ti := c.expr(selector_expr.expr) +pub fn (c &Checker) selector_expr(selector_expr ast.SelectorExpr) table.TypeRef { + typ := c.expr(selector_expr.expr) field_name := selector_expr.field - // struct_ := c.table.types[ti.idx] - // struct_info := struct_.info as table.Struct - typ := c.table.types[ti.idx] - match typ.kind { + match typ.typ.kind { .struct_ { - // if !c.table.struct_has_field(it, field) { - // c.error('AAA unknown field `${it.name}.$field`') - // } - // TODO: fix bug - field := c.table.struct_find_field(typ, field_name) or { - c.error('unknown field `${typ.name}.$field_name`', selector_expr.pos) + field := c.table.struct_find_field(typ.typ, field_name) or { + c.error('unknown field `${typ.typ.name}.$field_name`', selector_expr.pos) exit(0) } - return field.ti + return field.typ } else { - c.error('`$typ.name` is not a struct', selector_expr.pos) + c.error('`$typ.typ.name` is not a struct', selector_expr.pos) } } - return table.void_type + return c.table.type_ref(table.void_type_idx) } // TODO: non deferred pub fn (c &Checker) return_stmt(return_stmt ast.Return) { - mut got_tis := []table.Type + mut got_types := []table.TypeRef if return_stmt.exprs.len == 0 { return } for expr in return_stmt.exprs { - ti := c.expr(expr) - got_tis << ti + typ := c.expr(expr) + got_types << typ } - expected_ti := return_stmt.expected_ti - mut expected_tis := [expected_ti] - if expected_ti.kind == .multi_return { - mr_type := c.table.types[expected_ti.idx] - mr_info := mr_type.info as table.MultiReturn - expected_tis = mr_info.tis + expected_type := return_stmt.expected_type + mut expected_types := [expected_type] + if expected_type.typ.kind == .multi_return { + mr_info := expected_type.typ.info as table.MultiReturn + expected_types = mr_info.types } - if expected_tis.len > 0 && expected_tis.len != got_tis.len { - c.error('wrong number of return arguments:\n\texpected: $expected_tis.str()\n\tgot: $got_tis.str()', return_stmt.pos) + if expected_types.len > 0 && expected_types.len != got_types.len { + c.error('wrong number of return arguments:\n\texpected: $expected_types.str()\n\tgot: $got_types.str()', return_stmt.pos) } - for i, exp_ti in expected_tis { - got_ti := got_tis[i] - if !c.table.check(got_ti, exp_ti) { - c.error('cannot use `$got_ti.name` as type `$exp_ti.name` in return argument', return_stmt.pos) + for i, exp_typ in expected_types { + got_typ := got_types[i] + if !c.table.check(got_typ, exp_typ) { + c.error('cannot use `$got_typ.typ.name` as type `$exp_typ.typ.name` in return argument', return_stmt.pos) } } } -pub fn (c &Checker) array_init(array_init ast.ArrayInit) table.Type { - mut val_ti := table.void_type +pub fn (c &Checker) array_init(array_init ast.ArrayInit) table.TypeRef { + mut elem_type := c.table.type_ref(table.void_type_idx) for i, expr in array_init.exprs { c.expr(expr) - ti := c.expr(expr) + typ := c.expr(expr) // The first element's type if i == 0 { - val_ti = ti + elem_type = typ continue } - if !c.table.check(val_ti, ti) { - c.error('expected array element with type `$val_ti.name`', array_init.pos) + if !c.table.check(elem_type, typ) { + c.error('expected array element with type `$elem_type.typ.name`', array_init.pos) } } - return array_init.ti + return array_init.typ } fn (c &Checker) stmt(node ast.Stmt) { @@ -205,19 +226,14 @@ fn (c &Checker) stmt(node ast.Stmt) { } ast.VarDecl { typ := c.expr(it.expr) - // it.typ = typ // println('checker: var decl $typ.name it.typ=$it.typ.name $it.pos.line_nr') - if typ.kind != .void { + if typ.typ.kind != .void { it.typ = typ } - // if it.typ.kind == .unresolved { - // it.ti = typ - // println('unresolved var') - // } } ast.ForStmt { typ := c.expr(it.cond) - if typ.kind != .bool { + if typ.typ.kind != .bool { c.error('non-bool used as for condition', it.pos) } for stmt in it.stmts { @@ -240,13 +256,13 @@ fn (c &Checker) stmt(node ast.Stmt) { } } -pub fn (c &Checker) expr(node ast.Expr) table.Type { - match node { +pub fn (c &Checker) expr(node ast.Expr) table.TypeRef { + match mut node { ast.AssignExpr { c.check_assign_expr(it) } ast.IntegerLiteral { - return table.int_type + return c.table.type_ref(table.int_type_idx) } // ast.FloatLiteral {} ast.PostfixExpr { @@ -259,7 +275,7 @@ pub fn (c &Checker) expr(node ast.Expr) table.Type { */ ast.StringLiteral { - return table.string_type + return c.table.type_ref(table.string_type_idx) } ast.PrefixExpr { return c.expr(it.right) @@ -281,16 +297,19 @@ pub fn (c &Checker) expr(node ast.Expr) table.Type { } ast.Ident { if it.kind == .variable { - info := it.info as ast.IdentVar - if info.typ.kind == .unresolved { - return c.resolved[info.typ.idx] + mut info := it.info as ast.IdentVar + if info.typ.typ.kind == .unresolved { + typ := c.resolved[info.typ.idx] + info.typ = typ + it.info = info + return typ } return info.typ } - return table.void_type + return c.table.type_ref(table.void_type_idx) } ast.BoolLiteral { - return table.bool_type + return c.table.type_ref(table.bool_type_idx) } ast.SelectorExpr { return c.selector_expr(it) @@ -300,8 +319,8 @@ pub fn (c &Checker) expr(node ast.Expr) table.Type { } ast.IfExpr { typ := c.expr(it.cond) - if typ.kind != .bool { - c.error('non-bool (`$typ.name`) used as if condition', it.pos) + if typ.typ.kind != .bool { + c.error('non-bool (`$typ.typ.name`) used as if condition', it.pos) } for i, stmt in it.stmts { c.stmt(stmt) @@ -314,10 +333,10 @@ pub fn (c &Checker) expr(node ast.Expr) table.Type { } else {} } - return table.void_type + return c.table.type_ref(table.void_type_idx) } -pub fn (c &Checker) postfix_expr(node ast.PostfixExpr) table.Type { +pub fn (c &Checker) postfix_expr(node ast.PostfixExpr) table.TypeRef { /* match node.expr { ast.IdentVar { @@ -327,13 +346,13 @@ pub fn (c &Checker) postfix_expr(node ast.PostfixExpr) table.Type { } */ typ := c.expr(node.expr) - if typ.kind != .int { - c.error('invalid operation: $node.op.str() (non-numeric type `$typ.name`)', node.pos) + if typ.typ.kind != .int { + c.error('invalid operation: $node.op.str() (non-numeric type `$typ.typ.name`)', node.pos) } return typ } -pub fn (c &Checker) index_expr(node ast.IndexExpr) table.Type { +pub fn (c &Checker) index_expr(node ast.IndexExpr) table.TypeRef { mut typ := c.expr(node.left) mut is_range := false // TODO is_range := node.index is ast.RangeExpr match node.index { @@ -342,28 +361,20 @@ pub fn (c &Checker) index_expr(node ast.IndexExpr) table.Type { } else {} } - // TODO - // info := ti.info as table.Array - // ti = p.table.types[info.elem_type_idx] - if typ.name.starts_with('array_') { + if typ.typ.kind == .array { if is_range {} // `x[start..end]` has the same type as `x` else { - elm_typ := typ.name[6..] - // TODO `typ = ... or ...` - x := c.table.find_type(elm_typ) or { - c.error(elm_typ, node.pos) - exit(0) - } - typ = x // Check index type index_type := c.expr(node.index) - if index_type.kind != .int { - c.error('non-integer index (type `$index_type.name`)', node.pos) + if index_type.typ.kind != .int { + c.error('non-integer index (type `$index_type.typ.name`)', node.pos) } + info := typ.typ.info as table.Array + return info.elem_type } } else { - typ = table.int_type + typ = c.table.type_ref(table.int_type_idx) } return typ // c.expr(it.index) diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index f5a9688461..0479bf3bb6 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -49,7 +49,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { ast.Import {} ast.ConstDecl { for i, field in it.fields { - g.write('$field.typ.name $field.name = ') + g.write('$field.typ.typ.name $field.name = ') g.expr(it.exprs[i]) g.writeln(';') } @@ -61,15 +61,12 @@ fn (g mut Gen) stmt(node ast.Stmt) { g.write('int ${it.name}(') } else { - ti := g.table.refresh_ti(it.ti) - g.write('$ti.name ${it.name}(') - g.definitions.write('$ti.name ${it.name}(') + g.write('$it.typ.typ.name ${it.name}(') + g.definitions.write('$it.typ.typ.name ${it.name}(') } for i, arg in it.args { - // t := g.table.get_type(arg.ti.idx) - ti := g.table.refresh_ti(arg.ti) - g.write(ti.name + ' ' + arg.name) - g.definitions.write(ti.name + ' ' + arg.name) + g.write(arg.typ.typ.name + ' ' + arg.name) + g.definitions.write(arg.typ.typ.name + ' ' + arg.name) if i < it.args.len - 1 { g.write(', ') g.definitions.write(', ') @@ -92,9 +89,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { g.write('return') // multiple returns if it.exprs.len > 1 { - // ttln( := g.table.get_type(g.fn_decl.ti.idx) - ti := g.table.refresh_ti(g.fn_decl.ti) - g.write(' ($ti.name){') + g.write(' ($g.fn_decl.typ.typ.name){') for i, expr in it.exprs { g.write('.arg$i=') g.expr(expr) @@ -112,7 +107,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { g.writeln(';') } ast.VarDecl { - g.write('$it.typ.name $it.name = ') + g.write('$it.typ.typ.name $it.name = ') g.expr(it.expr) g.writeln(';') } @@ -141,9 +136,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { ast.StructDecl { g.writeln('typedef struct {') for field in it.fields { - // t := g.table.get_type(field.ti.idx) - ti := g.table.refresh_ti(field.typ) - g.writeln('\t$ti.name $field.name;') + g.writeln('\t$field.typ.typ.name $field.name;') } g.writeln('} $it.name;') } @@ -215,9 +208,7 @@ fn (g mut Gen) expr(node ast.Expr) { } // `user := User{name: 'Bob'}` ast.StructInit { - // t := g.table.get_type(it.ti.idx) - ti := g.table.refresh_ti(it.ti) - g.writeln('($ti.name){') + g.writeln('($it.typ.typ.name){') for i, field in it.fields { g.write('\t.$field = ') g.expr(it.exprs[i]) @@ -237,9 +228,7 @@ fn (g mut Gen) expr(node ast.Expr) { } ast.MethodCallExpr {} ast.ArrayInit { - // t := g.table.get_type(it.ti.idx) - ti := g.table.refresh_ti(it.ti) - g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($ti.name), {\t') + g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.typ.typ.name), {\t') for expr in it.exprs { g.expr(expr) g.write(', ') @@ -268,9 +257,9 @@ fn (g mut Gen) expr(node ast.Expr) { ast.IfExpr { // If expression? Assign the value to a temp var. // Previously ?: was used, but it's too unreliable. - ti := g.table.refresh_ti(it.ti) + // ti := g.table.refresh_ti(it.ti) mut tmp := '' - if ti.kind != .void { + if it.typ.typ.kind != .void { tmp = g.table.new_tmp_var() // g.writeln('$ti.name $tmp;') } @@ -279,7 +268,7 @@ fn (g mut Gen) expr(node ast.Expr) { g.writeln(') {') for i, stmt in it.stmts { // Assign ret value - if i == it.stmts.len - 1 && ti.kind != .void { + if i == it.stmts.len - 1 && it.typ.typ.kind != .void { // g.writeln('$tmp =') println(1) } diff --git a/vlib/v/gen/cgen_test.v b/vlib/v/gen/cgen_test.v index 5e9c1da332..7f91f5b080 100644 --- a/vlib/v/gen/cgen_test.v +++ b/vlib/v/gen/cgen_test.v @@ -11,9 +11,6 @@ const ( ) fn test_c_files() { - $if windows { - return - } println('Running V => C tests') vexe := os.getenv('VEXE') vroot := filepath.dir(vexe) @@ -21,9 +18,14 @@ fn test_c_files() { term_fail := term.fail_message('FAIL') for i in 1 .. nr_tests + 1 { path := '$vroot/vlib/v/gen/tests/${i}.vv' - ctext := os.read_file('$vroot/vlib/v/gen/tests/${i}.c') or { + mut ctext := os.read_file('$vroot/vlib/v/gen/tests/${i}.c') or { panic(err) } + ctext = ctext // unused warn + // normalise line endings on win + $if windows { + ctext = ctext.replace('\r', '') + } mut b := builder.new_builder(pref.Preferences{}) res := b.gen_c([path]) if compare_texts(res, ctext) { diff --git a/vlib/v/gen/jsgen.v b/vlib/v/gen/jsgen.v index 71c8f644ae..4363d79b1d 100644 --- a/vlib/v/gen/jsgen.v +++ b/vlib/v/gen/jsgen.v @@ -37,11 +37,9 @@ pub fn (g mut JsGen) writeln(s string) { fn (g mut JsGen) stmt(node ast.Stmt) { match node { ast.FnDecl { - ti := g.table.refresh_ti(it.ti) - g.write('/** @return { $ti.name } **/\nfunction ${it.name}(') + g.write('/** @return { $it.typ.typ.name } **/\nfunction ${it.name}(') for arg in it.args { - arg_ti := g.table.refresh_ti(arg.ti) - g.write(' /** @type { $arg_ti.name } **/ $arg.name') + g.write(' /** @type { $arg.typ.typ.name } **/ $arg.name') } g.writeln(') { ') for stmt in it.stmts { @@ -58,8 +56,7 @@ fn (g mut JsGen) stmt(node ast.Stmt) { g.writeln(';') } ast.VarDecl { - typ := g.table.refresh_ti(it.typ) - g.write('var /* $typ.name */ $it.name = ') + g.write('var /* $it.typ.typ.name */ $it.name = ') g.expr(it.expr) g.writeln(';') } @@ -121,8 +118,7 @@ fn (g mut JsGen) expr(node ast.Expr) { } // `user := User{name: 'Bob'}` ast.StructInit { - ti := g.table.refresh_ti(it.ti) - g.writeln('/*$ti.name*/{') + g.writeln('/*$it.typ.typ.name*/{') for i, field in it.fields { g.write('\t$field : ') g.expr(it.exprs[i]) diff --git a/vlib/v/gen/tests/1.vv b/vlib/v/gen/tests/1.vv index 959ff4ad4f..71f02aa4ff 100644 --- a/vlib/v/gen/tests/1.vv +++ b/vlib/v/gen/tests/1.vv @@ -85,7 +85,7 @@ fn myuser() { x := 1 q := x | 0x1004 user := User{age:10} - age := user.age + 1 + age := user.age + 1 // crash here boo := 2 boo2 := boo+1 b := age > 0 diff --git a/vlib/v/gen/tests/4.c b/vlib/v/gen/tests/4.c index d20392ff06..06a6d233cc 100644 --- a/vlib/v/gen/tests/4.c +++ b/vlib/v/gen/tests/4.c @@ -5,51 +5,57 @@ int testa(); int testb(); int testa(); int main() { -Bar b = (Bar){ + Bar b = (Bar){ .a = 122, -}; -Foo a = (Foo){ + }; + Foo a = (Foo){ .a = tos3("hello"), .b = b, -}; -a.a = tos3("da"); -a.b.a = 111; -string a1 = a.a; -int a2 = ; -int c = testa(); -c = 1; -string d = testb(1); -d = tos3("hello"); -string e = tos3("hello"); -e = testb(111); -e = tos3("world"); -return 0; + }; + a.a = tos3("da"); + a.b.a = 111; + string a1 = a.a; + int a2 = ; + int c = testa(); + c = 1; + string d = testb(1); + d = tos3("hello"); + string e = tos3("hello"); + e = testb(111); + e = tos3("world"); + array_int f = new_array_from_c_array(4, 4, sizeof(array_int), { + testa(), 2, 3, 4, + }); + array_string g = new_array_from_c_array(2, 2, sizeof(array_string), { + testb(1), tos3("hello"), + }); + return 0; } int testa() { -return testc(1); + return testc(1); } string testb(int a) { -return tos3("hello"); + return tos3("hello"); } int testc(int a) { -return a; + return a; } int testa() { -int a = ; -a = 1; -return 4; + int a = ; + a = 1; + return 4; } int testb() { -return 4; + return 4; } int testa() { -return 4; + return 4; } typedef struct { diff --git a/vlib/v/gen/tests/4.vv b/vlib/v/gen/tests/4.vv index d5b44f0b1d..2145892da0 100644 --- a/vlib/v/gen/tests/4.vv +++ b/vlib/v/gen/tests/4.vv @@ -13,7 +13,6 @@ fn main() { a: 'hello' b: b } - // a.c = 'sa' a.a = 'da' a.b.a = 111 @@ -29,10 +28,8 @@ fn main() { e = testb(111) e = 'world' - //mut f := [testa(),2,3,4] - // f = testa() - // c := 1 + 'string' - // zz := hi + 1 + mut f := [testa(),2,3,4] + mut g := [testb(1),'hello'] } diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index aed31a0776..7293d66385 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -8,7 +8,7 @@ import ( v.table ) -pub fn (p mut Parser) call_expr() (ast.CallExpr,table.Type) { +pub fn (p mut Parser) call_expr() (ast.CallExpr,table.TypeRef) { tok := p.tok fn_name := p.check_name() p.check(.lpar) @@ -18,7 +18,6 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,table.Type) { name: fn_name args: args // tok: tok - pos: tok.position() } if p.tok.kind == .key_orelse { @@ -28,7 +27,7 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,table.Type) { if f := p.table.find_fn(fn_name) { return node,f.return_type } - typ := p.add_unresolved(node) + typ := p.add_unresolved('${fn_name}()', node) return node,typ } @@ -65,7 +64,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl { // Receiver? mut rec_name := '' mut is_method := false - mut rec_ti := table.void_type + mut rec_type := p.table.type_ref(table.void_type_idx) if p.tok.kind == .lpar { is_method = true p.next() @@ -73,10 +72,10 @@ fn (p mut Parser) fn_decl() ast.FnDecl { if p.tok.kind == .key_mut { p.next() } - rec_ti = p.parse_type() + rec_type = p.parse_type() p.table.register_var(table.Var{ name: rec_name - typ: rec_ti + typ: rec_type }) p.check(.rpar) } @@ -120,19 +119,19 @@ fn (p mut Parser) fn_decl() ast.FnDecl { if p.tok.kind == .key_mut { p.check(.key_mut) } - ti := p.parse_type() + typ := p.parse_type() for arg_name in arg_names { arg := table.Var{ name: arg_name - typ: ti + typ: typ } args << arg p.table.register_var(arg) ast_args << ast.Arg{ - ti: ti + typ: typ name: arg_name } - if ti.kind == .variadic && p.tok.kind == .comma { + if typ.typ.kind == .variadic && p.tok.kind == .comma { p.error('cannot use ...(variadic) with non-final parameter $arg_name') } } @@ -143,16 +142,17 @@ fn (p mut Parser) fn_decl() ast.FnDecl { } p.check(.rpar) // Return type - mut typ := table.void_type + mut typ := p.table.type_ref(table.void_type_idx) if p.tok.kind in [.name, .lpar, .amp, .lsbr, .question] { typ = p.parse_type() p.return_type = typ } else { - p.return_type = table.void_type + // p.return_type = table.void_type + p.return_type = typ } if is_method { - ok := p.table.register_method(rec_ti, table.Fn{ + ok := p.table.register_method(rec_type.typ, table.Fn{ name: name args: args return_type: typ @@ -175,28 +175,13 @@ fn (p mut Parser) fn_decl() ast.FnDecl { return ast.FnDecl{ name: name stmts: stmts - ti: typ + typ: typ args: ast_args is_pub: is_pub receiver: ast.Field{ name: rec_name - typ: rec_ti + typ: rec_type } } } -pub fn (p &Parser) check_fn_calls() { - println('check fn calls2') - /* - for call in p.table.unknown_calls { - f := p.table.find_fn(call.name) or { - p.error_at_line('unknown function `$call.name`', call.tok.line_nr) - return - } - println(f.name) - // println(f.return_ti.name) - // println('IN AST typ=' + call.typ.name) - } - */ - -} diff --git a/vlib/v/parser/parse_type.v b/vlib/v/parser/parse_type.v index dc30b52ad5..8d4fa4d4e5 100644 --- a/vlib/v/parser/parse_type.v +++ b/vlib/v/parser/parse_type.v @@ -6,7 +6,7 @@ import ( v.table ) -pub fn (p mut Parser) parse_array_ti(nr_muls int) table.Type { +pub fn (p mut Parser) parse_array_ti(nr_muls int) table.TypeRef { p.check(.lsbr) // fixed array if p.tok.kind == .number { @@ -14,8 +14,8 @@ pub fn (p mut Parser) parse_array_ti(nr_muls int) table.Type { elem_ti := p.parse_type() p.check(.rsbr) p.check_name() - idx,name := p.table.find_or_register_array_fixed(&elem_ti, size, 1) - return table.new_type(.array_fixed, name, idx, nr_muls) + idx := p.table.find_or_register_array_fixed(elem_ti, size, 1) + return p.table.type_ref_ptr(idx, nr_muls) } // array p.check(.rsbr) @@ -26,29 +26,30 @@ pub fn (p mut Parser) parse_array_ti(nr_muls int) table.Type { p.check(.rsbr) nr_dims++ } - idx,name := p.table.find_or_register_array(&elem_ti, nr_dims) - return table.new_type(.array, name, idx, nr_muls) + idx := p.table.find_or_register_array(elem_ti, nr_dims) + return p.table.type_ref_ptr(idx, nr_muls) } -pub fn (p mut Parser) parse_map_type(nr_muls int) table.Type { +pub fn (p mut Parser) parse_map_type(nr_muls int) table.TypeRef { if p.tok.kind != .lsbr { - return table.map_type + // check notes in table/atypes.v near map_type_idx + return p.table.type_ref(p.table.type_idxs['map']) } p.next() p.check(.lsbr) key_ti := p.parse_type() p.check(.rsbr) value_ti := p.parse_type() - idx,name := p.table.find_or_register_map(&key_ti, &value_ti) - return table.new_type(.map, name, idx, nr_muls) + idx := p.table.find_or_register_map(key_ti, value_ti) + return p.table.type_ref_ptr(idx, nr_muls) } -pub fn (p mut Parser) parse_multi_return_ti() table.Type { +pub fn (p mut Parser) parse_multi_return_ti() table.TypeRef { p.check(.lpar) - mut mr_tis := []table.Type + mut mr_types := []table.TypeRef for { - mr_ti := p.parse_type() - mr_tis << mr_ti + mr_type := p.parse_type() + mr_types << mr_type if p.tok.kind == .comma { p.check(.comma) } @@ -57,24 +58,24 @@ pub fn (p mut Parser) parse_multi_return_ti() table.Type { } } p.check(.rpar) - idx,name := p.table.find_or_register_multi_return(mr_tis) - return table.new_type(.multi_return, name, idx, 0) + idx := p.table.find_or_register_multi_return(mr_types) + return p.table.type_ref(idx) } -pub fn (p mut Parser) parse_variadic_ti() table.Type { +pub fn (p mut Parser) parse_variadic_ti() table.TypeRef { p.check(.ellipsis) - variadic_ti := p.parse_type() - idx,name := p.table.find_or_register_variadic(&variadic_ti) - return table.new_type(.variadic, name, idx, 0) + variadic_type := p.parse_type() + idx := p.table.find_or_register_variadic(variadic_type) + return p.table.type_ref(idx) } -pub fn (p mut Parser) parse_fn_type() table.Type { +pub fn (p mut Parser) parse_fn_type() table.TypeRef { // p.check(.key_fn) p.fn_decl() - return table.int_type + return p.table.type_ref(table.int_type_idx) } -pub fn (p mut Parser) parse_type() table.Type { +pub fn (p mut Parser) parse_type() table.TypeRef { mut nr_muls := 0 for p.tok.kind == .amp { p.check(.amp) @@ -120,63 +121,64 @@ pub fn (p mut Parser) parse_type() table.Type { return p.parse_map_type(nr_muls) } 'voidptr' { - return table.new_type(.voidptr, 'voidptr', table.voidptr_type_idx, nr_muls) + return p.table.type_ref_ptr(table.voidptr_type_idx, nr_muls) } 'byteptr' { - return table.new_type(.byteptr, 'byteptr', table.byteptr_type_idx, nr_muls) + return p.table.type_ref_ptr(table.byteptr_type_idx, nr_muls) } 'charptr' { - return table.new_type(.charptr, 'charptr', table.charptr_type_idx, nr_muls) + return p.table.type_ref_ptr(table.charptr_type_idx, nr_muls) } 'i8' { - return table.new_type(.i8, 'i8', table.i8_type_idx, nr_muls) + return p.table.type_ref_ptr(table.i8_type_idx, nr_muls) } 'i16' { - return table.new_type(.i16, 'i16', table.i16_type_idx, nr_muls) + return p.table.type_ref_ptr(table.i16_type_idx, nr_muls) } 'int' { - return table.new_type(.int, 'int', table.int_type_idx, nr_muls) + return p.table.type_ref_ptr(table.int_type_idx, nr_muls) } 'i64' { - return table.new_type(.i64, 'i64', table.i64_type_idx, nr_muls) + return p.table.type_ref_ptr(table.i64_type_idx, nr_muls) } 'byte' { - return table.new_type(.byte, 'byte', table.byte_type_idx, nr_muls) + return p.table.type_ref_ptr(table.byte_type_idx, nr_muls) } 'u16' { - return table.new_type(.u16, 'u16', table.u16_type_idx, nr_muls) + return p.table.type_ref_ptr(table.u16_type_idx, nr_muls) } 'u32' { - return table.new_type(.u32, 'u32', table.u32_type_idx, nr_muls) + return p.table.type_ref_ptr(table.u32_type_idx, nr_muls) } 'u64' { - return table.new_type(.u64, 'u64', table.u64_type_idx, nr_muls) + return p.table.type_ref_ptr(table.u64_type_idx, nr_muls) } 'f32' { - return table.new_type(.f32, 'f32', table.f32_type_idx, nr_muls) + return p.table.type_ref_ptr(table.f32_type_idx, nr_muls) } 'f64' { - return table.new_type(.f64, 'f64', table.f64_type_idx, nr_muls) + return p.table.type_ref_ptr(table.f64_type_idx, nr_muls) } 'string' { - return table.new_type(.string, 'string', table.string_type_idx, nr_muls) + return p.table.type_ref_ptr(table.string_type_idx, nr_muls) } 'char' { - return table.new_type(.char, 'char', table.charptr_type_idx, nr_muls) + return p.table.type_ref_ptr(table.charptr_type_idx, nr_muls) } 'bool' { - return table.new_type(.bool, 'bool', table.bool_type_idx, nr_muls) + return p.table.type_ref_ptr(table.bool_type_idx, nr_muls) } // struct / enum / placeholder else { // struct / enum mut idx := p.table.find_type_idx(name) if idx > 0 { - return table.new_type(p.table.types[idx].kind, name, idx, nr_muls) + return p.table.type_ref_ptr(idx, nr_muls) } // not found - add placeholder idx = p.table.add_placeholder_type(name) - return table.new_type(.placeholder, name, idx, nr_muls) + println('NOT FOUND: $name - adding placeholder - $idx') + return p.table.type_ref_ptr(idx, nr_muls) } } } diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index b3869f5f87..2e907c6fde 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -33,7 +33,7 @@ mut: peek_tok token.Token // vars []string table &table.Table - return_type table.Type // current function's return type + return_type table.TypeRef // current function's return type // scope_level int // var_idx int is_c bool @@ -44,6 +44,7 @@ mut: builtin_mod bool mod string unresolved []ast.Expr + unresolved_idxs map[string]int } // for tests @@ -244,10 +245,10 @@ pub fn (p mut Parser) stmt() ast.Stmt { if p.tok.kind == .name && p.peek_tok.kind in [.decl_assign, .comma] { return p.var_decl() } - expr,ti := p.expr(0) + expr,typ := p.expr(0) return ast.ExprStmt{ expr: expr - ti: ti + typ: typ } } } @@ -298,8 +299,8 @@ fn (p mut Parser) range_expr(low ast.Expr) ast.Expr { } p.check(.dotdot) high,typ := p.expr(0) - if typ.kind != .int { - p.error('non-integer index `$typ.name`') + if typ.typ.kind != .int { + p.error('non-integer index `$typ.typ.name`') } node := ast.RangeExpr{ low: low @@ -369,9 +370,9 @@ pub fn (p &Parser) warn(s string) { } } -pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) { +pub fn (p mut Parser) name_expr() (ast.Expr,table.TypeRef) { mut node := ast.Expr{} - mut typ := table.void_type + mut typ := p.table.type_ref(table.void_type_idx) // mut typ := table.unresolved_type is_c := p.tok.lit == 'C' && p.peek_tok.kind == .dot if is_c { @@ -416,7 +417,7 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) { exprs << expr } node = ast.StructInit{ - ti: typ + typ: typ exprs: exprs fields: field_names pos: p.tok.position() @@ -431,25 +432,23 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) { } // variable if var := p.table.find_var(p.tok.lit) { - // println('#### IDENT: $var.name: $var.typ.name - $var.typ.idx') + // println('#### IDENT: $var.name: $var.typ.typ.name - $var.typ.idx') typ = var.typ ident.kind = .variable ident.info = ast.IdentVar{ typ: typ // name: ident.name // expr: p.expr(0)// var.expr - } // ident.ti = ti node = ident p.next() }else{ if is_c { - typ = table.int_type + typ = p.table.type_ref(table.int_type_idx) ident.info = ast.IdentVar{ typ: typ // name: ident.name - } node = ident p.next() @@ -462,7 +461,6 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) { ident.info = ast.IdentVar{ typ: typ // name: ident.name - } node = ident p.next() @@ -479,9 +477,9 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) { return node,typ } -pub fn (p mut Parser) expr(precedence int) (ast.Expr,table.Type) { +pub fn (p mut Parser) expr(precedence int) (ast.Expr,table.TypeRef) { // println('\n\nparser.expr()') - mut typ := table.void_type + mut typ := p.table.type_ref(table.void_type_idx) mut node := ast.Expr{} // Prefix match p.tok.kind { @@ -492,7 +490,7 @@ pub fn (p mut Parser) expr(precedence int) (ast.Expr,table.Type) { node,typ = p.string_expr() } .chartoken { - typ = table.byte_type + typ = p.table.type_ref(table.byte_type_idx) node = ast.CharLiteral{ val: p.tok.lit } @@ -509,7 +507,7 @@ pub fn (p mut Parser) expr(precedence int) (ast.Expr,table.Type) { node = ast.BoolLiteral{ val: p.tok.kind == .key_true } - typ = table.bool_type + typ = p.table.type_ref(table.bool_type_idx) p.next() } .key_match { @@ -537,7 +535,7 @@ pub fn (p mut Parser) expr(precedence int) (ast.Expr,table.Type) { p.check(.lpar) p.next() p.check(.rpar) - typ = table.int_type + typ = p.table.type_ref(table.int_type_idx) } else { p.error('pexpr(): bad token `$p.tok.str()`') @@ -573,16 +571,16 @@ pub fn (p mut Parser) expr(precedence int) (ast.Expr,table.Type) { return node,typ } -fn (p mut Parser) prefix_expr() (ast.Expr,table.Type) { +fn (p mut Parser) prefix_expr() (ast.Expr,table.TypeRef) { op := p.tok.kind p.next() - right,ti := p.expr(1) + right,typ := p.expr(1) mut expr := ast.Expr{} expr = ast.PrefixExpr{ op: op right: right } - return expr,ti + return expr,typ } // fn (p mut Parser) index_expr(left ast.Expr, typ_ table.Type) (ast.Expr,table.Type) { @@ -605,21 +603,20 @@ fn (p mut Parser) index_expr(left ast.Expr) ast.Expr { // println('got ]') // /ti := table.int_type mut node := ast.Expr{} + // println('index expr: $typ.typ.name') node = ast.IndexExpr{ left: left index: index_expr pos: p.tok.position() // typ: typ - } return node // return node,typ } -fn (p mut Parser) dot_expr(left ast.Expr, left_ti &table.Type) (ast.Expr,table.Type) { +fn (p mut Parser) dot_expr(left ast.Expr, left_type &table.TypeRef) (ast.Expr,table.TypeRef) { p.next() field_name := p.check_name() - mut ti := table.unresolved_type // Method call if p.tok.kind == .lpar { p.next() @@ -636,38 +633,39 @@ fn (p mut Parser) dot_expr(left ast.Expr, left_ti &table.Type) (ast.Expr,table.T } mut node := ast.Expr{} node = mcall_expr - ti = p.add_unresolved(mcall_expr) - return node,ti + typ := p.add_unresolved('${left_type.typ.name}.${field_name}()', mcall_expr) + return node,typ } sel_expr := ast.SelectorExpr{ expr: left field: field_name pos: p.tok.position() } + typ := p.add_unresolved('${left_type.typ.name}.$field_name', sel_expr) mut node := ast.Expr{} node = sel_expr - return node,ti + return node,typ } -fn (p mut Parser) infix_expr(left ast.Expr) (ast.Expr,table.Type) { +fn (p mut Parser) infix_expr(left ast.Expr) (ast.Expr,table.TypeRef) { op := p.tok.kind // mut typ := p. // println('infix op=$op.str()') precedence := p.tok.precedence() p.next() - right,mut ti := p.expr(precedence) + right,mut typ := p.expr(precedence) if op.is_relational() { - ti = table.bool_type + typ = p.table.type_ref(table.bool_type_idx) } mut expr := ast.Expr{} expr = ast.InfixExpr{ left: left right: right - right_type: ti + right_type: typ op: op pos: p.tok.position() } - return expr,ti + return expr,typ } // Implementation of Pratt Precedence @@ -716,7 +714,7 @@ fn (p mut Parser) for_statement() ast.Stmt { } p.check(.semicolon) if p.tok.kind != .semicolon { - mut typ := table.Type{} + mut typ := table.TypeRef{typ:0} cond,typ = p.expr(0) } p.check(.semicolon) @@ -740,7 +738,7 @@ fn (p mut Parser) for_statement() ast.Stmt { val_name := p.check_name() p.table.register_var(table.Var{ name: val_name - typ: table.int_type + typ: p.table.type_ref(table.int_type_idx) }) } p.check(.key_in) @@ -752,7 +750,7 @@ fn (p mut Parser) for_statement() ast.Stmt { } p.table.register_var(table.Var{ name: var_name - typ: table.int_type + typ: p.table.type_ref(table.int_type_idx) }) stmts := p.parse_block() // println('nr stmts=$stmts.len') @@ -773,7 +771,7 @@ fn (p mut Parser) for_statement() ast.Stmt { } } -fn (p mut Parser) if_expr() (ast.Expr,table.Type) { +fn (p mut Parser) if_expr() (ast.Expr,table.TypeRef) { p.inside_if = true // defer { // } @@ -792,14 +790,14 @@ fn (p mut Parser) if_expr() (ast.Expr,table.Type) { else_stmts = p.parse_block() } } - mut ti := table.void_type + mut typ := p.table.type_ref(table.void_type_idx) // mut left := ast.Expr{} // If the last statement is an expression, return its type if stmts.len > 0 { match stmts[stmts.len - 1] { ast.ExprStmt { - p.warn('if expr ret $it.ti.name') - ti = it.ti + p.warn('if expr ret $it.typ.typ.name') + typ = it.typ // return node,it.ti // left = } @@ -810,22 +808,22 @@ fn (p mut Parser) if_expr() (ast.Expr,table.Type) { cond: cond stmts: stmts else_stmts: else_stmts - ti: ti + typ: typ pos: p.tok.position() // left: left } - return node,ti + return node,typ } -fn (p mut Parser) string_expr() (ast.Expr,table.Type) { +fn (p mut Parser) string_expr() (ast.Expr,table.TypeRef) { mut node := ast.Expr{} node = ast.StringLiteral{ val: p.tok.lit } if p.peek_tok.kind != .str_dollar { p.next() - return node,table.string_type + return node, p.table.type_ref(table.string_type_idx) } // Handle $ interpolation for p.tok.kind == .str { @@ -839,13 +837,13 @@ fn (p mut Parser) string_expr() (ast.Expr,table.Type) { p.next() } } - return node,table.string_type + return node, p.table.type_ref(table.string_type_idx) } -fn (p mut Parser) array_init() (ast.Expr,table.Type) { +fn (p mut Parser) array_init() (ast.Expr,table.TypeRef) { mut node := ast.Expr{} p.check(.lsbr) - mut val_type := table.void_type + mut val_type := p.table.type_ref(table.void_type_idx) mut exprs := []ast.Expr for i := 0; p.tok.kind != .rsbr; i++ { expr,typ := p.expr(0) @@ -866,27 +864,27 @@ fn (p mut Parser) array_init() (ast.Expr,table.Type) { // type_idx,type_name := p.table.find_or_register_array_fixed(val_type, 1) // node = } - type_idx,type_name := p.table.find_or_register_array(val_type, 1) - array_ti := table.new_type(.array, type_name, type_idx, 0) + // array_type := table.new_type(.array, type_name, type_idx, 0) + idx := p.table.find_or_register_array(val_type, 1) + array_type := p.table.type_ref_ptr(idx, 0) node = ast.ArrayInit{ - ti: array_ti + typ: array_type exprs: exprs pos: p.tok.position() } - return node,array_ti + return node,array_type } -fn (p mut Parser) parse_number_literal() (ast.Expr,table.Type) { +fn (p mut Parser) parse_number_literal() (ast.Expr,table.TypeRef) { lit := p.tok.lit mut node := ast.Expr{} - mut ti := table.int_type + mut ti := p.table.type_ref(table.int_type_idx) if lit.contains('.') { node = ast.FloatLiteral{ // val: lit.f64() val: lit } - // ti = table.new_builtin_ti(.f64, 0) - ti = table.new_type(.f64, 'f64', table.f64_type_idx, 0) + ti = p.table.type_ref(table.f64_type_idx) } else { node = ast.IntegerLiteral{ @@ -987,7 +985,7 @@ fn (p mut Parser) struct_decl() ast.StructDecl { } field_name := p.check_name() // p.warn('field $field_name') - ti := p.parse_type() + typ := p.parse_type() // Default value if p.tok.kind == .assign { p.next() @@ -995,19 +993,19 @@ fn (p mut Parser) struct_decl() ast.StructDecl { } ast_fields << ast.Field{ name: field_name - typ: ti + typ: typ } fields << table.Field{ name: field_name // type_idx: ti.idx - - ti: ti + typ: typ } // println('struct field $ti.name $field_name') } p.check(.rcbr) if name != 'string' { ret := p.table.register_type(table.Type{ + parent: 0 kind: .struct_ name: name info: table.Struct{ @@ -1051,7 +1049,7 @@ fn (p mut Parser) return_stmt() ast.Return { } // TODO: consider non deferred stmt := ast.Return{ - expected_ti: p.return_type + expected_type: p.return_type exprs: exprs pos: p.tok.position() } @@ -1082,7 +1080,7 @@ fn (p mut Parser) var_decl() ast.VarDecl { typ: typ }) - p.warn('var decl name=$name typ=$typ.name') + p.warn('var decl name=$name typ=$typ.typ.name') // println(p.table.names) node := ast.VarDecl{ name: name @@ -1136,7 +1134,7 @@ fn (p mut Parser) global_decl() ast.GlobalDecl { } } -fn (p mut Parser) match_expr() (ast.Expr,table.Type) { +fn (p mut Parser) match_expr() (ast.Expr,table.TypeRef) { p.check(.key_match) p.expr(0) p.check(.lcbr) @@ -1156,16 +1154,25 @@ fn (p mut Parser) match_expr() (ast.Expr,table.Type) { p.check(.rcbr) mut node := ast.Expr{} node = ast.MatchExpr{} - return node,table.void_type + return node,p.table.type_ref(table.void_type_idx) } -fn (p mut Parser) add_unresolved(expr ast.Expr) table.Type { - t := table.Type{ - idx: p.unresolved.len - kind: .unresolved - name: 'unresolved' +fn (p mut Parser) add_unresolved(key string, expr ast.Expr) table.TypeRef { + mut idx := p.unresolved.len + if key in p.unresolved_idxs { + idx = p.unresolved_idxs[key] + } + else { + p.unresolved << expr + } + t := table.TypeRef{ + idx: idx + typ: &table.Type{ + parent: 0 + kind: .unresolved + name: 'unresolved $p.unresolved.len' + } } - p.unresolved << expr return t } diff --git a/vlib/v/table/atypes.v b/vlib/v/table/atypes.v index c3cc2f49df..c85eb756ba 100644 --- a/vlib/v/table/atypes.v +++ b/vlib/v/table/atypes.v @@ -7,14 +7,19 @@ pub type TypeInfo = Array | ArrayFixed | Map | Struct | MultiReturn | Variadic pub struct Type { pub: - idx int - parent_idx int + parent &Type mut: info TypeInfo kind Kind name string methods []Fn - nr_muls int +} + +pub struct TypeRef { +pub: + idx int + typ &Type + nr_muls int } pub const ( @@ -35,7 +40,11 @@ pub const ( char_type_idx = 15 byte_type_idx = 16 bool_type_idx = 17 - map_type_idx = 18 + // currently map is parsed from builtin as a normal struct named `map` + // any maps after that are of type map with parent being the struct named `map` + // same goes for array. this works since builtin is parsed first. + // will probably go back to registering these types manually and add idx here + // map_type_idx = 18 ) pub enum Kind { @@ -68,162 +77,170 @@ pub enum Kind { unresolved } -pub const ( - unresolved_type = Type{ - kind: .unresolved - name: 'unresolved' - } - void_type = Type{ - kind: .void - name: 'void' - idx: void_type_idx - } - int_type = Type{ - kind: .int - name: 'int' - idx: int_type_idx - } - string_type = Type{ - kind: .string - name: 'string' - idx: string_type_idx - } - bool_type = Type{ - kind: .bool - name: 'bool' - idx: bool_type_idx - } - byte_type = Type{ - kind: .byte - name: 'byte' - idx: byte_type_idx - } - map_type = Type{ - kind: .map - name: 'map' - idx: map_type_idx - } -) /* pub fn (t Type) str() string { return t.name } */ - -pub fn (t &Type) str() string { +pub fn (t &TypeRef) str() string { mut muls := '' for _ in 0 .. t.nr_muls { muls += '&' } - // return '$muls$ti.name' - return '$muls$t.idx' + return '$muls$t.typ.name' } -pub fn new_type(kind Kind, name string, idx int, nr_muls int) Type { - return Type{ +[inline] +pub fn (t &Table) type_ref(idx int) TypeRef { + return TypeRef{ idx: idx - kind: kind - name: name - nr_muls: nr_muls + typ: &t.types[idx] } } +[inline] +pub fn (t &Table) type_ref_ptr(idx int, nr_muls int) TypeRef { + return TypeRef{ + idx: idx + nr_muls: nr_muls + typ: &t.types[idx] + } +} + +[inline] +pub fn array_name(elem_type &TypeRef, nr_dims int) string { + return 'array_${elem_type.typ.name}' + if nr_dims > 1 { '_${nr_dims}d' } else { '' } +} + +[inline] +pub fn array_fixed_name(elem_type &TypeRef, size int, nr_dims int) string { + return 'array_fixed_${elem_type.typ.name}_${size}' + if nr_dims > 1 { '_${nr_dims}d' } else { '' } +} + +[inline] +pub fn map_name(key_type &TypeRef, value_type &TypeRef) string { + return 'map_${key_type.typ.name}_${value_type.typ.name}' +} + pub fn (t mut Table) register_builtin_types() { // reserve index 0 so nothing can go there // save index check, 0 will mean not found t.register_type(Type{ + parent: 0 kind: .placeholder name: 'reserved_0' }) t.register_type(Type{ + parent: 0 kind: .void name: 'void' }) t.register_type(Type{ + parent: 0 kind: .voidptr name: 'voidptr' }) t.register_type(Type{ + parent: 0 kind: .charptr name: 'charptr' }) t.register_type(Type{ + parent: 0 kind: .byteptr name: 'byteptr' }) t.register_type(Type{ + parent: 0 kind: .i8 name: 'i8' }) t.register_type(Type{ + parent: 0 kind: .i16 name: 'i16' }) t.register_type(Type{ + parent: 0 kind: .int name: 'int' }) t.register_type(Type{ + parent: 0 kind: .i64 name: 'i64' }) t.register_type(Type{ + parent: 0 kind: .u16 name: 'u16' }) t.register_type(Type{ + parent: 0 kind: .u32 name: 'u32' }) t.register_type(Type{ + parent: 0 kind: .u64 name: 'u64' }) t.register_type(Type{ + parent: 0 kind: .f32 name: 'f32' }) t.register_type(Type{ + parent: 0 kind: .f64 name: 'f64' }) t.register_type(Type{ + parent: 0 kind: .string name: 'string' }) t.register_type(Type{ + parent: 0 kind: .char name: 'char' }) t.register_type(Type{ + parent: 0 kind: .byte name: 'byte' }) t.register_type(Type{ + parent: 0 kind: .bool name: 'bool' }) + t.register_type(Type{ + parent: 0 + kind: .unresolved + name: 'unresolved' + }) } [inline] -pub fn (ti &Type) is_ptr() bool { - return ti.nr_muls > 0 +pub fn (t &TypeRef) is_ptr() bool { + return t.nr_muls > 0 } [inline] -pub fn (ti &Type) is_int() bool { - return ti.kind in [.i8, .i16, .int, .i64, .byte, .u16, .u32, .u64] +pub fn (t &Type) is_int() bool { + return t.kind in [.i8, .i16, .int, .i64, .byte, .u16, .u32, .u64] } [inline] -pub fn (ti &Type) is_float() bool { - return ti.kind in [.f32, .f64] +pub fn (t &Type) is_float() bool { + return t.kind in [.f32, .f64] } [inline] -pub fn (ti &Type) is_number() bool { - return ti.is_int() || ti.is_float() +pub fn (t &Type) is_number() bool { + return t.is_int() || t.is_float() } pub fn (k Kind) str() string { @@ -271,7 +288,13 @@ pub fn (k Kind) str() string { 'byte' } .u16{ - 'u18' + 'u16' + } + .u32{ + 'u32' + } + .u64{ + 'u64' } .f32{ 'f32' @@ -336,7 +359,7 @@ pub mut: pub struct Field { pub: name string - ti Type + typ TypeRef // type_idx int } // pub struct Int { @@ -350,58 +373,40 @@ pub: // } pub struct Array { pub: - elem_type_kind Kind - elem_type_idx int - elem_is_ptr bool - nr_dims int + nr_dims int +mut: + elem_type TypeRef } pub struct ArrayFixed { pub: - elem_type_kind Kind - elem_type_idx int - elem_is_ptr bool - nr_dims int - size int + nr_dims int + size int +mut: + elem_type TypeRef } pub struct Map { -pub: - key_type_kind Kind - key_type_idx int - value_type_kind Kind - value_type_idx int +pub mut: + key_type TypeRef + value_type TypeRef } pub struct MultiReturn { pub: - name string - tis []Type + name string + types []TypeRef } pub struct Variadic { pub: - ti Type + typ TypeRef } -pub fn (t &Table) refresh_ti(ti Type) Type { - if ti.idx == 0 { - return ti - } - if ti.kind in [.placeholder, .unresolved] { - typ := t.types[ti.idx] - return { - ti | - kind:typ.kind, - name:typ.name - } - } - return ti -} - -pub fn (t &Table) get_type(idx int) Type { +[inline] +pub fn (t &Table) get_type(idx int) &Type { if idx == 0 { panic('get_type: idx 0') } - return t.types[idx] + return &t.types[idx] } diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index fa6aed1bee..1912711afe 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -25,7 +25,7 @@ pub struct Fn { pub: name string args []Var - return_type Type + return_type TypeRef } pub struct Var { @@ -37,11 +37,13 @@ pub: is_global bool scope_level int mut: - typ Type + typ TypeRef } pub fn new_table() &Table { - mut t := &Table{} + mut t := &Table{ + types: make(0, 400, sizeof(Type)) + } t.register_builtin_types() return t } @@ -77,7 +79,7 @@ pub fn (t mut Table) register_const(v Var) { t.consts[v.name] = v } -pub fn (t mut Table) register_global(name string, typ Type) { +pub fn (t mut Table) register_global(name string, typ TypeRef) { t.consts[name] = Var{ name: name typ: typ @@ -86,12 +88,11 @@ pub fn (t mut Table) register_global(name string, typ Type) { // mod: p.mod // is_mut: true // idx: -1 - } } pub fn (t mut Table) register_var(v Var) { - println('register_var: $v.name - $v.typ.name') + println('register_var: $v.name - $v.typ.typ.name') new_var := { v | idx:t.var_idx, @@ -187,24 +188,25 @@ pub fn (t mut Table) register_fn(new_fn Fn) { t.fns[new_fn.name] = new_fn } -pub fn (t mut Table) register_method(typ &Type, new_fn Fn) bool { - idx := typ.idx - println('register method `$new_fn.name` type=$typ.name idx=$typ.idx') - mut methods := t.types[idx].methods +pub fn (t &Table) register_method(typ &Type, new_fn Fn) bool { + // println('register method `$new_fn.name` type=$typ.name idx=$typ.idx') + println('register method `$new_fn.name` type=$typ.name') + mut t1 := typ + mut methods := typ.methods methods << new_fn - t.types[idx].methods = methods + t1.methods = methods return true } -pub fn (t &Table) has_method(type_idx int, name string) bool { - t.find_method(type_idx, name) or { +pub fn (t &Type) has_method(name string) bool { + t.find_method(name) or { return false } return true } -pub fn (t &Table) find_method(type_idx int, name string) ?Fn { - for method in t.types[type_idx].methods { +pub fn (t &Type) find_method(name string) ?Fn { + for method in t.methods { if method.name == name { return method } @@ -218,7 +220,11 @@ pub fn (t mut Table) new_tmp_var() string { } pub fn (t &Table) struct_has_field(s &Type, name string) bool { - println('struct_has_field($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx') + if !isnil(s.parent) { + println('struct_has_field($s.name, $name) types.len=$t.types.len s.parent=$s.parent.name') + } else { + println('struct_has_field($s.name, $name) types.len=$t.types.len s.parent=none') + } // for typ in t.types { // println('$typ.idx $typ.name') // } @@ -229,20 +235,25 @@ pub fn (t &Table) struct_has_field(s &Type, name string) bool { } pub fn (t &Table) struct_find_field(s &Type, name string) ?Field { - println('struct_find_field($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx') + if !isnil(s.parent) { + println('struct_find_field($s.name, $name) types.len=$t.types.len s.parent=$s.parent.name') + } else { + println('struct_find_field($s.name, $name) types.len=$t.types.len s.parent=none') + } info := s.info as Struct for field in info.fields { if field.name == name { return field } } - if s.parent_idx != 0 { - parent := t.types[s.parent_idx] - parent_info := s.info as Struct - println('got parent $parent.name') - for field in parent_info.fields { - if field.name == name { - return field + if !isnil(s.parent) { + if s.parent.kind == .struct_ { + parent_info := s.parent.info as Struct + println('got parent $s.parent.name') + for field in parent_info.fields { + if field.name == name { + return field + } } } } @@ -282,14 +293,15 @@ pub fn (t mut Table) register_type(typ Type) int { if ex_type.kind == typ.kind { return existing_idx } + // panic('cannot register type `$typ.name`, another type with this name exists') return -1 } + } } - } - idx := t.types.len + typ_idx := t.types.len t.types << typ - t.type_idxs[typ.name] = idx - return idx + t.type_idxs[typ.name] = typ_idx + return typ_idx } pub fn (t &Table) known_type(name string) bool { @@ -299,136 +311,127 @@ pub fn (t &Table) known_type(name string) bool { return true } -pub fn (t mut Table) find_or_register_map(key_typ &Type, value_typ &Type) (int,string) { - name := 'map_${key_typ.name}_${value_typ.name}' +pub fn (t mut Table) find_or_register_map(key_type TypeRef, value_type TypeRef) int { + name := map_name(&key_type, &value_type) // existing existing_idx := t.type_idxs[name] if existing_idx > 0 { - return existing_idx,name + return existing_idx } // register map_type := Type{ + parent: &t.types[t.type_idxs['map']] kind: .map name: name info: Map{ - key_type_idx: key_typ.idx - value_type_idx: value_typ.idx + key_type: key_type + value_type: value_type } } - idx := t.register_type(map_type) - return idx,name + return t.register_type(map_type) } -pub fn (t mut Table) find_or_register_array(elem_typ &Type, nr_dims int) (int,string) { - name := 'array_${elem_typ.name}' + if nr_dims > 1 { '_${nr_dims}d' } else { '' } +pub fn (t mut Table) find_or_register_array(elem_type TypeRef, nr_dims int) int { + name := array_name(&elem_type, nr_dims) // existing existing_idx := t.type_idxs[name] if existing_idx > 0 { - return existing_idx,name + return existing_idx } // register - parent_idx := t.type_idxs['array'] array_type := Type{ - parent_idx: parent_idx + parent: &t.types[t.type_idxs['array']] kind: .array name: name info: Array{ - elem_type_idx: elem_typ.idx - elem_is_ptr: elem_typ.is_ptr() + elem_type: elem_type nr_dims: nr_dims } } - idx := t.register_type(array_type) - return idx,name + return t.register_type(array_type) } -pub fn (t mut Table) find_or_register_array_fixed(elem_typ &Type, size int, nr_dims int) (int,string) { - name := 'array_fixed_${elem_typ.name}_${size}' + if nr_dims > 1 { '_${nr_dims}d' } else { '' } +pub fn (t mut Table) find_or_register_array_fixed(elem_type TypeRef, size int, nr_dims int) int { + name := array_fixed_name(&elem_type, size, nr_dims) // existing existing_idx := t.type_idxs[name] if existing_idx > 0 { - return existing_idx,name + return existing_idx } // register array_fixed_type := Type{ + parent: 0 kind: .array_fixed name: name info: ArrayFixed{ - elem_type_idx: elem_typ.idx - elem_is_ptr: elem_typ.is_ptr() + elem_type: elem_type size: size nr_dims: nr_dims } } - idx := t.register_type(array_fixed_type) - return idx,name + return t.register_type(array_fixed_type) } -pub fn (t mut Table) find_or_register_multi_return(mr_typs []Type) (int,string) { +pub fn (t mut Table) find_or_register_multi_return(mr_typs []TypeRef) int { mut name := 'multi_return' for mr_typ in mr_typs { - name += '_$mr_typ.name' + name += '_$mr_typ.typ.name' } // existing existing_idx := t.type_idxs[name] if existing_idx > 0 { - return existing_idx,name + return existing_idx } // register mr_type := Type{ + parent: 0 kind: .multi_return name: name info: MultiReturn{ - tis: mr_typs + types: mr_typs } } - idx := t.register_type(mr_type) - return idx,name + return t.register_type(mr_type) } -pub fn (t mut Table) find_or_register_variadic(variadic_typ &Type) (int,string) { - name := 'variadic_$variadic_typ.name' +pub fn (t mut Table) find_or_register_variadic(variadic_typ TypeRef) int { + name := 'variadic_$variadic_typ.typ.name' // existing existing_idx := t.type_idxs[name] if existing_idx > 0 { - return existing_idx,name + return existing_idx } // register variadic_type := Type{ + parent: 0 kind: .variadic name: name info: Variadic{ - ti: variadic_typ + typ: variadic_typ } } - idx := t.register_type(variadic_type) - return idx,name + return t.register_type(variadic_type) } pub fn (t mut Table) add_placeholder_type(name string) int { ph_type := Type{ + parent: 0 kind: .placeholder name: name } - idx := t.register_type(ph_type) - println('added placeholder: $name - $idx') - return idx + // println('added placeholder: $name - $ph_type.idx') + return t.register_type(ph_type) } -// [inline] -// pub fn (t &Table) update_typ(ti &types.Type) types.Type { -// if typ.kind == .unresolved { -// } -// } -pub fn (t &Table) check(got, expected &Type) bool { - println('check: $got.name, $expected.name') - if expected.kind == .voidptr { +pub fn (t &Table) check(got, expected &TypeRef) bool { + println('check: $got.typ.name, $expected.typ.name') + if expected.typ.kind == .voidptr { return true } // if expected.name == 'array' { // return true // } - if got.idx != expected.idx && got.name != expected.name { + if got.idx != expected.idx && got.typ.name != expected.typ.name { return false } return true