From fcd97f513a374f896ed3c0a8f9f040ad7c1afe7d Mon Sep 17 00:00:00 2001 From: joe-conigliaro Date: Thu, 20 Feb 2020 21:13:18 +1100 Subject: [PATCH] v2: module/type/fn name fixes, compile fixes --- vlib/compiler/main.v | 7 ++-- vlib/v/ast/ast.v | 2 +- vlib/v/ast/scope.v | 15 +++++--- vlib/v/checker/checker.v | 69 +++++++++++++++++++++---------------- vlib/v/parser/fn.v | 4 --- vlib/v/parser/module.v | 13 +++++++ vlib/v/parser/parse_type.v | 5 +-- vlib/v/parser/parser.v | 14 +++----- vlib/v/parser/parser_test.v | 14 ++++---- vlib/v/table/table.v | 13 ------- 10 files changed, 83 insertions(+), 73 deletions(-) diff --git a/vlib/compiler/main.v b/vlib/compiler/main.v index 2bfb217857..c947bb69c3 100644 --- a/vlib/compiler/main.v +++ b/vlib/compiler/main.v @@ -327,11 +327,12 @@ pub fn (v mut V) compile2() { println(v.files) } // v1 compiler files - v.add_v_files_to_compile() + //v.add_v_files_to_compile() //v.files << v.dir // v2 compiler - //v.files << v.get_builtin_files() - //v.files << v.get_user_files() + v.files << v.get_builtin_files() + v.files << v.get_user_files() + v.set_module_lookup_paths() if v.pref.is_verbose { println('all .v files:') println(v.files) diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 4c8769560d..38de987113 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -212,7 +212,7 @@ pub: mod Module imports []Import stmts []Stmt - scope Scope + scope &Scope } pub struct IdentFunc { diff --git a/vlib/v/ast/scope.v b/vlib/v/ast/scope.v index 3735af72e8..5be3cd1af8 100644 --- a/vlib/v/ast/scope.v +++ b/vlib/v/ast/scope.v @@ -105,16 +105,23 @@ fn (s &Scope) contains(pos int) bool { return pos > s.start_pos && pos < s.end_pos } -pub fn (sc &Scope) print_vars(level int) { +pub fn (sc &Scope) show(level int) string { + mut out := '' mut indent := '' for _ in 0 .. level * 4 { indent += ' ' } - println('$indent# $sc.start_pos - $sc.end_pos') + out += '$indent# $sc.start_pos - $sc.end_pos\n' for _, var in sc.vars { - println('$indent * $var.name - $var.typ') + out += '$indent * $var.name - $var.typ\n' } for child in sc.children { - child.print_vars(level + 1) + out += child.show(level + 1) } + return out } + +pub fn (sc &Scope) str() string { + return sc.show(0) +} + diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 2fb693f3df..e9bdbd86f2 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -18,21 +18,18 @@ const ( pub struct Checker { table &table.Table mut: - file_name string - scope &ast.Scope + file ast.File nr_errors int } pub fn new_checker(table &table.Table) Checker { return Checker{ table: table - scope: 0 } } pub fn (c mut Checker) check(ast_file ast.File) { - c.file_name = ast_file.path - c.scope = &ast_file.scope + c.file = ast_file for stmt in ast_file.stmts { c.stmt(stmt) } @@ -124,30 +121,44 @@ fn (c mut Checker) check_assign_expr(assign_expr ast.AssignExpr) { pub fn (c mut Checker) call_expr(call_expr ast.CallExpr) table.Type { fn_name := call_expr.name - if f := c.table.find_fn(fn_name) { - // return_ti := f.return_ti - if f.is_c || call_expr.is_c { - return f.return_type - } - if call_expr.args.len < f.args.len { - c.error('too few arguments in call to `$fn_name`', call_expr.pos) - } - else if !f.is_variadic && call_expr.args.len > f.args.len { - c.error('too many arguments in call to `$fn_name` ($call_expr.args.len instead of $f.args.len)', call_expr.pos) - } - for i, arg_expr in call_expr.args { - arg := if f.is_variadic && i >= f.args.len - 1 { f.args[f.args.len - 1] } else { f.args[i] } - typ := c.expr(arg_expr) - typ_sym := c.table.get_type_symbol(typ) - arg_typ_sym := c.table.get_type_symbol(arg.typ) - if !c.table.check(typ, arg.typ) { - c.error('!cannot use type `$typ_sym.name` as type `$arg_typ_sym.name` in argument ${i+1} to `$fn_name`', call_expr.pos) - } + + mut found := false + // look for function in format `mod.fn` or `fn` (main/builtin) + mut f := table.Fn{} + if f1 := c.table.find_fn(fn_name) { + found = true + f = f1 + } + // try prefix with current module as it would have never gotten prefixed + if !found && !fn_name.contains('.') { + if f1 := c.table.find_fn('${c.file.mod.name}.$fn_name') { + found = true + f = f1 } + } + if !found { + c.error('unknown fn: $fn_name', call_expr.pos) + } + + if f.is_c || call_expr.is_c { return f.return_type } - c.error('unknown fn: $fn_name', call_expr.pos) - exit(1) + if call_expr.args.len < f.args.len { + c.error('too few arguments in call to `$fn_name`', call_expr.pos) + } + else if !f.is_variadic && call_expr.args.len > f.args.len { + c.error('too many arguments in call to `$fn_name` ($call_expr.args.len instead of $f.args.len)', call_expr.pos) + } + for i, arg_expr in call_expr.args { + arg := if f.is_variadic && i >= f.args.len - 1 { f.args[f.args.len - 1] } else { f.args[i] } + typ := c.expr(arg_expr) + typ_sym := c.table.get_type_symbol(typ) + arg_typ_sym := c.table.get_type_symbol(arg.typ) + if !c.table.check(typ, arg.typ) { + c.error('!cannot use type `$typ_sym.name` as type `$arg_typ_sym.name` in argument ${i+1} to `$fn_name`', call_expr.pos) + } + } + return f.return_type } pub fn (c mut Checker) check_method_call_expr(method_call_expr ast.MethodCallExpr) table.Type { @@ -399,8 +410,8 @@ pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type { if info.typ != 0 { return info.typ } - start_scope := c.scope.innermost(ident.pos.pos) or { - c.scope + start_scope := c.file.scope.innermost(ident.pos.pos) or { + c.file.scope } mut found := true mut var_scope := &ast.Scope(0) @@ -597,7 +608,7 @@ pub fn (c mut Checker) index_expr(node ast.IndexExpr) table.Type { pub fn (c mut Checker) error(s string, pos token.Position) { c.nr_errors++ print_backtrace() - mut path := c.file_name + mut path := c.file.path // Get relative path workdir := os.getwd() + filepath.separator if path.starts_with(workdir) { diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 3e98aae5a2..5f2a6207d2 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -18,7 +18,6 @@ pub fn (p mut Parser) call_expr(is_c bool, mod string) ast.CallExpr { name: fn_name args: args // tok: tok - pos: tok.position() is_c: is_c } @@ -26,9 +25,6 @@ pub fn (p mut Parser) call_expr(is_c bool, mod string) ast.CallExpr { p.next() p.parse_block() } - if f := p.table.find_fn(fn_name) { - return node - } return node } diff --git a/vlib/v/parser/module.v b/vlib/v/parser/module.v index 27640a846f..b33e644d4d 100644 --- a/vlib/v/parser/module.v +++ b/vlib/v/parser/module.v @@ -2,3 +2,16 @@ // Use of this source code is governed by an MIT license // that can be found in the LICENSE file. module parser + +// return true if file being parsed imports `mod` +pub fn (p &Parser) known_import(mod string) bool { + return mod in p.imports +} + +fn (p &Parser) prepend_mod(name string) string { + if p.builtin_mod || p.mod == 'main' { + return name + } + return '${p.mod}.$name' +} + diff --git a/vlib/v/parser/parse_type.v b/vlib/v/parser/parse_type.v index c30199154a..c9a6252d0a 100644 --- a/vlib/v/parser/parse_type.v +++ b/vlib/v/parser/parse_type.v @@ -101,13 +101,14 @@ pub fn (p mut Parser) parse_type() table.Type { // `module.Type` if p.peek_tok.kind == .dot { // /if !(p.tok.lit in p.table.imports) { - if !p.table.known_import(p.tok.lit) { + if !p.known_import(name) { println(p.table.imports) p.error('unknown module `$p.tok.lit`') } p.next() p.check(.dot) - name += '.' + p.tok.lit + // prefix with full module + name = '${p.imports[name]}.$p.tok.lit' } // `Foo` in module `mod` means `mod.Foo` else if !(p.mod in ['builtin', 'main']) && !(name in table.builtin_type_names) { diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index fe020b4b58..160f75144c 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -109,7 +109,7 @@ pub fn parse_file(path string, table &table.Table) ast.File { mod: module_decl imports: imports stmts: stmts - scope: *p.scope + scope: p.scope } } @@ -520,9 +520,10 @@ pub fn (p mut Parser) name_expr() ast.Expr { mut node := ast.Expr{} is_c := p.tok.lit == 'C' mut mod := '' - if p.peek_tok.kind == .dot && (is_c || p.tok.lit in p.imports) { + if p.peek_tok.kind == .dot && (is_c || p.known_import(p.tok.lit)) { if !is_c { - mod = p.tok.lit + // prepend the full import + mod = p.imports[p.tok.lit] } p.next() p.check(.dot) @@ -1655,13 +1656,6 @@ fn (p mut Parser) type_decl() ast.TypeDecl { } } -fn (p &Parser) prepend_mod(name string) string { - if p.builtin_mod || p.mod == 'main' { - return name - } - return '${p.mod}.${name}' -} - fn verror(s string) { println(s) exit(1) diff --git a/vlib/v/parser/parser_test.v b/vlib/v/parser/parser_test.v index a4b0f6b47e..eb3d15bb4d 100644 --- a/vlib/v/parser/parser_test.v +++ b/vlib/v/parser/parser_test.v @@ -34,14 +34,14 @@ fn test_eval() { ] /* table := table.new_table() - mut scope := ast.Scope{start_pos: 0, parent: 0} + mut scope := &ast.Scope{start_pos: 0, parent: 0} mut stmts := []ast.Stmt for input in inputs { - stmts << parse_stmt(input, table, &scope) + stmts << parse_stmt(input, table, scope) } file := ast.File{ stmts: stmts - scope: &scope + scope: scope } mut checker := checker.new_checker(table) checker.check(file) @@ -87,10 +87,10 @@ fn test_one() { ] expected := 'int a = 10;int b = -a;int c = 20;' table := table.new_table() - mut scope := ast.Scope{start_pos: 0, parent: 0} + mut scope := &ast.Scope{start_pos: 0, parent: 0} mut e := []ast.Stmt for line in input { - e << parse_stmt(line, table, &scope) + e << parse_stmt(line, table, scope) } program := ast.File{ stmts: e @@ -179,10 +179,10 @@ fn test_parse_expr() { mut e := []ast.Stmt table := table.new_table() mut checker := checker.new_checker(table) - mut scope := ast.Scope{start_pos: 0, parent: 0} + mut scope := &ast.Scope{start_pos: 0, parent: 0} for s in input { println('\n\nst="$s"') - e << parse_stmt(s, table, &scope) + e << parse_stmt(s, table, scope) } program := ast.File{ stmts: e diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index 580500b649..8d5d35d046 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -3,11 +3,6 @@ // that can be found in the LICENSE file. module table -import ( - v.token - // v.ast -) - pub struct Table { // struct_fields map[string][]string pub mut: @@ -400,11 +395,3 @@ pub fn (t &Table) check(got, expected Type) bool { return true } -pub fn (t &Table) known_import(name string) bool { - for i in t.imports { - if i.all_after('.') == name { - return true - } - } - return false -}