From 4262ff76c36bb364a9353cc3eff7486b20109930 Mon Sep 17 00:00:00 2001 From: Joe Conigliaro Date: Wed, 18 Mar 2020 23:18:18 +1100 Subject: [PATCH] checker/parser: check & gen stmts for ForIn & fix key, val vars --- vlib/v/checker/checker.v | 89 +++++++++++++++++++++++----------------- vlib/v/gen/cgen.v | 10 ++--- vlib/v/parser/parser.v | 29 +++++++------ vlib/v/table/table.v | 53 ++++++++++++++++++++---- 4 files changed, 117 insertions(+), 64 deletions(-) diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index f5c64dcf53..9f532cf607 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -319,6 +319,11 @@ pub fn (c mut Checker) method_call_expr(method_call_expr mut ast.MethodCallExpr) method_call_expr.return_type = method.return_type return method.return_type } + // TODO: str methods + if typ_sym.kind in [.map] && name == 'str' { + method_call_expr.return_type = table.string_type + return table.string_type + } c.error('type `$typ_sym.name` has no method `$name`', method_call_expr.pos) return table.void_type } @@ -530,9 +535,7 @@ fn (c mut Checker) stmt(node ast.Stmt) { ast.FnDecl { c.expected_type = table.void_type c.fn_return_type = it.return_type - for stmt in it.stmts { - c.stmt(stmt) - } + c.stmts(it.stmts) } ast.ForStmt { typ := c.expr(it.cond) @@ -541,22 +544,47 @@ fn (c mut Checker) stmt(node ast.Stmt) { } // TODO: update loop var type // how does this work currenly? - for stmt in it.stmts { - c.stmt(stmt) - } + c.stmts(it.stmts) } ast.ForCStmt { c.stmt(it.init) c.expr(it.cond) // c.stmt(it.inc) c.expr(it.inc) - for stmt in it.stmts { - c.stmt(stmt) - } + c.stmts(it.stmts) } ast.ForInStmt { - c.expr(it.cond) - c.expr(it.high) + typ := c.expr(it.cond) + if it.is_range { + c.expr(it.high) + } + else { + mut scope := c.file.scope.innermost(it.pos.pos) + if it.key_var.len > 0 { + sym := c.table.get_type_symbol(typ) + key_type := match sym.kind { + .map{ + sym.map_info().key_type + } + else { + table.int_type} + } + scope.override_var(ast.Var{ + name: it.key_var + typ: key_type + }) + } + value_type := c.table.value_type(typ) + if value_type == table.void_type { + typ_sym := c.table.get_type_symbol(typ) + c.error('for in: cannot index $typ_sym.name', it.pos) + } + scope.override_var(ast.Var{ + name: it.val_var + typ: c.table.value_type(typ) + }) + } + c.stmts(it.stmts) } // ast.GlobalDecl {} // ast.HashStmt {} @@ -566,9 +594,7 @@ fn (c mut Checker) stmt(node ast.Stmt) { } // ast.StructDecl {} ast.UnsafeStmt { - for stmt in it.stmts { - c.stmt(stmt) - } + c.stmts(it.stmts) } else {} // println('checker.stmt(): unhandled node') @@ -761,6 +787,15 @@ pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type { if !name.contains('.') && !(c.file.mod.name in ['builtin', 'main']) { name = '${c.file.mod.name}.$ident.name' } + // hack - const until consts are fixed properly + if ident.name == 'v_modules_path' { + ident.name = name + ident.kind = .constant + ident.info = ast.IdentVar{ + typ: table.string_type + } + return table.string_type + } // constant if constant := c.table.find_const(name) { ident.name = name @@ -913,30 +948,10 @@ pub fn (c mut Checker) index_expr(node mut ast.IndexExpr) table.Type { else if typ_sym.kind == .map && table.type_idx(index_type) != table.string_type_idx { c.error('non-string map index (type `$typ_sym.name`)', node.pos) } - if typ_sym.kind == .array { - // Check index type - info := typ_sym.info as table.Array - return info.elem_type + value_type := c.table.value_type(typ) + if value_type != table.void_type { + return value_type } - else if typ_sym.kind == .array_fixed { - info := typ_sym.info as table.ArrayFixed - return info.elem_type - } - else if typ_sym.kind == .map { - info := typ_sym.info as table.Map - return info.value_type - } - else if typ_sym.kind in [.byteptr, .string] { - return table.byte_type - } - else if table.type_is_ptr(typ) { - // byte* => byte - // bytes[0] is a byte, not byte* - return table.type_deref(typ) - } - // else { - // return table.int_type - // } } return typ } diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 6a406f3049..e1b9562a52 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -271,9 +271,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { // g.stmt(it.inc) g.expr(it.inc) g.writeln(') {') - for stmt in it.stmts { - g.stmt(stmt) - } + g.stmts(it.stmts) g.writeln('}') } ast.ForInStmt { @@ -284,7 +282,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { g.write('; $i < ') g.expr(it.high) g.writeln('; $i++) { ') - // g.stmts(it.stmts) TODO + g.stmts(it.stmts) g.writeln('}') } } @@ -297,9 +295,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { g.expr(it.cond) } g.writeln(') {') - for stmt in it.stmts { - g.stmt(stmt) - } + g.stmts(it.stmts) g.writeln('}') } ast.GlobalDecl { diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index cbbe993823..a1ac77fc2f 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -1096,13 +1096,14 @@ fn (p mut Parser) for_statement() ast.Stmt { } // `for i in vals`, `for i in start .. end` else if p.peek_tok.kind in [.key_in, .comma] { - var_name := p.check_name() - mut val_name := '' + mut key_var_name := '' + mut val_var_name := p.check_name() if p.tok.kind == .comma { p.check(.comma) - val_name = p.check_name() + key_var_name = val_var_name + val_var_name = p.check_name() p.scope.register_var(ast.Var{ - name: val_name + name: key_var_name typ: table.int_type }) } @@ -1118,13 +1119,17 @@ 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{ + name: val_var_name + typ: table.int_type + }) + } + else { + // this type will be set in checker + p.scope.register_var(ast.Var{ + name: val_var_name + }) } - // TODO: update var type in checker - p.scope.register_var(ast.Var{ - name: var_name - // expr: cond - - }) stmts := p.parse_block() // println('nr stmts=$stmts.len') p.close_scope() @@ -1132,8 +1137,8 @@ fn (p mut Parser) for_statement() ast.Stmt { stmts: stmts pos: p.tok.position() cond: cond - key_var: var_name - val_var: val_name + key_var: key_var_name + val_var: val_var_name high: high_expr is_range: is_range } diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index f0c77b60c5..aeb2101a32 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -29,19 +29,19 @@ pub: pub struct Arg { pub: - name string - is_mut bool - typ Type + name string + is_mut bool + typ Type } pub struct Var { pub: - name string - is_mut bool - is_const bool - is_global bool + name string + is_mut bool + is_const bool + is_global bool mut: - typ Type + typ Type } pub fn new_table() &Table { @@ -411,6 +411,43 @@ pub fn (t mut Table) add_placeholder_type(name string) int { return t.register_type_symbol(ph_type) } +[inline] +pub fn (t &Table) value_type(typ Type) Type { + typ_sym := t.get_type_symbol(typ) + if typ_sym.kind == .array { + // Check index type + info := typ_sym.info as Array + return info.elem_type + } + else if typ_sym.kind == .array_fixed { + info := typ_sym.info as ArrayFixed + return info.elem_type + } + else if typ_sym.kind == .map { + info := typ_sym.info as Map + return info.value_type + } + else if typ_sym.kind in [.byteptr, .string] { + return byte_type + } + else if type_is_ptr(typ) { + // byte* => byte + // bytes[0] is a byte, not byte* + return type_deref(typ) + } + else if type_is_variadic(typ) { + // ...string => string + return type_clear_extra(typ) + } + else { + // TODO: remove when map_string is removed + if typ_sym.name == 'map_string' { + return string_type + } + return void_type + } +} + pub fn (t &Table) check(got, expected Type) bool { got_type_sym := t.get_type_symbol(got) exp_type_sym := t.get_type_symbol(expected)