From 9e9bdc32eac11f2e81155a43e32bc083c84cc36d Mon Sep 17 00:00:00 2001 From: joe-conigliaro Date: Sat, 8 Feb 2020 19:50:12 +1100 Subject: [PATCH] v2: lots of small fixes parent method/field resolution --- vlib/v/ast/ast.v | 13 ++++++----- vlib/v/checker/checker.v | 47 +++++++++++++++++++++++++------------- vlib/v/gen/cgen.v | 8 +++++-- vlib/v/parser/fn.v | 35 ++++++++++++++++++++++++---- vlib/v/parser/parse_type.v | 14 ------------ vlib/v/parser/parser.v | 35 ++++++++++++++++------------ vlib/v/table/atypes.v | 23 +++++++++---------- vlib/v/table/table.v | 36 ++++++++++++++--------------- 8 files changed, 123 insertions(+), 88 deletions(-) diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 76883b0d1f..65db7d0583 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -111,12 +111,13 @@ pub: pub struct FnDecl { pub: - name string - stmts []Stmt - typ table.TypeRef - args []Arg - is_pub bool - receiver Field + name string + stmts []Stmt + typ table.TypeRef + args []Arg + is_pub bool + is_variadic bool + receiver Field } pub struct BranchStmt { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index a06ec0cc7c..6b250d2778 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -28,7 +28,7 @@ pub fn (c mut Checker) check(ast_file ast.File) { // if ast_file.unresolved.len != c.resolved.len { // c.resolve_exprs(file) // } - c.complete_types(ast_file) + c.complete_types() for stmt in ast_file.stmts { c.stmt(stmt) } @@ -39,7 +39,7 @@ pub fn (c mut Checker) check_files(ast_files []ast.File) { // files this muse be done first. TODO: optimize for file in ast_files { c.file_name = file.path - c.resolve_expr_types(file) + c.resolve_expr_types(file.unresolved) } for file in ast_files { c.check(file) @@ -47,14 +47,14 @@ pub fn (c mut Checker) check_files(ast_files []ast.File) { } // resolve type of unresolved expressions -fn (c mut Checker) resolve_expr_types(f ast.File) { - for x in f.unresolved { +fn (c mut Checker) resolve_expr_types(exprs []ast.Expr) { + for x in exprs { c.resolved << c.expr(x) } } // update any types chich contain unresolved sub types -fn (c &Checker) complete_types(f ast.File) { +fn (c &Checker) complete_types() { for idx, t in c.table.types { // println('Resolve type: $t.name') if t.kind == .array { @@ -160,6 +160,16 @@ pub fn (c &Checker) call_expr(call_expr ast.CallExpr) table.TypeRef { c.error('too many arguments in call to `$fn_name` ($call_expr.args.len instead of $f.args.len)', call_expr.pos) } } + // for debugging + if f.name == 'backtrace_symbols_fd' { + println('ARGS FOR: backtrace_symbols_fd:') + for i, arg_expr in call_expr.args { + typ := c.expr(arg_expr) + println(' -- $i - $typ.typ.name') + } + } + // TODO: variadic + if fn_name != 'printf' && f.args.len > 0 { for i, arg in f.args { arg_expr := call_expr.args[i] typ := c.expr(arg_expr) @@ -167,6 +177,7 @@ pub fn (c &Checker) call_expr(call_expr ast.CallExpr) table.TypeRef { 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 } c.error('unknown fn: $fn_name', call_expr.pos) @@ -178,11 +189,9 @@ pub fn (c &Checker) check_method_call_expr(method_call_expr ast.MethodCallExpr) if method := typ.typ.find_method(method_call_expr.name) { return method.return_type } - if typ.typ.kind == .array { - a := c.table.find_type('array') or { - exit(1) - } - if method := a.find_method(method_call_expr.name) { + // check parent + if !isnil(typ.typ.parent) { + if method := typ.typ.parent.find_method(method_call_expr.name) { return method.return_type } } @@ -201,13 +210,17 @@ pub fn (c &Checker) selector_expr(selector_expr ast.SelectorExpr) table.TypeRef } return field.typ } - .array { - if field_name == 'len' { - return c.table.type_ref(table.int_type_idx) - } - } - .string {} else { + // types with parent struct (array/maps) handled here + if !isnil(typ.typ.parent) && typ.typ.parent.kind == .struct_ { + parent := typ.typ.parent + if field := c.table.struct_find_field(parent, field_name) { + if field.typ.typ.kind == .unresolved { + return c.resolved[field.typ.idx] + } + return field.typ + } + } c.error('`$typ.typ.name` is not a struct', selector_expr.pos) } } @@ -439,6 +452,8 @@ pub fn (c &Checker) error(s string, pos token.Position) { path = path.replace(workdir, '') } final_msg_line := '$path:$pos.line_nr: checker error: $s' + // sometimes eprintln wasnt working? + println(final_msg_line) eprintln(final_msg_line) /* if colored_output { diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 925959652e..91b023f8df 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -72,8 +72,12 @@ fn (g mut Gen) stmt(node ast.Stmt) { g.definitions.write('$it.typ.typ.name ${it.name}(') } for i, arg in it.args { - g.write(arg.typ.typ.name + ' ' + arg.name) - g.definitions.write(arg.typ.typ.name + ' ' + arg.name) + mut arg_type := arg.typ.typ.name + if i == it.args.len-1 && it.is_variadic { + arg_type = 'variadic_$arg.typ.typ.name' + } + g.write(arg_type + ' ' + arg.name) + g.definitions.write(arg_type + ' ' + arg.name) if i < it.args.len - 1 { g.write(', ') g.definitions.write(', ') diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 7c457da608..528b9345e9 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -18,7 +18,6 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,table.TypeRef) { name: fn_name args: args // tok: tok - pos: tok.position() } if p.tok.kind == .key_orelse { @@ -93,6 +92,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl { } // println('fn decl $name') p.check(.lpar) + mut is_variadic := false // Args mut args := []table.Var mut ast_args := []ast.Arg @@ -102,12 +102,32 @@ fn (p mut Parser) fn_decl() ast.FnDecl { p.peek_tok.kind == .rpar if types_only { p.warn('types only') + mut arg_no := 1 for p.tok.kind != .rpar { - p.parse_type() + arg_name := 'arg_$arg_no' + if p.tok.kind == .ellipsis { + p.check(.ellipsis) + is_variadic = true + } + arg_type := p.parse_type() if p.tok.kind == .comma { + if is_variadic { + p.error('cannot use ...(variadic) with non-final parameter no $arg_no') + } p.next() } + arg := table.Var{ + name: arg_name + typ: arg_type + } + args << arg + //p.table.register_var(arg) + ast_args << ast.Arg{ + name: arg_name + typ: arg_type + } } + arg_no++ } else { for p.tok.kind != .rpar { @@ -120,6 +140,10 @@ fn (p mut Parser) fn_decl() ast.FnDecl { if p.tok.kind == .key_mut { p.check(.key_mut) } + if p.tok.kind == .ellipsis { + p.check(.ellipsis) + is_variadic = true + } typ := p.parse_type() for arg_name in arg_names { arg := table.Var{ @@ -129,10 +153,11 @@ fn (p mut Parser) fn_decl() ast.FnDecl { args << arg p.table.register_var(arg) ast_args << ast.Arg{ - typ: typ name: arg_name + typ: typ } - if typ.typ.kind == .variadic && p.tok.kind == .comma { + //if typ.typ.kind == .variadic && p.tok.kind == .comma { + if is_variadic && p.tok.kind == .comma { p.error('cannot use ...(variadic) with non-final parameter $arg_name') } } @@ -167,6 +192,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl { name: name args: args return_type: typ + is_variadic: is_variadic is_c: is_c }) } @@ -180,6 +206,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl { typ: typ args: ast_args is_pub: is_pub + is_variadic: is_variadic receiver: ast.Field{ name: rec_name typ: rec_type diff --git a/vlib/v/parser/parse_type.v b/vlib/v/parser/parse_type.v index 8d4fa4d4e5..22b591ed86 100644 --- a/vlib/v/parser/parse_type.v +++ b/vlib/v/parser/parse_type.v @@ -62,13 +62,6 @@ pub fn (p mut Parser) parse_multi_return_ti() table.TypeRef { return p.table.type_ref(idx) } -pub fn (p mut Parser) parse_variadic_ti() table.TypeRef { - p.check(.ellipsis) - 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.TypeRef { // p.check(.key_fn) p.fn_decl() @@ -105,13 +98,6 @@ pub fn (p mut Parser) parse_type() table.TypeRef { } return p.parse_multi_return_ti() } - // variadic - .ellipsis { - if nr_muls > 0 { - p.error('parse_ti: unexpected `&` before variadic') - } - return p.parse_variadic_ti() - } else { defer { p.next() diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 409b2eb08e..4d399baccb 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -71,12 +71,13 @@ pub fn parse_file(path string, table &table.Table) ast.File { table: table file_name: path pref: &pref.Preferences{} - builtin_mod: true } p.read_first_token() // module decl module_decl := if p.tok.kind == .key_module { p.module_decl() } else { ast.Module{name: 'main' } } + p.mod = module_decl.name + p.builtin_mod = p.mod == 'builtin' // imports mut imports := []ast.Import for p.tok.kind == .key_import { @@ -471,7 +472,7 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.TypeRef) { if p.peek_tok.kind == .lpar { name := p.tok.lit // type cast. TODO: finish - if name in p.table.type_idxs { + if name in table.builtin_type_names { // ['byte', 'string', 'int'] // SKIP FOR NOW mut par_d := 0 @@ -1054,26 +1055,30 @@ fn (p mut Parser) struct_decl() ast.StructDecl { } fields << table.Field{ name: field_name - // type_idx: ti.idx - 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{ - fields: fields - } - }) - if ret == -1 { - p.error('cannot register type `$name`, another type with this name exists') + t := table.Type{ + parent: 0 + kind: .struct_ + name: name + info: table.Struct{ + fields: fields } } + mut ret := 0 + if p.builtin_mod && t.name in table.builtin_type_names { + // this allows overiding the builtins type + // with the real struct type info parsed from builtin + ret = p.table.register_builtin_type(t) + } else { + ret = p.table.register_type(t) + } + if ret == -1 { + p.error('cannot register type `$name`, another type with this name exists') + } return ast.StructDecl{ name: name is_pub: is_pub diff --git a/vlib/v/table/atypes.v b/vlib/v/table/atypes.v index 9664fae3f9..b32fb00a61 100644 --- a/vlib/v/table/atypes.v +++ b/vlib/v/table/atypes.v @@ -3,7 +3,7 @@ // that can be found in the LICENSE file. module table -pub type TypeInfo = Array | ArrayFixed | Map | Struct | MultiReturn | Variadic +pub type TypeInfo = Array | ArrayFixed | Map | Struct | MultiReturn pub struct Type { pub: @@ -47,6 +47,13 @@ pub const ( // map_type_idx = 18 ) +pub const ( + builtin_type_names = [ + 'void', 'voidptr', 'charptr', 'byteptr', 'i8', 'i16', 'int', 'i64', 'u16', 'u32', 'u64', + 'f32' ,'f64', 'string', 'char', 'byte' ,'bool', 'struct', 'array', 'array_fixed', 'map' + ] +) + pub enum Kind { placeholder void @@ -66,14 +73,13 @@ pub enum Kind { char byte bool - const_ - enum_ + //const_ + //enum_ struct_ array array_fixed map multi_return - variadic unresolved } @@ -371,9 +377,6 @@ pub fn (k Kind) str() string { .multi_return{ 'multi_return' } - .variadic{ - 'variadic' - } else { 'unknown'} } @@ -407,6 +410,7 @@ pub mut: pub struct Field { pub: name string +mut: typ TypeRef // type_idx int } @@ -447,11 +451,6 @@ mut: types []TypeRef } -pub struct Variadic { -pub: - typ TypeRef -} - [inline] pub fn (t &Table) get_type(idx int) &Type { if idx == 0 { diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index 398e24287b..dced4c754c 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -27,6 +27,7 @@ pub: name string args []Var return_type TypeRef + is_variadic bool is_c bool } @@ -279,6 +280,19 @@ pub fn (t &Table) find_type(name string) ?Type { return none } +// this will override or register builtin type +// allows prexisitng types added in register_builtins +// to be overriden with their real type info +[inline] +pub fn (t mut Table) register_builtin_type(typ Type) int { + existing_idx := t.type_idxs[typ.name] + if existing_idx > 0 { + t.types[existing_idx] = typ + return existing_idx + } + return t.register_type(typ) +} + [inline] pub fn (t mut Table) register_type(typ Type) int { existing_idx := t.type_idxs[typ.name] @@ -399,25 +413,6 @@ pub fn (t mut Table) find_or_register_multi_return(mr_typs []TypeRef) int { return t.register_type(mr_type) } -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 - } - // register - variadic_type := Type{ - parent: 0 - kind: .variadic - name: name - info: Variadic{ - typ: variadic_typ - } - } - return t.register_type(variadic_type) -} - pub fn (t mut Table) add_placeholder_type(name string) int { ph_type := Type{ parent: 0 @@ -433,6 +428,9 @@ pub fn (t &Table) check(got, expected &TypeRef) bool { if expected.typ.kind == .voidptr { return true } + if expected.typ.kind in [.voidptr, .byteptr, .charptr] && got.typ.kind == .int { + return true + } if expected.typ.kind == .byteptr && got.typ.kind == .voidptr { return true }