diff --git a/cmd/tools/vfmt.v b/cmd/tools/vfmt.v index 290ae5e455..a0b768a22a 100644 --- a/cmd/tools/vfmt.v +++ b/cmd/tools/vfmt.v @@ -6,6 +6,7 @@ module main import ( os os.cmdline + v.ast v.pref v.fmt v.util @@ -160,7 +161,7 @@ fn (foptions &FormatOptions) format_file(file string) { eprintln('vfmt2 running fmt.fmt over file: $file') } table := table.new_table() - file_ast := parser.parse_file(file, table, .parse_comments, prefs) + file_ast := parser.parse_file(file, table, .parse_comments, prefs, &ast.Scope{parent: 0}) formatted_content := fmt.fmt(file_ast, table) file_name := os.file_name(file) vfmt_output_path := os.join_path(os.temp_dir(), 'vfmt_' + file_name) diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 06bb4d26af..ddec29ff68 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -20,6 +20,9 @@ pub type Stmt = GlobalDecl | FnDecl | Return | Module | Import | ExprStmt | ForStmt | StructDecl | ForCStmt | ForInStmt | CompIf | ConstDecl | Attr | BranchStmt | HashStmt | AssignStmt | EnumDecl | TypeDecl | DeferStmt | GotoLabel | GotoStmt | LineComment | MultiLineComment | AssertStmt | UnsafeStmt | GoStmt | Block | InterfaceDecl + +pub type ScopeObject = ConstField | GlobalDecl | Var + // pub type Type = StructType | ArrayType // pub struct StructType { // fields []Field @@ -110,12 +113,21 @@ mut: // typ2 Type } +pub struct ConstField { +pub: + name string + expr Expr + is_pub bool + pos token.Position +mut: + typ table.Type +} + pub struct ConstDecl { pub: - pos token.Position - fields []Field - exprs []Expr + fields []ConstField is_pub bool + pos token.Position } pub struct StructDecl { @@ -184,6 +196,7 @@ pub: pos token.Position left Expr // `user` in `user.register()` is_method bool + mod string mut: name string args []CallArg @@ -253,6 +266,8 @@ pub: imports []Import stmts []Stmt scope &Scope + // TODO: consider parent instead of field + global_scope &Scope } pub struct IdentFn { @@ -275,6 +290,7 @@ pub enum IdentKind { blank_ident variable constant + global function } @@ -284,6 +300,7 @@ pub: value string is_c bool tok_kind token.Kind + mod string pos token.Position mut: name string diff --git a/vlib/v/ast/scope.v b/vlib/v/ast/scope.v index c846debc37..e96be16928 100644 --- a/vlib/v/ast/scope.v +++ b/vlib/v/ast/scope.v @@ -11,7 +11,7 @@ mut: children []&Scope start_pos int end_pos int - vars map[string]Var + objects map[string]ScopeObject } pub fn new_scope(parent &Scope, start_pos int) &Scope { @@ -21,25 +21,47 @@ pub fn new_scope(parent &Scope, start_pos int) &Scope { } } -pub fn (s &Scope) find_scope_and_var(name string) ?(&Scope,Var) { - if name in s.vars { - return s,s.vars[name] +pub fn (s &Scope) find_with_scope(name string) ?(ScopeObject,&Scope) { + mut sc := s + for { + if name in sc.objects { + return sc.objects[name],sc + } + if isnil(sc.parent) { + break + } + sc = sc.parent } - for sc := s; !isnil(sc.parent); sc = sc.parent { - if name in sc.vars { - return sc,sc.vars[name] + return none +} + +pub fn (s &Scope) find(name string) ?ScopeObject { + for sc := s; ; sc = sc.parent { + if name in sc.objects { + return sc.objects[name] + } + if isnil(sc.parent) { + break } } return none } -pub fn (s &Scope) find_var(name string) ?Var { - if name in s.vars { - return s.vars[name] +pub fn (s &Scope) is_known(name string) bool { + if _ := s.find(name) { + return true } - for sc := s; !isnil(sc.parent); sc = sc.parent { - if name in sc.vars { - return sc.vars[name] + return false +} + + +pub fn (s &Scope) find_var(name string) ?Var { + if obj := s.find(name) { + match obj { + Var { + return *it + } + else {} } } return none @@ -52,28 +74,24 @@ pub fn (s &Scope) known_var(name string) bool { return false } -pub fn (s mut Scope) register_var(var Var) { - if x := s.find_var(var.name) { - // println('existing var: $var.name') - return - } - s.vars[var.name] = var -} - -pub fn (s mut Scope) override_var(var Var) { - s.vars[var.name] = var -} - pub fn (s mut Scope) update_var_type(name string, typ table.Type) { - mut x := s.vars[name] - // dont do an insert for no reason - if x.typ == typ { + match mut s.objects[name] { + Var { + if it.typ == typ { + return + } + it.typ = typ + } + else {} + } +} + +pub fn (s mut Scope) register(name string, obj ScopeObject) { + if x := s.find(name) { + // println('existing obect: $name') return } - x.typ = typ - s.vars[name] = x - // TODO - // s.vars[name].typ = typ + s.objects[name] = obj } pub fn (s &Scope) outermost() &Scope { @@ -115,42 +133,37 @@ pub fn (s &Scope) innermost(pos int) &Scope { return s } -/* -pub fn (s &Scope) innermost(pos int) ?&Scope { - if s.contains(pos) { - for s1 in s.children { - if s1.contains(pos) { - return s1.innermost(pos) - } - } - return s - } - return none -} -*/ - - [inline] fn (s &Scope) contains(pos int) bool { return pos >= s.start_pos && pos <= s.end_pos } -pub fn (sc &Scope) show(level int) string { +pub fn (sc &Scope) show(depth int, max_depth int) string { mut out := '' mut indent := '' - for _ in 0 .. level * 4 { + for _ in 0 .. depth * 4 { indent += ' ' } out += '$indent# $sc.start_pos - $sc.end_pos\n' - for _, var in sc.vars { - out += '$indent * $var.name - $var.typ\n' + for _, obj in sc.objects { + match obj { + ConstField { + out += '$indent * const: $it.name - $it.typ\n' + } + Var { + out += '$indent * var: $it.name - $it.typ\n' + } + else {} + } } - for child in sc.children { - out += child.show(level + 1) + if max_depth == 0 || depth < max_depth-1 { + for i, _ in sc.children { + out += sc.children[i].show(depth + 1, max_depth) + } } return out } pub fn (sc &Scope) str() string { - return sc.show(0) + return sc.show(0, 0) } diff --git a/vlib/v/builder/builder.v b/vlib/v/builder/builder.v index d69ca8f8dc..6a5c44c75d 100644 --- a/vlib/v/builder/builder.v +++ b/vlib/v/builder/builder.v @@ -25,6 +25,7 @@ pub: mut: module_search_paths []string parsed_files []ast.File + global_scope &ast.Scope } pub fn new_builder(pref &pref.Preferences) Builder { @@ -34,12 +35,15 @@ pub fn new_builder(pref &pref.Preferences) Builder { pref: pref table: table checker: checker.new_checker(table, pref) + global_scope: &ast.Scope{ + parent: 0 + } } } pub fn (b mut Builder) gen_c(v_files []string) string { t0 := time.ticks() - b.parsed_files = parser.parse_files(v_files, b.table, b.pref) + b.parsed_files = parser.parse_files(v_files, b.table, b.pref, b.global_scope) b.parse_imports() t1 := time.ticks() parse_time := t1 - t0 @@ -74,7 +78,7 @@ pub fn (b mut Builder) build_c(v_files []string, out_file string) { pub fn (b mut Builder) build_x64(v_files []string, out_file string) { t0 := time.ticks() - b.parsed_files = parser.parse_files(v_files, b.table, b.pref) + b.parsed_files = parser.parse_files(v_files, b.table, b.pref, b.global_scope) b.parse_imports() t1 := time.ticks() parse_time := t1 - t0 @@ -112,7 +116,7 @@ pub fn (b mut Builder) parse_imports() { panic('cannot import module "$mod" (no .v files in "$import_path")') } // Add all imports referenced by these libs - parsed_files := parser.parse_files(v_files, b.table, b.pref) + parsed_files := parser.parse_files(v_files, b.table, b.pref, b.global_scope) for file in parsed_files { if file.mod.name != mod { // v.parsers[pidx].error_with_token_index('bad module definition: ${v.parsers[pidx].file_path} imports module "$mod" but $file is defined as module `$p_mod`', 1 diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index c812473e9d..88aa94fca7 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -5,6 +5,7 @@ module checker import ( v.ast + v.depgraph v.table v.token v.pref @@ -25,8 +26,9 @@ mut: error_lines []int // to avoid printing multiple errors for the same line expected_type table.Type fn_return_type table.Type // current function's return type + const_deps []string // fn_decl ast.FnDecl - pref &pref.Preferences // Preferences shared from V struct + pref &pref.Preferences // Preferences shared from V struct } pub fn new_checker(table &table.Table, pref &pref.Preferences) Checker { @@ -41,13 +43,6 @@ pub fn (c mut Checker) check(ast_file ast.File) { for stmt in ast_file.stmts { c.stmt(stmt) } - /* - println('all types:') - for t in c.table.types { - println(t.name + ' - ' + t.kind.str()) - } - */ - } pub fn (c mut Checker) check2(ast_file ast.File) []string { @@ -59,18 +54,6 @@ pub fn (c mut Checker) check2(ast_file ast.File) []string { } pub fn (c mut Checker) check_files(ast_files []ast.File) { - // TODO: temp fix, impl proper solution - for file in ast_files { - c.file = file - for stmt in file.stmts { - match mut stmt { - ast.ConstDecl { - c.stmt(*it) - } - else {} - } - } - } for file in ast_files { c.check(file) } @@ -294,8 +277,8 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type { mut f := table.Fn{} mut found := false // try prefix with current module as it would have never gotten prefixed - if !fn_name.contains('.') && !(c.file.mod.name in ['builtin', 'main']) { - name_prefixed := '${c.file.mod.name}.$fn_name' + if !fn_name.contains('.') && !(call_expr.mod in ['builtin', 'main']) { + name_prefixed := '${call_expr.mod}.$fn_name' if f1 := c.table.find_fn(name_prefixed) { call_expr.name = name_prefixed found = true @@ -435,7 +418,7 @@ pub fn (c mut Checker) return_stmt(return_stmt mut ast.Return) { return } 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) + // c.error('wrong number of return arguments:\n\texpected: $expected_table.str()\n\tgot: $got_types.str()', return_stmt.pos) c.error('wrong number of return arguments', return_stmt.pos) } for i, exp_typ in expected_types { @@ -589,66 +572,45 @@ fn (c mut Checker) stmt(node ast.Stmt) { c.stmts(it.stmts) } ast.ConstDecl { - mut unresolved_num:= 0 // number of type-unresolved consts - mut ordered_exprs := []ast.Expr - mut ordered_fields := []ast.Field - for i, expr in it.exprs { - mut field := it.fields[i] - typ := c.expr(expr) - if typ == table.void_type { - unresolved_num++ + mut field_names := []string + mut field_order := []int + for i, field in it.fields { + field_names << field.name + field_order << i + } + mut needs_order := false + mut done_fields := []int + for i, field in it.fields { + mut set_const := false + if c.const_deps.len == 0 { + set_const = true } - else { // succeed in resolving type - c.table.register_const(table.Var{ - name: field.name - typ: typ - }) - field.typ = typ - it.fields[i] = field - ordered_exprs << expr - ordered_fields << field - if unresolved_num == 0 { - continue - } - for j, _expr in it.exprs[0..i]{ - mut _field := it.fields[j] - _typ := c.expr(_expr) - if _field.typ == 0 && _typ != table.void_type { - // succeed in resolving type - c.table.register_const(table.Var{ - name: _field.name - typ: _typ - }) - unresolved_num-- - _field.typ = _typ - it.fields[j] = _field - ordered_exprs << _expr - ordered_fields << _field + c.const_deps << field.name + typ := c.expr(field.expr) + it.fields[i].typ = typ + if set_const { + for cd in c.const_deps { + for j, f in it.fields { + if j != i && cd in field_names && cd == f.name && !(j in done_fields) { + needs_order = true + x := field_order[j] + field_order[j] = field_order[i] + field_order[i] = x + break + } } } + done_fields << i + c.const_deps = [] } } - if unresolved_num != 0 { - for i, expr in it.exprs { - typ := c.expr(expr) - if typ == table.void_type { - mut _field := it.fields[i] - if !_field.already_reported { - _field.already_reported = true - it.fields[i] = _field - c.error("$unresolved_num ill-defined const `$_field.name`", _field.pos) - } - } + if needs_order { + mut ordered_fields := []ast.ConstField + for order in field_order { + ordered_fields << it.fields[order] } + it.fields = ordered_fields } - for i, field in ordered_fields { // set the fields and exprs as ordered - it.fields[i] = field - it.exprs[i] = ordered_exprs[i] - } - /* - it.exprs = ordered_exprs - it.fields = ordered_fields - */ } ast.ExprStmt { c.expr(it.expr) @@ -876,34 +838,42 @@ pub fn (c mut Checker) expr(node ast.Expr) table.Type { } pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type { - // println('IDENT: $ident.name - $ident.pos.pos') + // TODO: move this + if c.const_deps.len > 0 { + mut name := ident.name + if !name.contains('.') && !(ident.mod in ['builtin', 'main']) { + name = '${ident.mod}.$ident.name' + } + if name in c.const_deps { + c.error('cycle in constants', ident.pos) + return table.void_type + } + c.const_deps << name + } + if ident.kind == .blank_ident { + return table.void_type + } + // second use if ident.kind == .variable { - // println('===========================') - // c.scope.print_vars(0) - // println('===========================') info := ident.info as ast.IdentVar - if info.typ != 0 { - return info.typ - } + return info.typ + } + else if ident.kind == .constant { + info := ident.info as ast.IdentVar + return info.typ + } + else if ident.kind == .function { + info := ident.info as ast.IdentFn + return info.typ + } + // first use + else if ident.kind == .unresolved { start_scope := c.file.scope.innermost(ident.pos.pos) - mut found := true - mut var_scope,var := start_scope.find_scope_and_var(ident.name) or { - found = false - c.error('not found: $ident.name - POS: $ident.pos.pos', ident.pos) - panic('') - } - if found { - // update the variable - // we need to do this here instead of var_decl since some - // vars are registered manually for things like for loops etc - // NOTE: or consider making those declarations part of those ast nodes + if var := start_scope.find_var(ident.name) { mut typ := var.typ - // set var type on first use if typ == 0 { typ = c.expr(var.expr) - var_scope.update_var_type(var.name, typ) } - // update ident ident.kind = .variable ident.info = ast.IdentVar{ typ: typ @@ -915,33 +885,35 @@ pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type { } return typ } - } - // second use, already resovled in unresolved branch - else if ident.kind == .constant { - info := ident.info as ast.IdentVar - return info.typ - } - // second use, already resovled in unresovled branch - else if ident.kind == .function { - info := ident.info as ast.IdentFn - return info.typ - } - // Handle indents with unresolved types during the parsing step - // (declared after first usage) - else if ident.kind == .unresolved { // prepend mod to look for fn call or const mut name := ident.name - if !name.contains('.') && !(c.file.mod.name in ['builtin', 'main']) { - name = '${c.file.mod.name}.$ident.name' + if !name.contains('.') && !(ident.mod in ['builtin', 'main']) { + name = '${ident.mod}.$ident.name' } - // constant - if constant := c.table.find_const(name) { - ident.name = name - ident.kind = .constant - ident.info = ast.IdentVar{ - typ: constant.typ + if obj := c.file.global_scope.find(name) { + match obj { + ast.GlobalDecl { + ident.kind = .global + ident.info = ast.IdentVar{ + typ: it.typ + } + return it.typ + } + ast.ConstField { + mut typ := it.typ + if typ == 0 { + typ = c.expr(it.expr) + } + ident.name = name + ident.kind = .constant + ident.info = ast.IdentVar{ + typ: typ + } + it.typ = typ + return typ + } + else {} } - return constant.typ } // Function object (not a call), e.g. `onclick(my_click)` if func := c.table.find_fn(name) { diff --git a/vlib/v/doc/doc.v b/vlib/v/doc/doc.v index 348add4abe..59beb06ab0 100644 --- a/vlib/v/doc/doc.v +++ b/vlib/v/doc/doc.v @@ -45,7 +45,7 @@ pub fn doc(mod string, table &table.Table) string { if file.ends_with('_test.v') || file.ends_with('_windows.v') || file.ends_with('_macos.v') { continue } - file_ast := parser.parse_file(os.join_path(path,file), table, .skip_comments, &pref.Preferences{}) + file_ast := parser.parse_file(os.join_path(path,file), table, .skip_comments, &pref.Preferences{}, &ast.Scope{parent: 0}) d.stmts << file_ast.stmts } if d.stmts.len == 0 { diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index cf66fc1d9a..2aeca384eb 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -142,7 +142,7 @@ fn (f mut Fmt) stmt(node ast.Stmt) { for i, field in it.fields { name := field.name.after('.') f.write('$name = ') - f.expr(it.exprs[i]) + f.expr(field.expr) f.writeln('') } f.indent-- diff --git a/vlib/v/fmt/fmt_test.v b/vlib/v/fmt/fmt_test.v index 88ac6fd7f3..9beda6b0c6 100644 --- a/vlib/v/fmt/fmt_test.v +++ b/vlib/v/fmt/fmt_test.v @@ -2,6 +2,7 @@ import ( os term benchmark + v.ast v.fmt v.parser v.table @@ -46,7 +47,7 @@ fn test_fmt() { continue } table := table.new_table() - file_ast := parser.parse_file(ipath, table, .parse_comments, &pref.Preferences{}) + file_ast := parser.parse_file(ipath, table, .parse_comments, &pref.Preferences{}, &ast.Scope{parent: 0}) result_ocontent := fmt.fmt(file_ast, table) if expected_ocontent != result_ocontent { fmt_bench.fail() diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index d4569a85fa..abf8bc8d16 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -762,7 +762,7 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) { if name.starts_with('_op_') { name = op_to_fn_name(name) } - // type_name := g.table.type_to_str(it.return_type) + // type_name := g.table.Type_to_str(it.return_type) type_name := g.typ(it.return_type) g.write('$type_name ${name}(') g.definitions.write('$type_name ${name}(') @@ -834,34 +834,40 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) { fn (g mut Gen) free_scope_vars(pos int) { scope := g.file.scope.innermost(pos) - for _, var in scope.vars { - // println('//////') - // println(var.name) - // println(var.typ) - // if var.typ == 0 { - // // TODO why 0? - // continue - // } - sym := g.table.get_type_symbol(var.typ) - if sym.kind == .array && !table.type_is_optional(var.typ) { - g.writeln('array_free($var.name); // autofreed') - } - if sym.kind == .string && !table.type_is_optional(var.typ) { - // Don't free simple string literals. - t := typeof(var.expr) - match var.expr { - ast.StringLiteral { - g.writeln('// str literal') - continue + for _, obj in scope.objects { + match obj { + ast.Var { + // println('//////') + // println(var.name) + // println(var.typ) + // if var.typ == 0 { + // // TODO why 0? + // continue + // } + var := *it + sym := g.table.get_type_symbol(var.typ) + if sym.kind == .array && !table.type_is_optional(var.typ) { + g.writeln('array_free($var.name); // autofreed') } - else { - // NOTE/TODO: assign_stmt multi returns variables have no expr - // since the type comes from the called fns return type - g.writeln('// other ' + t) - continue + if sym.kind == .string && !table.type_is_optional(var.typ) { + // Don't free simple string literals. + t := typeof(var.expr) + match var.expr { + ast.StringLiteral { + g.writeln('// str literal') + continue + } + else { + // NOTE/TODO: assign_stmt multi returns variables have no expr + // since the type comes from the called fns return type + g.writeln('// other ' + t) + continue + } + } + g.writeln('string_free($var.name); // autofreed') } - } - g.writeln('string_free($var.name); // autofreed') + } + else {} } } } @@ -995,7 +1001,7 @@ fn (g mut Gen) expr(node ast.Expr) { g.expr_with_cast(it.expr, it.expr_type, it.typ) } else { - // styp := g.table.type_to_str(it.typ) + // styp := g.table.Type_to_str(it.typ) styp := g.typ(it.typ) // g.write('($styp)(') g.write('(($styp)(') @@ -1837,13 +1843,12 @@ fn (g mut Gen) return_statement(node ast.Return) { fn (g mut Gen) const_decl(node ast.ConstDecl) { for i, field in node.fields { name := c_name(field.name) - expr := node.exprs[i] // TODO hack. Cut the generated value and paste it into definitions. pos := g.out.len - g.expr(expr) + g.expr(field.expr) val := g.out.after(pos) g.out.go_back(val.len) - match expr { + match field.expr { ast.CharLiteral, ast.IntegerLiteral { // Simple expressions should use a #define // so that we don't pollute the binary with unnecessary global vars @@ -2155,15 +2160,15 @@ int typ; } // sort structs by dependant fields -fn (g &Gen) sort_structs(types []table.TypeSymbol) []table.TypeSymbol { +fn (g &Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol { mut dep_graph := depgraph.new_dep_graph() // types name list mut type_names := []string - for typ in types { + for typ in typesa { type_names << typ.name } // loop over types - for t in types { + for t in typesa { // create list of deps mut field_deps := []string match t.info { diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index a2fa6f5bfe..5c232c7a0e 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -18,7 +18,7 @@ pub fn (p mut Parser) call_expr(is_c bool, mod string) ast.CallExpr { if p.tok.kind == .key_orelse { p.next() p.open_scope() - p.scope.register_var(ast.Var{ + p.scope.register('err', ast.Var{ name: 'err' typ: table.string_type }) @@ -29,7 +29,7 @@ pub fn (p mut Parser) call_expr(is_c bool, mod string) ast.CallExpr { name: fn_name args: args // tok: tok - + mod: p.mod pos: tok.position() is_c: is_c or_block: ast.OrExpr{ @@ -118,7 +118,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl { args2,is_variadic := p.fn_args() args << args2 for arg in args { - p.scope.register_var(ast.Var{ + p.scope.register(arg.name, ast.Var{ name: arg.name typ: arg.typ }) diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index e54d5f07f1..52a406b845 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -18,26 +18,27 @@ import ( ) struct Parser { - scanner &scanner.Scanner - file_name string + scanner &scanner.Scanner + file_name string mut: - tok token.Token - peek_tok token.Token + tok token.Token + peek_tok token.Token // vars []string - table &table.Table - is_c bool + table &table.Table + is_c bool // prefix_parse_fns []PrefixParseFn - inside_if bool - pref &pref.Preferences // Preferences shared from V struct - builtin_mod bool - mod string - attr string - expr_mod string - scope &ast.Scope - imports map[string]string - ast_imports []ast.Import - is_amp bool - returns bool + inside_if bool + pref &pref.Preferences // Preferences shared from V struct + builtin_mod bool + mod string + attr string + expr_mod string + scope &ast.Scope + global_scope &ast.Scope + imports map[string]string + ast_imports []ast.Import + is_amp bool + returns bool inside_match_case bool // to separate `match_expr { }` from `Struct{}` } @@ -50,14 +51,17 @@ pub fn parse_stmt(text string, table &table.Table, scope &ast.Scope) ast.Stmt { pref: &pref.Preferences{} scope: scope // scope: &ast.Scope{start_pos: 0, parent: 0} - + global_scope: &ast.Scope{ + start_pos: 0 + parent: 0 + } } p.init_parse_fns() p.read_first_token() return p.stmt() } -pub fn parse_file(path string, table &table.Table, comments_mode scanner.CommentsMode, pref &pref.Preferences) ast.File { +pub fn parse_file(path string, table &table.Table, comments_mode scanner.CommentsMode, pref &pref.Preferences, global_scope &ast.Scope) ast.File { // println('parse_file("$path")') // text := os.read_file(path) or { // panic(err) @@ -74,11 +78,11 @@ pub fn parse_file(path string, table &table.Table, comments_mode scanner.Comment start_pos: 0 parent: 0 } + global_scope: global_scope // comments_mode: comments_mode } p.read_first_token() - // p.scope = &ast.Scope{start_pos: p.tok.position(), parent: 0} // module decl module_decl := if p.tok.kind == .key_module { p.module_decl() } else { ast.Module{name: 'main' } } @@ -110,6 +114,7 @@ pub fn parse_file(path string, table &table.Table, comments_mode scanner.Comment imports: p.ast_imports stmts: stmts scope: p.scope + global_scope: p.global_scope } } @@ -141,7 +146,7 @@ fn (q mut Queue) run() { */ -pub fn parse_files(paths []string, table &table.Table, pref &pref.Preferences) []ast.File { +pub fn parse_files(paths []string, table &table.Table, pref &pref.Preferences, global_scope &ast.Scope) []ast.File { /* println('\n\n\nparse_files()') println(paths) @@ -162,7 +167,7 @@ pub fn parse_files(paths []string, table &table.Table, pref &pref.Preferences) [ mut files := []ast.File for path in paths { // println('parse_files $path') - files << parse_file(path, table, .skip_comments, pref) + files << parse_file(path, table, .skip_comments, pref, global_scope) } return files } @@ -530,16 +535,9 @@ pub fn (p mut Parser) parse_ident(is_c bool) ast.Ident { kind: .unresolved name: name is_c: is_c + mod: p.mod pos: pos } - // variable - if p.expr_mod.len == 0 { - if var := p.scope.find_var(name) { - ident.kind = .variable - ident.info = ast.IdentVar{} - } - } - // handle consts/fns in checker return ident } @@ -941,7 +939,7 @@ fn (p mut Parser) index_expr(left ast.Expr) ast.IndexExpr { } fn (p mut Parser) filter() { - p.scope.register_var(ast.Var{ + p.scope.register('it', ast.Var{ name: 'it' }) } @@ -967,7 +965,7 @@ fn (p mut Parser) dot_expr(left ast.Expr) ast.Expr { if p.tok.kind == .key_orelse { p.next() p.open_scope() - p.scope.register_var(ast.Var{ + p.scope.register('err', ast.Var{ name: 'err' typ: table.string_type }) @@ -1112,7 +1110,7 @@ fn (p mut Parser) for_statement() ast.Stmt { p.check(.comma) key_var_name = val_var_name val_var_name = p.check_name() - p.scope.register_var(ast.Var{ + p.scope.register(key_var_name, ast.Var{ name: key_var_name typ: table.int_type }) @@ -1129,14 +1127,14 @@ fn (p mut Parser) for_statement() ast.Stmt { is_range = true p.check(.dotdot) high_expr = p.expr(0) - p.scope.register_var(ast.Var{ + p.scope.register(val_var_name, ast.Var{ name: val_var_name typ: table.int_type }) } else { // this type will be set in checker - p.scope.register_var(ast.Var{ + p.scope.register(val_var_name, ast.Var{ name: val_var_name }) } @@ -1197,7 +1195,7 @@ fn (p mut Parser) if_expr() ast.IfExpr { var_name := p.check_name() p.check(.decl_assign) expr := p.expr(0) - p.scope.register_var(ast.Var{ + p.scope.register(var_name, ast.Var{ name: var_name expr: expr }) @@ -1436,31 +1434,26 @@ fn (p mut Parser) const_decl() ast.ConstDecl { pos := p.tok.position() p.check(.key_const) p.check(.lpar) - mut fields := []ast.Field - mut exprs := []ast.Expr + mut fields := []ast.ConstField for p.tok.kind != .rpar { name := p.prepend_mod(p.check_name()) + // name := p.check_name() // println('!!const: $name') p.check(.assign) expr := p.expr(0) - fields << ast.Field{ + field := ast.ConstField{ name: name + expr: expr pos: p.tok.position() - // typ: typ } - exprs << expr - // TODO: once consts are fixed reg here & update in checker - // p.table.register_const(table.Var{ - // name: name - // // typ: typ - // }) + fields << field + p.global_scope.register(field.name, field) } p.check(.rpar) return ast.ConstDecl{ pos : pos fields: fields - exprs: exprs is_pub: is_pub } } @@ -1695,13 +1688,13 @@ fn (p mut Parser) assign_stmt() ast.Stmt { p.error('redefinition of `$ident.name`') } if idents.len == exprs.len { - p.scope.register_var(ast.Var{ + p.scope.register(ident.name, ast.Var{ name: ident.name expr: exprs[i] }) } else { - p.scope.register_var(ast.Var{ + p.scope.register(ident.name, ast.Var{ name: ident.name }) } @@ -1736,27 +1729,28 @@ fn (p mut Parser) global_decl() ast.GlobalDecl { p.next() p.expr(0) } - p.table.register_global(name, typ) // p.genln(p.table.cgen_name_type_pair(name, typ)) /* - mut g := p.table.cgen_name_type_pair(name, typ) - if p.tok == .assign { - p.next() - g += ' = ' - _,expr := p.tmp_expr() - g += expr - } - // p.genln('; // global') - g += '; // global' - if !p.cgen.nogen { - p.cgen.consts << g - } - */ + mut g := p.table.cgen_name_type_pair(name, typ) + if p.tok == .assign { + p.next() + g += ' = ' + _,expr := p.tmp_expr() + g += expr + } + // p.genln('; // global') + g += '; // global' + if !p.cgen.nogen { + p.cgen.consts << g + } + */ - return ast.GlobalDecl{ + glob := ast.GlobalDecl{ name: name typ: typ } + p.global_scope.register(name, glob) + return glob } fn (p mut Parser) match_expr() ast.MatchExpr { @@ -1793,7 +1787,7 @@ fn (p mut Parser) match_expr() ast.MatchExpr { mut expr := ast.Expr{} expr = x exprs << expr - p.scope.register_var(ast.Var{ + p.scope.register('it', ast.Var{ name: 'it' typ: table.type_to_ptr(typ) }) diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index 1a319777be..3c85a1ba70 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -13,7 +13,6 @@ pub mut: type_idxs map[string]int // fns Hashmap fns map[string]Fn - consts map[string]Var imports []string // List of all imports modules []string // List of all modules registered by the application } @@ -38,8 +37,6 @@ pub struct Var { pub: name string is_mut bool - is_const bool - is_global bool mut: typ Type } @@ -50,23 +47,6 @@ pub fn new_table() &Table { return t } -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) { - t.consts[name] = Var{ - name: name - typ: typ - is_const: true - is_global: true - // mod: p.mod - // is_mut: true - // idx: -1 - - } -} - // used to compare fn's & for naming anon fn's pub fn (f &Fn) signature() string { mut sig := '' @@ -95,15 +75,6 @@ pub fn (t &Table) find_fn(name string) ?Fn { return none } -pub fn (t &Table) find_const(name string) ?Var { - f := t.consts[name] - if f.name.str != 0 { - // TODO - return f - } - return none -} - pub fn (t mut Table) register_fn(new_fn Fn) { // println('reg fn $new_fn.name nr_args=$new_fn.args.len') t.fns[new_fn.name] = new_fn diff --git a/vlib/v/tests/const_test.v b/vlib/v/tests/const_test.v index c248b264a1..3b19b255b8 100644 --- a/vlib/v/tests/const_test.v +++ b/vlib/v/tests/const_test.v @@ -1,4 +1,5 @@ pub const ( + c = a a = b c = a + b b = 1 @@ -13,5 +14,5 @@ struct Foo { fn test_const() { assert a == 1 assert d == 11 - // assert c == 1 // TODO: This will not build yet + assert c == 1 }