diff --git a/vlib/compiler/main.v b/vlib/compiler/main.v index bd051bc1a8..de27ccf425 100644 --- a/vlib/compiler/main.v +++ b/vlib/compiler/main.v @@ -8,11 +8,7 @@ import ( os.cmdline strings filepath - v.gen.x64 - v.table - v.parser - v.gen - time + v.builder ) pub const ( @@ -390,29 +386,15 @@ pub fn (v mut V) compile2() { println('all .v files before:') println(v.files) } - v.add_v_files_to_compile() + // v.add_v_files_to_compile() + v.files << v.dir if v.pref.is_verbose { println('all .v files:') println(v.files) } - table := table.new_table() - files := parser.parse_files(v.files, table) - c := gen.cgen(files, table) - println('out: $v.out_name_c') - os.write_file(v.out_name_c, c) - /* - cgen.genln(c_builtin_types) - - if !v.pref.is_bare { - cgen.genln(c_headers) - } - else { - cgen.genln(bare_c_headers) - } - } - */ + mut b := builder.new_builder() + b.build_c(v.files, v.out_name) v.cc() - } pub fn (v mut V) compile_x64() { @@ -423,12 +405,8 @@ pub fn (v mut V) compile_x64() { //v.files << v.v_files_from_dir(filepath.join(v.pref.vlib_path,'builtin','bare')) v.files << v.dir - table := &table.new_table() - ticks := time.ticks() - files := parser.parse_files(v.files, table) - println('PARSE: ${time.ticks() - ticks}ms') - x64.gen(files, v.out_name) - println('x64 GEN: ${time.ticks() - ticks}ms') + mut b := builder.new_builder() + b.build_x64(v.files, v.out_name) } fn (v mut V) generate_init() { diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 08a667106e..b55087f4b8 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -45,6 +45,7 @@ pub: // `foo.bar` pub struct SelectorExpr { pub: + pos token.Position expr Expr field string } @@ -60,11 +61,13 @@ pub: pub struct Field { pub: name string + // type_idx int ti types.TypeIdent } pub struct StructDecl { pub: + pos token.Position name string fields []Field is_pub bool @@ -72,7 +75,7 @@ pub: pub struct StructInit { pub: -// typ types.TypeIdent + pos token.Position ti types.TypeIdent fields []string exprs []Expr @@ -81,7 +84,9 @@ pub: // import statement pub struct Import { pub: - mods map[string]string // alias -> module + pos token.Position + mod string + alias string // expr Expr } @@ -103,24 +108,27 @@ pub: pub struct CallExpr { pub: -// func Expr + // tok token.Token + pos token.Position +mut: + // func Expr name string args []Expr - is_unknown bool - tok token.Token } pub struct MethodCallExpr { pub: + // tok token.Token + pos token.Position expr Expr name string args []Expr - is_unknown bool - tok token.Token } pub struct Return { pub: + pos token.Position + expected_ti types.TypeIdent // TODO: remove once checker updated exprs []Expr } @@ -144,12 +152,30 @@ pub struct VarDecl { pub: name string expr Expr + is_mut bool + mut: ti types.TypeIdent + pos token.Position } pub struct File { pub: - stmts []Stmt + mod Module + imports []Import + stmts []Stmt +} + +pub struct IdentVar { +pub: + expr Expr + ti types.TypeIdent +} + +type IdentInfo = IdentVar + +pub enum IdentKind { + blank_ident + variable } // A single identifier @@ -157,14 +183,18 @@ pub struct Ident { pub: name string tok_kind token.Kind + pos token.Position value string +mut: + kind IdentKind + info IdentInfo } pub struct BinaryExpr { pub: -// tok_kind token.Kind // op BinaryOp op token.Kind + pos token.Position left Expr // left_ti types.TypeIdent right Expr @@ -231,6 +261,7 @@ pub: pub struct ReturnStmt { tok_kind token.Kind // or pos + pos token.Position results []Expr } @@ -246,9 +277,10 @@ pub: pub struct AssignExpr { pub: + op token.Kind + pos token.Position left Expr val Expr - op token.Kind } pub struct ArrayInit { diff --git a/vlib/v/builder/builder.v b/vlib/v/builder/builder.v new file mode 100644 index 0000000000..7681bf5d71 --- /dev/null +++ b/vlib/v/builder/builder.v @@ -0,0 +1,45 @@ +module builder + +import ( + os + time + v.table + v.checker + v.parser + v.gen + v.gen.x64 +) + +pub struct Builder { +pub: + table &table.Table + checker checker.Checker +} + +pub fn new_builder() Builder { + table := table.new_table() + return Builder{ + table: table + checker: checker.new_checker(table) + } +} + +pub fn (b mut Builder) gen_c(v_files []string) string { + ast_files := parser.parse_files(v_files, b.table) + b.checker.check_files(v_files, ast_files) + return gen.cgen(ast_files, b.table) +} + +pub fn (b mut Builder) build_c(v_files []string, out_file string) { + os.write_file(out_file, b.gen_c(v_files)) +} + +pub fn (b mut Builder) build_x64(v_files []string, out_file string) { + ticks := time.ticks() + ast_files := parser.parse_files(v_files, b.table) + println('PARSE: ${time.ticks() - ticks}ms') + b.checker.check_files(v_files, ast_files) + println('CHECK: ${time.ticks() - ticks}ms') + x64.gen(ast_files, out_file) + println('x64 GEN: ${time.ticks() - ticks}ms') +} diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v new file mode 100644 index 0000000000..a513b61bd3 --- /dev/null +++ b/vlib/v/checker/checker.v @@ -0,0 +1,258 @@ +// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module checker + +import ( + v.ast + v.table + v.types + v.token +) + +pub struct Checker { + table &table.Table +mut: + file_name string + // TODO: resolved +} + +pub fn new_checker(table &table.Table) Checker { + return Checker{ + table: table + } +} + +pub fn (c &Checker) check(ast_file ast.File) { + for stmt in ast_file.stmts { + c.stmt(stmt) + } +} + +pub fn (c mut Checker) check_files(v_files []string, ast_files []ast.File) { + for i, file in ast_files { + c.file_name = v_files[i] + c.check(file) + } +} + +pub fn (c &Checker) check_struct_init(struct_init ast.StructInit) { + typ := c.table.find_type(struct_init.ti.name) or { + c.error('unknown struct: $struct_init.ti.name', struct_init.pos) + panic('') + } + match typ.kind { + .placeholder { + c.error('unknown struct: $struct_init.ti.name', struct_init.pos) + } + .struct_ { + info := typ.info as types.Struct + for i, expr in struct_init.exprs { + field := info.fields[i] + expr_ti := c.table.get_expr_ti(expr) + if !c.table.check(expr_ti, field.ti) { + c.error('cannot assign $expr_ti.name as $field.ti.name for field $field.name', struct_init.pos) + } + } + } + else {} + } +} + +pub fn (c &Checker) check_binary_expr(binary_expr ast.BinaryExpr) { + left_ti := c.table.get_expr_ti(binary_expr.left) + right_ti := c.table.get_expr_ti(binary_expr.right) + if !c.table.check(&right_ti, &left_ti) { + c.error('binary expr: cannot use $right_ti.name as $left_ti.name', binary_expr.pos) + } +} + +fn (c &Checker) check_assign_expr(assign_expr ast.AssignExpr) { + left_ti := c.table.get_expr_ti(assign_expr.left) + right_ti := c.table.get_expr_ti(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) + } +} + +pub fn (c &Checker) check_call_expr(call_expr ast.CallExpr) { + fn_name := call_expr.name + if f := c.table.find_fn(fn_name) { + // return_ti := f.return_ti + if call_expr.args.len < f.args.len { + c.error('too few arguments in call to `$fn_name`', call_expr.pos) + } else if call_expr.args.len > f.args.len { + c.error('too many arguments in call to `$fn_name`', call_expr.pos) + } + for i, arg in f.args { + arg_expr := call_expr.args[i] + ti := c.table.get_expr_ti(arg_expr) + if !c.table.check(&ti, &arg.ti) { + c.error('cannot use type `$ti.name` as type `$arg.ti.name` in argument to `$fn_name`', call_expr.pos) + } + } + } else { + c.error('unknown fn: $fn_name', call_expr.pos) + // c.warn('unknown function `$fn_name`') + } +} + +pub fn (c &Checker) check_method_call_expr(method_call_expr ast.MethodCallExpr) { + ti := c.table.get_expr_ti(method_call_expr.expr) + if !c.table.has_method(ti.idx, method_call_expr.name) { + c.error('type `$ti.name` has no method `$method_call_expr.name`', method_call_expr.pos) + } +} + +pub fn (c &Checker) check_selector_expr(selector_expr ast.SelectorExpr) { + ti := c.table.get_expr_ti(selector_expr.expr) + field_name := selector_expr.field + // struct_ := c.table.types[ti.idx] as types.Struct + typ := c.table.types[ti.idx] + match typ.kind { + .struct_ { + // if !c.table.struct_has_field(it, field) { + // c.error('AAA unknown field `${it.name}.$field`') + // } + // TODO: fix bug + c.table.struct_find_field(typ, field_name) or { + c.error('unknown field `${typ.name}.$field_name`', selector_expr.pos) + } + } + else { + c.error('$ti.name is not a struct', selector_expr.pos) + } + } +} + +// TODO: non deferred +pub fn (c &Checker) check_return_stmt(return_stmt ast.Return) { + mut got_tis := []types.TypeIdent + for expr in return_stmt.exprs { + ti := c.table.get_expr_ti(expr) + got_tis << ti + } + 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 types.MultiReturn + expected_tis = mr_info.tis + } + if 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) + } + 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) + } + } +} + +fn (c &Checker) stmt(node ast.Stmt) { + match node { + ast.FnDecl { + for stmt in it.stmts { + c.stmt(stmt) + } + } + ast.Return { + c.check_return_stmt(it) + } + ast.VarDecl { + c.expr(it.expr) + } + ast.ForStmt { + c.expr(it.cond) + for stmt in it.stmts { + c.stmt(stmt) + } + } + ast.ForCStmt { + c.stmt(it.init) + c.expr(it.cond) + c.stmt(it.inc) + for stmt in it.stmts { + c.stmt(stmt) + } + } + // ast.StructDecl {} + ast.ExprStmt { + c.expr(it.expr) + } + else {} + } +} + +fn (c &Checker) expr(node ast.Expr) { + match node { + ast.AssignExpr { + c.check_assign_expr(it) + } + // ast.IntegerLiteral {} + // ast.FloatLiteral {} + ast.PostfixExpr { + c.expr(it.expr) + } + ast.UnaryExpr { + c.expr(it.left) + } + // ast.StringLiteral {} + ast.PrefixExpr { + c.expr(it.right) + } + ast.BinaryExpr { + c.check_binary_expr(it) + } + ast.StructInit { + c.check_struct_init(it) + } + ast.CallExpr { + c.check_call_expr(it) + } + ast.MethodCallExpr { + c.check_method_call_expr(it) + } + ast.ArrayInit { + for expr in it.exprs { + c.expr(expr) + } + } + // ast.Ident {} + // ast.BoolLiteral {} + ast.SelectorExpr { + c.check_selector_expr(it) + } + ast.IndexExpr { + c.expr(it.left) + c.expr(it.index) + } + ast.IfExpr { + c.expr(it.cond) + for i, stmt in it.stmts { + c.stmt(stmt) + } + if it.else_stmts.len > 0 { + for stmt in it.else_stmts { + c.stmt(stmt) + } + } + } + else {} + } +} + +pub fn (c &Checker) error(s string, pos token.Position) { + print_backtrace() + final_msg_line := '$c.file_name:$pos.line_nr: error: $s' + eprintln(final_msg_line) + /* + if colored_output { + eprintln(term.bold(term.red(final_msg_line))) + }else{ + eprintln(final_msg_line) + } + */ + exit(1) +} diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index d3186a35b9..82a78302f4 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -55,15 +55,18 @@ fn (g mut Gen) stmt(node ast.Stmt) { g.write('int ${it.name}(') } else { - g.write('$it.ti.name ${it.name}(') - g.definitions.write('$it.ti.name ${it.name}(') + ti := g.table.refresh_ti(it.ti) + g.write('$ti.name ${it.name}(') + g.definitions.write('$ti.name ${it.name}(') } for i, arg in it.args { - g.write(arg.ti.name + ' ' + arg.name) + // t := g.table.get_type(arg.ti.idx) + ti := g.table.refresh_ti(arg.ti) + g.write(ti.name + ' ' + arg.name) if i < it.args.len - 1 { g.write(', ') } - g.definitions.write(arg.ti.name + ' ' + arg.name) + g.definitions.write(ti.name + ' ' + arg.name) } g.writeln(') { ') if !is_main { @@ -82,7 +85,9 @@ fn (g mut Gen) stmt(node ast.Stmt) { g.write('return ') // multiple returns if it.exprs.len > 1 { - g.write('($g.fn_decl.ti.name){') + // t := g.table.get_type(g.fn_decl.ti.idx) + ti := g.table.refresh_ti(g.fn_decl.ti) + g.write('($ti.name){') for i, expr in it.exprs { g.write('.arg$i=') g.expr(expr) @@ -99,7 +104,14 @@ fn (g mut Gen) stmt(node ast.Stmt) { g.writeln(';') } ast.VarDecl { - g.write('$it.ti.name $it.name = ') + mut ti := it.ti + if ti.kind == .unresolved { + ti = g.table.get_expr_ti(it.expr) + // println('A $it.ti.name') + // println('B $ti.name') + // panic("############# UNRESOLVED") + } + g.write('$ti.name $it.name = ') g.expr(it.expr) g.writeln(';') } @@ -128,7 +140,9 @@ fn (g mut Gen) stmt(node ast.Stmt) { ast.StructDecl { g.writeln('typedef struct {') for field in it.fields { - g.writeln('\t$field.ti.name $field.name;') + // t := g.table.get_type(field.ti.idx) + ti := g.table.refresh_ti(field.ti) + g.writeln('\t$ti.name $field.name;') } g.writeln('} $it.name;') } @@ -197,7 +211,9 @@ fn (g mut Gen) expr(node ast.Expr) { } // `user := User{name: 'Bob'}` ast.StructInit { - g.writeln('($it.ti.name){') + // t := g.table.get_type(it.ti.idx) + ti := g.table.refresh_ti(it.ti) + g.writeln('($ti.name){') for i, field in it.fields { g.write('\t.$field = ') g.expr(it.exprs[i]) @@ -215,8 +231,11 @@ fn (g mut Gen) expr(node ast.Expr) { } g.write(')') } + ast.MethodCallExpr {} ast.ArrayInit { - g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.ti.name), {\t') + // 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') for expr in it.exprs { g.expr(expr) g.write(', ') @@ -248,17 +267,18 @@ 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) mut tmp := '' - if it.ti.kind != .void { + if ti.kind != .void { tmp = g.table.new_tmp_var() - // g.writeln('$it.ti.name $tmp;') + // g.writeln('$ti.name $tmp;') } g.write('if (') g.expr(it.cond) g.writeln(') {') for i, stmt in it.stmts { // Assign ret value - if i == it.stmts.len - 1 && it.ti.kind != .void { + if i == it.stmts.len - 1 && ti.kind != .void { // g.writeln('$tmp =') println(1) } diff --git a/vlib/v/gen/cgen_test.v b/vlib/v/gen/cgen_test.v index 5ac52d34ee..ef781d753f 100644 --- a/vlib/v/gen/cgen_test.v +++ b/vlib/v/gen/cgen_test.v @@ -1,10 +1,7 @@ import ( os filepath - v.parser - v.ast - v.gen - v.table + v.builder term ) @@ -26,9 +23,8 @@ fn test_c_files() { ctext := os.read_file('$vroot/vlib/v/gen/tests/${i}.c') or { panic(err) } - table := &table.new_table() - program := parser.parse_file(path, table) - res := gen.cgen([program], table) + mut b := builder.new_builder() + res := b.gen_c([path]) if compare_texts(res, ctext) { eprintln('${term_ok} ${i}') } diff --git a/vlib/v/gen/jsgen.v b/vlib/v/gen/jsgen.v index 96dea1cbb6..ba3b790f93 100644 --- a/vlib/v/gen/jsgen.v +++ b/vlib/v/gen/jsgen.v @@ -3,16 +3,19 @@ module gen import ( strings v.ast + v.table term ) struct JsGen { out strings.Builder + table &table.Table } -pub fn jsgen(program ast.File) string { +pub fn jsgen(program ast.File, table &table.Table) string { mut g := JsGen{ out: strings.new_builder(100) + table: table } for stmt in program.stmts { g.stmt(stmt) @@ -34,9 +37,11 @@ pub fn (g mut JsGen) writeln(s string) { fn (g mut JsGen) stmt(node ast.Stmt) { match node { ast.FnDecl { - g.write('/** @return { $it.ti.name } **/\nfunction ${it.name}(') + ti := g.table.refresh_ti(it.ti) + g.write('/** @return { $ti.name } **/\nfunction ${it.name}(') for arg in it.args { - g.write(' /** @type { arg.ti.name } **/ $arg.name') + arg_ti := g.table.refresh_ti(arg.ti) + g.write(' /** @type { $arg_ti.name } **/ $arg.name') } g.writeln(') { ') for stmt in it.stmts { @@ -55,7 +60,8 @@ fn (g mut JsGen) stmt(node ast.Stmt) { g.writeln(';') } ast.VarDecl { - g.write('var /* $it.ti.name */ $it.name = ') + ti := g.table.refresh_ti(it.ti) + g.write('var /* $ti.name */ $it.name = ') g.expr(it.expr) g.writeln(';') } @@ -114,7 +120,8 @@ fn (g mut JsGen) expr(node ast.Expr) { } // `user := User{name: 'Bob'}` ast.StructInit { - g.writeln('/*$it.ti.name*/{') + ti := g.table.refresh_ti(it.ti) + g.writeln('/*$ti.name*/{') for i, field in it.fields { g.write('\t$field : ') g.expr(it.exprs[i]) diff --git a/vlib/v/gen/tests/1.c b/vlib/v/gen/tests/1.c index e28d4c91d1..16c2803c82 100644 --- a/vlib/v/gen/tests/1.c +++ b/vlib/v/gen/tests/1.c @@ -31,7 +31,7 @@ i < 10; i++; 1, 2, 3, }); int number = nums[0]; - void n = get_int2(); + int n = get_int2(); } int get_int(string a) { diff --git a/vlib/v/parser/a_type.v b/vlib/v/parser/a_type.v index d77ebef7da..40dfa92e8c 100644 --- a/vlib/v/parser/a_type.v +++ b/vlib/v/parser/a_type.v @@ -149,10 +149,11 @@ pub fn (p mut Parser) parse_ti() types.TypeIdent { else { // struct / enum mut idx := p.table.find_type_idx(name) - // add placeholder - if idx == 0 { - idx = p.table.add_placeholder_type(name) + if idx > 0 { + return types.new_ti(p.table.types[idx].kind, name, idx, nr_muls) } + // not found - add placeholder + idx = p.table.add_placeholder_type(name) return types.new_ti(.placeholder, name, idx, nr_muls) } } diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 5f899c471f..740b03c82e 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -13,50 +13,30 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,types.TypeIdent) { tok := p.tok fn_name := p.check_name() p.check(.lpar) - mut is_unknown := false - is_unknown = false mut args := []ast.Expr - mut return_ti := types.void_ti - if f := p.table.find_fn(fn_name) { - // println('found fn $fn_name') - return_ti = f.return_ti - for i, arg in f.args { - e,ti := p.expr(0) - if !types.check(&arg.ti, &ti) { - p.error('cannot use type `$ti.name` as type `$arg.ti.name` in argument to `$fn_name`') - } - args << e - if i < f.args.len - 1 { - p.check(.comma) - } - } - if p.tok.kind == .comma { - p.error('too many arguments in call to `$fn_name`') - } - }else{ - is_unknown = true - p.warn('unknown function `$fn_name`') - for p.tok.kind != .rpar { - e,_ := p.expr(0) - args << e - if p.tok.kind != .rpar { - p.check(.comma) - } + // mut return_ti := types.void_ti + for p.tok.kind != .rpar { + e,_ := p.expr(0) + args << e + if p.tok.kind != .rpar { + p.check(.comma) } } p.check(.rpar) node := ast.CallExpr{ name: fn_name args: args - is_unknown: is_unknown - tok: tok - // typ: return_ti + // tok: tok + pos: tok.position() } - if is_unknown { - p.table.unknown_calls << node + mut ti := types.unresolved_ti + if f := p.table.find_fn(fn_name) { + ti = f.return_ti } - return node,return_ti + println('adding call_expr check $fn_name') + + return node, ti } pub fn (p mut Parser) call_args() []ast.Expr { @@ -170,6 +150,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl { 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) @@ -179,4 +160,5 @@ pub fn (p &Parser) check_fn_calls() { // println(f.return_ti.name) // println('IN AST typ=' + call.typ.name) } + */ } diff --git a/vlib/v/parser/module.v b/vlib/v/parser/module.v new file mode 100644 index 0000000000..2ce4124e97 --- /dev/null +++ b/vlib/v/parser/module.v @@ -0,0 +1,4 @@ +// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module parser diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 494ec71af7..d6022e1a08 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -60,6 +60,22 @@ pub fn parse_file(path string, table &table.Table) ast.File { file_name: path } p.read_first_token() + + // module decl + module_decl := if p.tok.kind == .key_module { + p.module_decl() + } else { + ast.Module{ + name: 'main' + } + } + // imports + mut imports := []ast.Import + for p.tok.kind == .key_import { + imports << p.import_stmt() + } + // TODO: import only mode + for { // res := s.scan() if p.tok.kind == .eof { @@ -69,11 +85,12 @@ pub fn parse_file(path string, table &table.Table) ast.File { // println('stmt at ' + p.tok.str()) stmts << p.top_stmt() } - p.check_fn_calls() // println('nr stmts = $stmts.len') // println(stmts[0]) return ast.File{ - stmts: stmts + mod: module_decl + imports: imports + stmts: stmts } } @@ -136,14 +153,11 @@ fn (p mut Parser) check_name() string { pub fn (p mut Parser) top_stmt() ast.Stmt { match p.tok.kind { - .key_module { - return p.module_decl() - } - .key_import { - return p.import_stmt() - } .key_pub { match p.peek_tok.kind { + .key_const { + return p.const_decl() + } .key_fn { return p.fn_decl() } @@ -154,16 +168,16 @@ pub fn (p mut Parser) top_stmt() ast.Stmt { p.error('wrong pub keyword usage') return ast.Stmt{} } - } - // .key_const { - // return p.const_decl() - // } // .key_enum { // return p.enum_decl() // } // .key_type { // return p.type_decl() // } + } + } + .key_const { + return p.const_decl() } .key_fn { return p.fn_decl() @@ -213,11 +227,12 @@ pub fn (p mut Parser) stmt() ast.Stmt { pub fn (p mut Parser) assign_expr(left ast.Expr) ast.AssignExpr { op := p.tok.kind p.next() - val,_ := p.expr(0) + val, _ := p.expr(0) node := ast.AssignExpr{ left: left - op: op val: val + op: op + pos: p.tok.position() } return node } @@ -238,7 +253,7 @@ pub fn (p mut Parser) assign_stmt() ast.AssignStmt { // println('assignn_stmt() ' + op.str()) p.next() right_expr,right_type := p.expr(0) - if !types.check(left_type, right_type) { + if !p.table.check(left_type, right_type) { p.error('oops') } return ast.AssignStmt{ @@ -282,7 +297,8 @@ pub fn (p &Parser) warn(s string) { pub fn (p mut Parser) name_expr() (ast.Expr,types.TypeIdent) { mut node := ast.Expr{} - mut ti := types.void_ti + // mut ti := types.void_ti + mut ti := types.unresolved_ti if p.tok.lit == 'C' { p.next() p.check(.dot) @@ -293,7 +309,8 @@ pub fn (p mut Parser) name_expr() (ast.Expr,types.TypeIdent) { } // fn call if p.peek_tok.kind == .lpar { - x,ti2 := p.call_expr() // TODO `node,typ :=` should work + println('calling $p.tok.lit') + x, ti2 := p.call_expr() // TODO `node,typ :=` should work node = x ti = ti2 } @@ -308,22 +325,21 @@ pub fn (p mut Parser) name_expr() (ast.Expr,types.TypeIdent) { field_name := p.check_name() field_names << field_name p.check(.colon) - // expr,field_type := p.expr(0) expr,_ := p.expr(0) - // if !types.check( ,field_type exprs << expr } node = ast.StructInit{ ti: ti exprs: exprs fields: field_names + pos: p.tok.position() } p.check(.rcbr) } else { // p.warn('name ') // left := p.parse_ident() - node = ast.Ident{ + mut ident := ast.Ident{ name: p.tok.lit } var := p.table.find_var(p.tok.lit) or { @@ -331,6 +347,13 @@ pub fn (p mut Parser) name_expr() (ast.Expr,types.TypeIdent) { exit(0) } ti = var.ti + ident.kind = .variable + ident.info = ast.IdentVar { + ti: ti + expr: var.expr + } + // ident.ti = ti + node = ident p.next() } return node,ti @@ -438,59 +461,33 @@ fn (p mut Parser) index_expr(left ast.Expr) (ast.Expr,types.TypeIdent) { return node,ti } -fn (p mut Parser) dot_expr(left ast.Expr, ti types.TypeIdent) (ast.Expr,types.TypeIdent) { +fn (p mut Parser) dot_expr(left ast.Expr, left_ti &types.TypeIdent) (ast.Expr,types.TypeIdent) { p.next() field_name := p.check_name() - println('# $ti.name $ti.idx - $field_name') - if ti.kind != .void { - p.warn('#### void type in dot_expr - field: $field_name') - } - struc := p.table.types[ti.idx] as types.Struct + ti := types.unresolved_ti // Method call if p.tok.kind == .lpar { - if !p.table.struct_has_method(struc, field_name) { - p.error('type `$struc.name` has no method `$field_name`') - } p.next() args := p.call_args() - println('method call $field_name') - mut node := ast.Expr{} - node = ast.MethodCallExpr{ + mcall_expr := ast.MethodCallExpr{ expr: left name: field_name args: args + pos: p.tok.position() } - return node,types.int_ti + mut node := ast.Expr{} + node = mcall_expr + return node, ti } - if !p.table.struct_has_field(struc, field_name) { - // t := - p.error('type `$struc.name` has no field `$field_name`') - } - /* - // p.next() - field := p.check_name() - if !ti.type_kind in [.placeholder, .struct_] { - println('kind: $ti.str()') - p.error('cannot access field, `$ti.type_name` is not a struct') - } - typ := p.table.types[ti.type_idx] as types.Struct - mut ok := false - for f in typ.fields { - if f.name == field { - ok = true - } - } - if !ok { - p.error('unknown field `${typ.name}.$field`') - } - */ - mut node := ast.Expr{} - node = ast.SelectorExpr{ + sel_expr := ast.SelectorExpr{ expr: left field: field_name + pos: p.tok.position() } - return node,types.int_ti + mut node := ast.Expr{} + node = sel_expr + return node, ti } fn (p mut Parser) infix_expr(left ast.Expr) (ast.Expr,types.TypeIdent) { @@ -505,9 +502,10 @@ fn (p mut Parser) infix_expr(left ast.Expr) (ast.Expr,types.TypeIdent) { } mut expr := ast.Expr{} expr = ast.BinaryExpr{ - op: op left: left right: right + op: op + pos: p.tok.position() } return expr,ti } @@ -587,7 +585,7 @@ fn (p mut Parser) for_statement() ast.Stmt { } // `for cond {` cond,ti := p.expr(0) - if !types.check(types.bool_ti, ti) { + if !p.table.check(types.bool_ti, ti) { p.error('non-bool used as for condition') } stmts := p.parse_block() @@ -604,7 +602,7 @@ fn (p mut Parser) if_expr() (ast.Expr,types.TypeIdent) { mut node := ast.Expr{} p.check(.key_if) cond,cond_ti := p.expr(0) - // if !types.check(types.bool_ti, cond_ti) { + // if !p.table.check(types.bool_ti, cond_ti) { if cond_ti.kind != .bool { p.error('non-bool used as if condition') } @@ -670,7 +668,7 @@ fn (p mut Parser) array_init() (ast.Expr,types.TypeIdent) { if i == 0 { val_ti = ti } - else if !types.check(val_ti, ti) { + else if !p.table.check(val_ti, ti) { p.error('expected array element with type `$val_ti.name`') } exprs << expr @@ -714,25 +712,57 @@ fn (p mut Parser) parse_number_literal() (ast.Expr,types.TypeIdent) { fn (p mut Parser) module_decl() ast.Module { p.check(.key_module) - p.next() - return ast.Module{} + name := p.check_name() + return ast.Module{ + name: name + } } -fn (p mut Parser) import_stmt() ast.Import { - p.check(.key_import) - name := p.check_name() - mut alias := name +fn (p mut Parser) parse_import() ast.Import { + mod_name := p.check_name() + mut mod_alias := mod_name if p.tok.kind == .key_as { p.check(.key_as) - alias = p.check_name() + mod_alias = p.check_name() } - mut mods := map[string]string - mods[alias] = name return ast.Import{ - mods: mods + mod: mod_name + alias: mod_alias + pos: p.tok.position() } } +fn (p mut Parser) import_stmt() []ast.Import { + p.check(.key_import) + mut imports := []ast.Import + if p.tok.kind == .lpar { + p.check(.lpar) + for p.tok.kind != .rpar { + imports << p.parse_import() + } + p.check(.rpar) + } else { + imports << p.parse_import() + } + return imports +} + +// TODO +//fn (p mut Parser) const_decl() ast... { +fn (p mut Parser) const_decl() ast.Stmt { + p.check(.key_const) + p.check(.lpar) + for p.tok.kind != .rpar { + name := p.check_name() + println('const: $name') + p.check(.assign) + _, _ := p.expr(0) + // expr, ti := p.expr(0) + } + p.check(.rpar) + return ast.Stmt{} +} + fn (p mut Parser) struct_decl() ast.StructDecl { is_pub := p.tok.kind == .key_pub if is_pub { @@ -756,18 +786,23 @@ fn (p mut Parser) struct_decl() ast.StructDecl { } fields << types.Field{ name: field_name - type_idx: ti.idx + // type_idx: ti.idx + ti: ti } } p.check(.rcbr) - p.table.register_struct(types.Struct{ + p.table.register_type(table.Type{ + kind: .struct_ name: name - fields: fields + info: types.Struct{ + fields: fields + } }) return ast.StructDecl{ name: name is_pub: is_pub fields: ast_fields + pos: p.tok.position() } } @@ -776,11 +811,12 @@ fn (p mut Parser) return_stmt() ast.Return { // return expressions mut exprs := []ast.Expr // return type idents - mut got_tis := []types.TypeIdent + // mut got_tis := []types.TypeIdent for { - expr,ti := p.expr(0) + // expr,ti := p.expr(0) + expr, _ := p.expr(0) exprs << expr - got_tis << ti + // got_tis << ti if p.tok.kind == .comma { p.check(.comma) } @@ -788,23 +824,13 @@ fn (p mut Parser) return_stmt() ast.Return { break } } - mut expected_tis := [p.return_ti] - if p.return_ti.kind == .multi_return { - mr_type := p.table.types[p.return_ti.idx] as types.MultiReturn - expected_tis = mr_type.tis - } - if expected_tis.len != got_tis.len { - p.error('wrong number of return arguments:\n\texpected: $expected_tis.str()\n\tgot: $got_tis.str()') - } - for i, exp_ti in expected_tis { - got_ti := got_tis[i] - if !types.check(got_ti, exp_ti) { - p.error('cannot use `$got_ti.name` as type `$exp_ti.name` in return argument') - } - } - return ast.Return{ + // TODO: consider non deferred + stmt := ast.Return{ + expected_ti: p.return_ti exprs: exprs + pos: p.tok.position() } + return stmt } fn (p mut Parser) var_decl() ast.VarDecl { @@ -820,25 +846,29 @@ fn (p mut Parser) var_decl() ast.VarDecl { } name := p.tok.lit p.read_first_token() - expr,ti := p.expr(token.lowest_prec) + expr, ti := p.expr(token.lowest_prec) if _ := p.table.find_var(name) { p.error('redefinition of `$name`') } p.table.register_var(table.Var{ name: name - ti: ti is_mut: is_mut + expr: expr + ti: ti }) // println(p.table.names) - // println('added var `$name` with type $t.name') - return ast.VarDecl{ + node := ast.VarDecl{ name: name expr: expr // p.expr(token.lowest_prec) - + is_mut: is_mut ti: ti + pos: p.tok.position() } + return node } + + 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 2a016ce975..8252a4ad2d 100644 --- a/vlib/v/parser/parser_test.v +++ b/vlib/v/parser/parser_test.v @@ -4,6 +4,7 @@ import ( v.ast v.gen v.table + v.checker term ) @@ -37,7 +38,7 @@ fn test_one() { // ] expected := 'int a = 10;int b = -a;int c = 20;' - table := &table.Table{} + table := table.new_table() mut e := []ast.Stmt for line in input { e << parse_stmt(line, table) @@ -118,7 +119,8 @@ fn test_parse_expr() { '-a;', ] mut e := []ast.Stmt - table := &table.Table{} + table := table.new_table() + mut checker := checker.new_checker(table) for s in input { // println('\n\nst="$s"') e << parse_stmt(s, table) @@ -126,6 +128,7 @@ fn test_parse_expr() { program := ast.File{ stmts: e } + checker.check(program) res := gen.cgen([program], table) println('========') println(res) diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index e5e7ff8c20..c9a44e5b2c 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -1,30 +1,21 @@ module table import ( - v.types v.ast + v.types ) pub struct Table { // struct_fields map[string][]string pub mut: - types []types.Type + types []Type // type_idxs Hashmap type_idxs map[string]int local_vars []Var // fns Hashmap fns map[string]Fn - methods [][]Fn - // - unknown_calls []ast.CallExpr tmp_cnt int -} - -pub struct Var { -pub: - name string - ti types.TypeIdent - is_mut bool + imports []string } pub struct Fn { @@ -34,6 +25,29 @@ pub: return_ti types.TypeIdent } +pub struct Var { +pub: + name string + is_mut bool + expr ast.Expr +mut: + ti types.TypeIdent +} + +pub struct Type { +pub: + parent_idx int +mut: + info types.TypeInfo + kind types.Kind + name string + methods []Fn +} + +pub fn (t Type) str() string { + return t.name +} + pub fn new_table() &Table { mut t := &Table{} t.register_builtin_types() @@ -41,55 +55,56 @@ pub fn new_table() &Table { } pub fn (t mut Table) register_builtin_types() { - // add dummy type at 0 so nothing can go there + // reserve index 0 so nothing can go there // save index check, 0 will mean not found - t.register_type(types.Type{}, 'dymmy_type_at_idx_0', 0) - t.register_type(types.Primitive{ - idx: types.void_type_idx - kind: .void - }, 'void', types.void_type_idx) - t.register_type(types.Primitive{ - idx: types.voidptr_type_idx - kind: .voidptr - }, 'voidptr', types.voidptr_type_idx) - t.register_type(types.Primitive{ - idx: types.charptr_type_idx - kind: .charptr - }, 'charptr', types.charptr_type_idx) - t.register_type(types.Primitive{ - idx: types.byteptr_type_idx - kind: .byteptr - }, 'byteptr', types.byteptr_type_idx) - t.register_type(types.Int{ - types.i8_type_idx,8,false}, 'i8', types.i8_type_idx) - t.register_type(types.Int{ - types.i16_type_idx,16,false}, 'i16', types.i16_type_idx) - t.register_type(types.Int{ - types.i64_type_idx,32,false}, 'int', types.int_type_idx) - t.register_type(types.Int{ - types.i64_type_idx,64,false}, 'i64', types.i64_type_idx) - t.register_type(types.Int{ - types.u16_type_idx,16,true}, 'u16', types.u16_type_idx) - t.register_type(types.Int{ - types.u32_type_idx,32,true}, 'u32', types.u32_type_idx) - t.register_type(types.Int{ - types.u64_type_idx,64,true}, 'u64', types.u64_type_idx) - t.register_type(types.Float{ - types.f64_type_idx,32}, 'f32', types.f32_type_idx) - t.register_type(types.Float{ - types.f64_type_idx,64}, 'f64', types.f64_type_idx) - t.register_type(types.String{ - types.string_type_idx}, 'string', types.string_type_idx) - t.register_type(types.Primitive{ - idx: types.char_type_idx - kind: .char - }, 'char', types.char_type_idx) - t.register_type(types.Primitive{ - idx: types.byte_type_idx - kind: .byte - }, 'byte', types.byte_type_idx) - t.register_type(types.Bool{ - types.bool_type_idx}, 'bool', types.bool_type_idx) + t.register_type(Type{kind: .placeholder, name: 'reserved_0'}) + t.register_type(Type{kind: .void, name: 'void'}) + t.register_type(Type{kind: .voidptr, name: 'voidptr'}) + t.register_type(Type{kind: .charptr, name: 'charptr'}) + t.register_type(Type{kind: .byteptr, name: 'byteptr'}) + t.register_type(Type{kind: .i8, name: 'i8'}) + t.register_type(Type{kind: .i16, name: 'i16'}) + t.register_type(Type{kind: .int, name: 'int'}) + t.register_type(Type{kind: .i64, name: 'i64'}) + t.register_type(Type{kind: .u16, name: 'u16'}) + t.register_type(Type{kind: .u32, name: 'u32'}) + t.register_type(Type{kind: .u64, name: 'u64'}) + t.register_type(Type{kind: .f32, name: 'f32'}) + t.register_type(Type{kind: .f64, name: 'f64'}) + t.register_type(Type{kind: .string, name: 'string'}) + t.register_type(Type{kind: .char, name: 'char'}) + t.register_type(Type{kind: .byte, name: 'byte'}) + t.register_type(Type{kind: .bool, name: 'bool'}) +} + +pub fn (t &Table) refresh_ti(ti types.TypeIdent) types.TypeIdent { + 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 { + if idx == 0 { + panic('get_type: idx 0') + } + return t.types[idx] +} + +pub fn (t &Table) find_var_idx(name string) int { + for i,var in t.local_vars { + if var.name == name { + return i + } + } + return -1 } pub fn (t &Table) find_var(name string) ?Var { @@ -122,6 +137,7 @@ pub fn (t mut Table) clear_vars() { } pub fn (t mut Table) register_var(v Var) { + println('register_var: $v.name - $v.ti.name') t.local_vars << v /* mut new_var := { @@ -159,68 +175,66 @@ pub fn (t mut Table) register_fn(new_fn Fn) { t.fns[new_fn.name] = new_fn } -pub fn (t mut Table) register_method(ti types.TypeIdent, new_fn Fn) bool { - println('register method `$new_fn.name` tiname=$ti.name ') - /* - match t.types[ti.idx] { - types.Struct { - println('got struct') - } - else { - return false - } - } - mut struc := t.types[ti.idx] as types.Struct - if struc.methods.len == 0 { - struc.methods = make(0, 0, sizeof(types.Field)) - } - println('register method `$new_fn.name` struct=$struc.name ') - struc.methods << types.Field{ - name: new_fn.name - } - t.types[ti.idx] = struc - */ - - println('register method `$new_fn.name` struct=$ti.name ') - println('##### $ti.idx - $t.methods.len') - t.methods[ti.idx] << new_fn +pub fn (t mut Table) register_method(ti &types.TypeIdent, new_fn Fn) bool { + idx := ti.idx + println('register method `$new_fn.name` type=$ti.name idx=$ti.idx') + mut methods := t.types[idx].methods + methods << new_fn + t.types[idx].methods = methods return true } +pub fn (t &Table) has_method(type_idx int, name string) bool { + t.find_method(type_idx, 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 { + if method.name == name { + return method + } + } + return none +} + pub fn (t mut Table) new_tmp_var() string { t.tmp_cnt++ return 'tmp$t.tmp_cnt' } -pub fn (t &Table) struct_has_field(s &types.Struct, name string) bool { - println('struct_has_field($s.name, $name) s.idx=$s.idx types.len=$t.types.len s.parent_idx=$s.parent_idx') +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') // for typ in t.types { // println('$typ.idx $typ.name') // } - for field in s.fields { - if field.name == name { - return true - } - } - if s.parent_idx != 0 { - parent := t.types[s.parent_idx] as types.Struct - println('got parent $parent.name') - for field in parent.fields { - if field.name == name { - return true - } - } + if _ := t.struct_find_field(s, name) { + return true } return false } -pub fn (t &Table) struct_has_method(s &types.Struct, name string) bool { - for field in t.methods[s.idx] { +pub fn (t &Table) struct_find_field(s &Type, name string) ?types.Field { + println('struct_find_field($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx') + info := s.info as types.Struct + for field in info.fields { if field.name == name { - return true + return field } } - return false + if s.parent_idx != 0 { + parent := t.types[s.parent_idx] + parent_info := s.info as types.Struct + println('got parent $parent.name') + for field in parent_info.fields { + if field.name == name { + return field + } + } + } + return none } [inline] @@ -229,7 +243,7 @@ pub fn (t &Table) find_type_idx(name string) int { } [inline] -pub fn (t &Table) find_type(name string) ?types.Type { +pub fn (t &Table) find_type(name string) ?Type { idx := t.type_idxs[name] if idx > 0 { return t.types[idx] @@ -238,52 +252,30 @@ pub fn (t &Table) find_type(name string) ?types.Type { } [inline] -pub fn (t mut Table) register_type(typ types.Type, name string, idx int) { - // sanity check - if idx != t.types.len { - panic('error registering type $name, type.idx must = table.types.len (got `$idx` expected `$t.types.len`') - } - t.type_idxs[name] = idx - t.types << typ - e := []Fn - t.methods << e // TODO [] breaks V -} - -pub fn (t mut Table) register_struct(typ types.Struct) int { - println('register_struct($typ.name)') - // existing +pub fn (t mut Table) register_type(typ Type) int { existing_idx := t.type_idxs[typ.name] if existing_idx > 0 { ex_type := t.types[existing_idx] - match ex_type { - types.Placeholder { + match ex_type.kind { + .placeholder { // override placeholder - println('overriding type placeholder `$it.name` with struct') - mut struct_type := types.Type{} - struct_type = { - typ | - idx:existing_idx + println('overriding type placeholder `$typ.name`') + t.types[existing_idx] = {typ| + methods: ex_type.methods } - t.types[existing_idx] = struct_type - return existing_idx - } - types.Struct { return existing_idx } else { + if ex_type.kind == typ.kind { + return existing_idx + } panic('cannot register type `$typ.name`, another type with this name exists') } + } } - } - // register - println('registering: $typ.name') idx := t.types.len - struct_type := { - typ | - idx:idx, - parent_idx:0, - } - t.register_type(struct_type, typ.name, idx) + t.types << typ + t.type_idxs[typ.name] = idx return idx } @@ -295,13 +287,15 @@ pub fn (t mut Table) find_or_register_map(key_ti &types.TypeIdent, value_ti &typ return existing_idx,name } // register - idx := t.types.len - map_type := types.Map{ + map_type := Type{ + kind: .map name: name - key_type_idx: key_ti.idx - value_type_idx: value_ti.idx + info: types.Map{ + key_type_idx: key_ti.idx + value_type_idx: value_ti.idx + } } - t.register_type(map_type, name, idx) + idx := t.register_type(map_type) return idx,name } @@ -314,16 +308,17 @@ pub fn (t mut Table) find_or_register_array(elem_ti &types.TypeIdent, nr_dims in } // register parent_idx := t.type_idxs['array'] - idx := t.types.len - array_type := types.Array{ - idx: idx + array_type := Type{ parent_idx: parent_idx + kind: .array name: name - elem_type_idx: elem_ti.idx - elem_is_ptr: elem_ti.is_ptr() - nr_dims: nr_dims + info: types.Array{ + elem_type_idx: elem_ti.idx + elem_is_ptr: elem_ti.is_ptr() + nr_dims: nr_dims + } } - t.register_type(array_type, name, idx) + idx := t.register_type(array_type) return idx,name } @@ -335,16 +330,17 @@ pub fn (t mut Table) find_or_register_array_fixed(elem_ti &types.TypeIdent, size return existing_idx,name } // register - idx := t.types.len - array_fixed_type := types.ArrayFixed{ - idx: idx + array_fixed_type := Type{ + kind: .array_fixed name: name - elem_type_idx: elem_ti.idx - elem_is_ptr: elem_ti.is_ptr() - size: size - nr_dims: nr_dims + info: types.ArrayFixed{ + elem_type_idx: elem_ti.idx + elem_is_ptr: elem_ti.is_ptr() + size: size + nr_dims: nr_dims + } } - t.register_type(array_fixed_type, name, idx) + idx := t.register_type(array_fixed_type) return idx,name } @@ -359,13 +355,14 @@ pub fn (t mut Table) find_or_register_multi_return(mr_tis []types.TypeIdent) (in return existing_idx,name } // register - idx := t.types.len - mr_type := types.MultiReturn{ - idx: idx + mr_type := Type{ + kind: .multi_return name: name - tis: mr_tis + info: types.MultiReturn{ + tis: mr_tis + } } - t.register_type(mr_type, name, idx) + idx := t.register_type(mr_type) return idx,name } @@ -377,22 +374,121 @@ pub fn (t mut Table) find_or_register_variadic(variadic_ti &types.TypeIdent) (in return existing_idx,name } // register - idx := t.types.len - variadic_type := types.Variadic{ - idx: idx - ti: variadic_ti + variadic_type := Type{ + kind: .variadic + name: name + info: types.Variadic{ + ti: variadic_ti + } } - t.register_type(variadic_type, name, idx) + idx := t.register_type(variadic_type) return idx,name } pub fn (t mut Table) add_placeholder_type(name string) int { - idx := t.types.len - ph_type := types.Placeholder{ - idx: idx + ph_type := Type{ + kind: .placeholder name: name } - println('added placeholder: $name - $idx ') - t.register_type(ph_type, name, idx) + idx := t.register_type(ph_type) + println('added placeholder: $name - $idx') return idx } + +// [inline] +// pub fn (t &Table) update_ti(ti &types.TypeIdent) types.TypeIdent { +// if ti.kind == .unresolved { + +// } +// } + +pub fn (t &Table) check(got, expected &types.TypeIdent) bool { + println('check: $got.name, $expected.name') + if expected.kind == .voidptr { + return true + } + //if expected.name == 'array' { + // return true + //} + if got.idx != expected.idx { + return false + } + return true +} + +[inline] +pub fn (t &Table) get_expr_ti(expr ast.Expr) types.TypeIdent { + match expr { + ast.ArrayInit{ + return it.ti + } + ast.IndexExpr{ + return t.get_expr_ti(it.left) + } + ast.CallExpr { + func := t.find_fn(it.name) or { + return types.void_ti + } + return func.return_ti + } + ast.MethodCallExpr { + ti := t.get_expr_ti(it.expr) + func := t.find_method(ti.idx, it.name) or { + return types.void_ti + } + return func.return_ti + } + ast.Ident { + if it.kind == .variable { + info := it.info as ast.IdentVar + if info.ti.kind != .unresolved { + return info.ti + } + return t.get_expr_ti(info.expr) + } + return types.void_ti + } + ast.StructInit { + return it.ti + } + ast.StringLiteral { + return types.string_ti + } + ast.IntegerLiteral { + return types.int_ti + } + ast.SelectorExpr { + ti := t.get_expr_ti(it.expr) + kind := t.types[ti.idx].kind + if ti.kind == .placeholder { + println(' ##### PH $ti.name') + } + if !(kind in [.placeholder, .struct_]) { + return types.void_ti + } + struct_ := t.types[ti.idx] + struct_info := struct_.info as types.Struct + for field in struct_info.fields { + if field.name == it.field { + return field.ti + } + } + if struct_.parent_idx != 0 { + parent := t.types[struct_.parent_idx] + parent_info := parent.info as types.Struct + for field in parent_info.fields { + if field.name == it.field { + return field.ti + } + } + } + return types.void_ti + } + ast.BinaryExpr { + return t.get_expr_ti(it.left) + } + else { + return types.void_ti + } + } +} diff --git a/vlib/v/token/position.v b/vlib/v/token/position.v new file mode 100644 index 0000000000..39e8abb4c2 --- /dev/null +++ b/vlib/v/token/position.v @@ -0,0 +1,18 @@ +// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module token + +pub struct Position { +pub: + line_nr int // the line number in the source where the token occured + // pos int // the position of the token in scanner text +} + +[inline] +pub fn (tok &Token) position() Position { + return Position{ + line_nr: tok.line_nr + // pos: tok.pos + } +} diff --git a/vlib/v/types/types.v b/vlib/v/types/types.v index 894acaf79c..57a186f5aa 100644 --- a/vlib/v/types/types.v +++ b/vlib/v/types/types.v @@ -29,14 +29,10 @@ pub enum Kind { voidptr charptr byteptr - const_ - enum_ - struct_ - int i8 i16 + int i64 - byte u16 u32 u64 @@ -44,20 +40,25 @@ pub enum Kind { f64 string char + byte bool + const_ + enum_ + struct_ array array_fixed map multi_return variadic + unresolved } -pub type Type = Placeholder | Primitive | Const | Enum | Struct | Int | Float | -String | Bool | Array | ArrayFixed | Map | MultiReturn | Variadic +pub type TypeInfo = Array | ArrayFixed | Map | Struct | MultiReturn | Variadic pub struct TypeIdent { pub: idx int +mut: kind Kind name string nr_muls int @@ -73,17 +74,18 @@ pub fn new_ti(kind Kind, name string, idx int, nr_muls int) TypeIdent { } } -[inline] -pub fn new_builtin_ti(kind Kind, nr_muls int) TypeIdent { - return TypeIdent{ - idx: -int(kind) - 1 - kind: kind - name: kind.str() - nr_muls: nr_muls - } -} +// [inline] +// pub fn new_builtin_ti(kind Kind, nr_muls int) TypeIdent { +// return TypeIdent{ +// idx: -int(kind) - 1 +// kind: kind +// name: kind.str() +// nr_muls: nr_muls +// } +// } pub const ( + unresolved_ti = new_ti(.unresolved, 'unresolved', 0, 0) void_ti = new_ti(.void, 'void', void_type_idx, 0) int_ti = new_ti(.int, 'int', int_type_idx, 0) string_ti = new_ti(.string, 'string', string_type_idx, 0) @@ -115,24 +117,15 @@ pub fn (ti &TypeIdent) str() string { for _ in 0 .. ti.nr_muls { muls += '&' } - return '$muls$ti.name' -} - -pub fn check(got, expected &TypeIdent) bool { - if expected.kind == .voidptr { - return true - } - if expected.name == 'array' { - return true - } - if got.idx != expected.idx { - return false - } - return true + // return '$muls$ti.name' + return '$muls$ti.idx' } pub fn (k Kind) str() string { k_str := match k { + .unresolved{ + 'unresolved' + } .placeholder{ 'placeholder' } @@ -148,12 +141,12 @@ pub fn (k Kind) str() string { .byteptr{ 'byteptr' } - .const_{ - 'const' - } - .enum_{ - 'enum' - } + // .const_{ + // 'const' + // } + // .enum_{ + // 'enum' + // } .struct_{ 'struct' } @@ -222,75 +215,42 @@ pub fn (kinds []Kind) str() string { return kinds_str } -pub struct Placeholder { -pub: - idx int - name string - // kind Kind -} -// Void | Voidptr | Charptr | Byteptr -pub struct Primitive { -pub: - idx int - kind Kind -} +// pub struct Const { +// pub: +// name string +// } -pub struct Const { -pub: - idx int - name string -} - -pub struct Enum { -pub: - idx int - name string -} +// pub struct Enum { +// pub: +// name string +// } pub struct Struct { -pub: - idx int - parent_idx int - name string pub mut: fields []Field - methods []Field // TODO Method } pub struct Field { pub: name string - type_idx int + ti TypeIdent + // type_idx int } -pub struct Int { -pub: - idx int - bit_size u32 - is_unsigned bool -} +// pub struct Int { +// pub: +// bit_size u32 +// is_unsigned bool +// } -pub struct Float { -pub: - idx int - bit_size u32 -} +// pub struct Float { +// pub: +// bit_size u32 +// } -pub struct String { -pub: - idx int -} - -pub struct Bool { -pub: - idx int -} pub struct Array { pub: - idx int - parent_idx int - name string elem_type_kind Kind elem_type_idx int elem_is_ptr bool @@ -299,9 +259,6 @@ pub: pub struct ArrayFixed { pub: - idx int - parent_idx int - name string elem_type_kind Kind elem_type_idx int elem_is_ptr bool @@ -311,8 +268,6 @@ pub: pub struct Map { pub: - idx int - name string key_type_kind Kind key_type_idx int value_type_kind Kind @@ -321,89 +276,11 @@ pub: pub struct MultiReturn { pub: - idx int name string tis []TypeIdent } pub struct Variadic { pub: - idx int ti TypeIdent } - -pub fn (t Primitive) str() string { - s := match t.kind { - .void{ - 'void' - } - .voidptr{ - 'voidptr' - } - .charptr{ - 'charptr' - } - .byteptr{ - 'byteptr' - } - .char{ - 'char' - } - .byte{ - 'byte' - } - else { - 'unknown'} - } - return s -} - -pub fn (t Const) str() string { - return t.name -} - -pub fn (t Enum) str() string { - return t.name -} - -pub fn (t Struct) str() string { - return t.name -} - -pub fn (t Int) str() string { - return if t.is_unsigned { 'u$t.bit_size' } else { 'i$t.bit_size' } -} - -pub fn (t Float) str() string { - return 'f$t.bit_size' -} - -pub fn (t String) str() string { - return 'string' -} - -pub fn (t Array) str() string { - return t.name -} - -pub fn (t ArrayFixed) str() string { - return t.name -} - -pub fn (t Map) str() string { - return t.name -} - -pub fn (t MultiReturn) str() string { - return t.name -} - -pub fn (t Variadic) str() string { - return 'variadic_$t.ti.kind.str()' -} - -/* -pub fn (s &Struct) has_field(name string) bool { - -} -*/