From de55a26cfed08f31f994797bd368260c670eb276 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Tue, 10 Mar 2020 23:21:26 +0100 Subject: [PATCH] cgen: lots of fixes --- vlib/builtin/array.v | 6 +- vlib/builtin/int.v | 2 +- vlib/strings/builder_c.v | 5 ++ vlib/v/ast/ast.v | 43 +++++----- vlib/v/checker/checker.v | 11 ++- vlib/v/gen/cgen.v | 172 +++++++++++++++++++++++++++++---------- vlib/v/gen/cgen_test.v | 19 +++-- vlib/v/gen/cheaders.v | 1 + vlib/v/gen/tests/1.c | 4 +- vlib/v/gen/tests/1.vv | 2 + vlib/v/parser/fn.v | 15 +++- vlib/v/parser/parser.v | 28 ++++--- 12 files changed, 214 insertions(+), 94 deletions(-) diff --git a/vlib/builtin/array.v b/vlib/builtin/array.v index b5cb6b1db0..6b5181c5b8 100644 --- a/vlib/builtin/array.v +++ b/vlib/builtin/array.v @@ -255,7 +255,7 @@ fn (a array) slice2(start, _end int, end_max bool) array { } // array.clone returns an independent copy of a given array -pub fn (a array) clone() array { +pub fn (a &array) clone() array { mut size := a.cap * a.element_size if size == 0 { size++ @@ -270,7 +270,7 @@ pub fn (a array) clone() array { return arr } -fn (a array) slice_clone(start, _end int) array { +fn (a &array) slice_clone(start, _end int) array { mut end := _end $if !no_bounds_checking? { if start > end { @@ -316,8 +316,6 @@ pub fn (a3 mut array) push_many(val voidptr, size int) { // handle `arr << arr` copy := a3.clone() a3.ensure_cap(a3.len + size) - C.printf("%d", a3.len*2) - println(a3.len*2) //C.memcpy(a.data, copy.data, copy.element_size * copy.len) C.memcpy(a3.data + a3.element_size * a3.len, copy.data, a3.element_size * size) } else { diff --git a/vlib/builtin/int.v b/vlib/builtin/int.v index 064243dac8..a7a7886e9a 100644 --- a/vlib/builtin/int.v +++ b/vlib/builtin/int.v @@ -190,7 +190,7 @@ pub fn (c rune) str() string { for i in 0..len { str.str[i] = int(c)>>8 * (3 - i) & 0xff } - str[len] = `\0` + str.str[len] = `\0` return str } diff --git a/vlib/strings/builder_c.v b/vlib/strings/builder_c.v index 3edbd546f0..2b75de1582 100644 --- a/vlib/strings/builder_c.v +++ b/vlib/strings/builder_c.v @@ -40,6 +40,11 @@ pub fn (b mut Builder) write(s string) { b.len += s.len } +pub fn (b mut Builder) go_back(n int) { + b.buf.trim(b.buf.len-n) + //b.len -= n + } + pub fn (b mut Builder) writeln(s string) { // for c in s { // b.buf << c diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 61b8d83a0f..575fc9c604 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -10,15 +10,15 @@ import ( pub type TypeDecl = AliasTypeDecl | SumTypeDecl -pub type Expr = InfixExpr | IfExpr | StringLiteral | IntegerLiteral | CharLiteral | -FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr | PostfixExpr | -AssignExpr | PrefixExpr | MethodCallExpr | IndexExpr | RangeExpr | MatchExpr | -CastExpr | EnumVal | Assoc | SizeOf | None | MapInit | IfGuardExpr | ParExpr | OrExpr | +pub type Expr = InfixExpr | IfExpr | StringLiteral | IntegerLiteral | CharLiteral | +FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr | PostfixExpr | +AssignExpr | PrefixExpr | MethodCallExpr | IndexExpr | RangeExpr | MatchExpr | +CastExpr | EnumVal | Assoc | SizeOf | None | MapInit | IfGuardExpr | ParExpr | OrExpr | ConcatExpr | Type | AsCast -pub type Stmt = GlobalDecl | FnDecl | Return | Module | Import | ExprStmt | -ForStmt | StructDecl | ForCStmt | ForInStmt | CompIf | ConstDecl | Attr | BranchStmt | -HashStmt | AssignStmt | EnumDecl | TypeDecl | DeferStmt | GotoLabel | GotoStmt | +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 // pub type Type = StructType | ArrayType // pub struct StructType { @@ -156,28 +156,31 @@ pub: pub struct CallExpr { pub: // tok token.Token - pos token.Position + pos token.Position mut: // func Expr - name string - args []Expr - is_c bool - muts []bool - or_block OrExpr + name string + args []Expr + arg_types []table.Type + is_c bool + muts []bool + or_block OrExpr typ table.Type } pub struct MethodCallExpr { pub: // tok token.Token - pos token.Position - expr Expr - name string - args []Expr - muts []bool - or_block OrExpr + pos token.Position + expr Expr // `user` in `user.register()` + name string + args []Expr + muts []bool + or_block OrExpr mut: - typ table.Type + expr_type table.Type // type of `user` + receiver_type table.Type // User + typ table.Type } pub struct Return { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 36a3e31231..413e073c4e 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -22,6 +22,7 @@ mut: errors []string expected_type table.Type fn_return_type table.Type // current function's return type + // is_amp bool } pub fn new_checker(table &table.Table) Checker { @@ -250,7 +251,7 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type { // TODO: clean this up, remove dupe code & consider merging method/fn call everywhere pub fn (c mut Checker) method_call_expr(method_call_expr mut ast.MethodCallExpr) table.Type { typ := c.expr(method_call_expr.expr) - method_call_expr.typ = typ + method_call_expr.expr_type = typ typ_sym := c.table.get_type_symbol(typ) name := method_call_expr.name if typ_sym.kind == .array && name in ['filter', 'clone'] { @@ -281,6 +282,10 @@ pub fn (c mut Checker) method_call_expr(method_call_expr mut ast.MethodCallExpr) return typ } if method := typ_sym.find_method(name) { + if name == 'clone' { + println('CLONE nr args=$method.args.len') + } + method_call_expr.receiver_type = method.args[0].typ for i, arg_expr in method_call_expr.args { c.expected_type = method.args[i].typ c.expr(arg_expr) @@ -382,7 +387,7 @@ pub fn (c mut Checker) assign_stmt(assign_stmt mut ast.AssignStmt) { mut scope := c.file.scope.innermost(assign_stmt.pos.pos) for i, _ in assign_stmt.left { mut ident := assign_stmt.left[i] - val_type := mr_info.types[i] + val_type := mr_info.types[i] mut var_info := ident.var_info() var_info.typ = val_type ident.info = var_info @@ -403,7 +408,7 @@ pub fn (c mut Checker) assign_stmt(assign_stmt mut ast.AssignStmt) { } // `a := 1` | `a,b := 1,2` else { - if assign_stmt.left.len != assign_stmt.right.len { + if assign_stmt.left.len != assign_stmt.right.len { c.error('wrong number of vars', assign_stmt.pos) } mut scope := c.file.scope.innermost(assign_stmt.pos.pos) diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 2c8e8b61c8..16169825bc 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -19,6 +19,7 @@ mut: is_c_call bool // e.g. `C.printf("v")` is_assign_expr bool is_array_set bool + is_amp bool // for `&Foo{}` to merge PrefixExpr `&` and StructInit `Foo{}`; also for `&byte(0)` etc } pub fn cgen(files []ast.File, table &table.Table) string { @@ -42,6 +43,7 @@ pub fn (g mut Gen) init() { g.definitions.writeln('#include ') // int64_t etc g.definitions.writeln(c_builtin_types) g.definitions.writeln(c_headers) + g.write_builtin_types() g.write_array_types() g.write_sorted_types() g.write_multi_return_types() @@ -211,7 +213,12 @@ fn (g mut Gen) stmt(node ast.Stmt) { } ast.ForStmt { g.write('while (') - g.expr(it.cond) + if it.is_inf { + g.write('1') + } + else { + g.expr(it.cond) + } g.writeln(') {') for stmt in it.stmts { g.stmt(stmt) @@ -288,20 +295,20 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { else { panic('expected call') } - } - mr_typ_sym := g.table.get_type_symbol(return_type) + } mr_var_name := 'mr_$assign_stmt.pos.pos' - g.write('$mr_typ_sym.name $mr_var_name = ') + mr_typ_str := g.typ(return_type) + g.write('$mr_typ_str $mr_var_name = ') g.expr(assign_stmt.right[0]) g.writeln(';') for i, ident in assign_stmt.left { ident_var_info := ident.var_info() - var_type_sym := g.table.get_type_symbol(ident_var_info.typ) + styp := g.typ(ident_var_info.typ) if ident.kind == .blank_ident { - g.writeln('{$var_type_sym.name _ = $mr_var_name->arg[$i]};') + g.writeln('{ $styp _ = ${mr_var_name}.arg$i};') } else { - g.writeln('$var_type_sym.name $ident.name = $mr_var_name->arg[$i];') + g.writeln('$styp $ident.name = ${mr_var_name}.arg$i;') } } } @@ -310,24 +317,29 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { for i, ident in assign_stmt.left { val := assign_stmt.right[i] ident_var_info := ident.var_info() - var_type_sym := g.table.get_type_symbol(ident_var_info.typ) + styp := g.typ(ident_var_info.typ) if ident.kind == .blank_ident { is_call := match val { - ast.CallExpr { true } - ast.MethodCallExpr { true } - else { false } - } + ast.CallExpr{ + true + } + ast.MethodCallExpr{ + true + } + else { + false} + } if is_call { - g.expr(val) + g.expr(val) } else { - g.write('{$var_type_sym.name _ = ') + g.write('{$styp _ = ') g.expr(val) - g.write('}') + g.write('}') } } else { - g.write('$var_type_sym.name $ident.name = ') + g.write('$styp $ident.name = ') g.expr(val) } g.writeln(';') @@ -359,13 +371,14 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) { g.definitions.write('$type_name ${name}(') } // Receiver is the first argument + /* if it.is_method { mut styp := g.typ(it.receiver.typ) // if table.type_nr_muls(it.receiver.typ) > 0 { // if it.rec_mut { // styp += '*' // } - g.write('$styp $it.receiver.name') + g.write('$styp $it.receiver.name ') // TODO mut g.definitions.write('$styp $it.receiver.name') if it.args.len > 0 { @@ -373,6 +386,7 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) { g.definitions.write(', ') } } + */ // no_names := it.args.len > 0 && it.args[0].name == 'arg_1' for i, arg in it.args { @@ -459,13 +473,24 @@ fn (g mut Gen) expr(node ast.Expr) { name = name[3..] } g.write('${name}(') - g.call_args(it.args) + g.call_args(it.args, it.muts) g.write(')') g.is_c_call = false } ast.CastExpr { + // g.write('/*cast*/') + if g.is_amp { + // &Foo(0) => ((Foo*)0) + g.out.go_back(1) + } if it.typ == table.string_type_idx { - g.write('tos(') + // tos(str, len), tos2(str) + if it.has_arg { + g.write('tos(') + } + else { + g.write('tos2(') + } g.expr(it.expr) if it.has_arg { g.write(',') @@ -474,10 +499,16 @@ fn (g mut Gen) expr(node ast.Expr) { g.write(')') } else { - styp := g.table.type_to_str(it.typ) - g.write('($styp)(') + // styp := g.table.type_to_str(it.typ) + styp := g.typ(it.typ) + // g.write('($styp)(') + g.write('(($styp)(') + // if g.is_amp { + // g.write('*') + // } + // g.write(')(') g.expr(it.expr) - g.write(')') + g.write('))') } } ast.CharLiteral { @@ -491,7 +522,12 @@ fn (g mut Gen) expr(node ast.Expr) { } ast.Ident { name := it.name.replace('.', '__') - g.write(name) + if name.starts_with('C__') { + g.write(name[3..]) + } + else { + g.write(name) + } } ast.IfExpr { // If expression? Assign the value to a temp var. @@ -544,9 +580,11 @@ fn (g mut Gen) expr(node ast.Expr) { g.write('/* guard */') } ast.IndexExpr { + // g.index_expr(it) } ast.InfixExpr { + // sdf g.infix_expr(it) } ast.IntegerLiteral { @@ -614,20 +652,30 @@ fn (g mut Gen) expr(node ast.Expr) { ast.MethodCallExpr { mut receiver_name := 'TODO' // TODO: there are still due to unchecked exprs (opt/some fn arg) - if it.typ != 0 { - typ_sym := g.table.get_type_symbol(it.typ) + if it.expr_type != 0 { + typ_sym := g.table.get_type_symbol(it.expr_type) receiver_name = typ_sym.name - // if typ_sym.kind == .array { - // receiver_name = 'array' - // } + if typ_sym.kind == .array && receiver_name.starts_with('array_') { + // array_byte_clone => array_clone + receiver_name = 'array' + } } name := '${receiver_name}_$it.name'.replace('.', '__') + // if it.receiver_type != 0 { + // g.write('/*${g.typ(it.receiver_type)}*/') + // g.write('/*expr_type=${g.typ(it.expr_type)} rec type=${g.typ(it.receiver_type)}*/') + // } g.write('${name}(') + if table.type_is_ptr(it.receiver_type) && !table.type_is_ptr(it.expr_type) { + // The receiver is a reference, but the caller provided a value + // Add `&` automatically. + g.write('&') + } g.expr(it.expr) if it.args.len > 0 { g.write(', ') } - g.call_args(it.args) + g.call_args(it.args, it.muts) g.write(')') } ast.None { @@ -643,9 +691,13 @@ fn (g mut Gen) expr(node ast.Expr) { g.write(it.op.str()) } ast.PrefixExpr { - g.write(it.op.str()) + if it.op == .amp { + g.is_amp = true + } // g.write('/*pref*/') + g.write(it.op.str()) g.expr(it.right) + g.is_amp = false } /* ast.UnaryExpr { @@ -677,13 +729,22 @@ fn (g mut Gen) expr(node ast.Expr) { // `user := User{name: 'Bob'}` ast.StructInit { styp := g.typ(it.typ) - g.writeln('($styp){') + if g.is_amp { + g.out.go_back(1) // delete the & already generated in `prefix_expr() + g.write('($styp*)memdup(&($styp){') + } + else { + g.writeln('($styp){') + } for i, field in it.fields { g.write('\t.$field = ') g.expr(it.exprs[i]) g.writeln(', ') } g.write('}') + if g.is_amp { + g.write(', sizeof($styp))') + } } ast.SelectorExpr { g.expr(it.expr) @@ -731,14 +792,27 @@ fn (g mut Gen) infix_expr(it ast.InfixExpr) { g.expr(it.right) g.write(')') } - // arr << val - else if it.op == .left_shift && g.table.get_type_symbol(it.left_type).kind == .array { - g.write('array_push(') + else if it.op == .key_in { + styp := g.typ(it.left_type) + g.write('_IN($styp, ') g.expr(it.left) g.write(', ') g.expr(it.right) g.write(')') } + // arr << val + else if it.op == .left_shift && g.table.get_type_symbol(it.left_type).kind == .array { + sym := g.table.get_type_symbol(it.left_type) + info := sym.info as table.Array + elem_type_str := g.typ(info.elem_type) + // g.write('array_push(&') + tmp := g.new_tmp_var() + g.write('_PUSH(&') + g.expr(it.left) + g.write(', ') + g.expr(it.right) + g.write(', $tmp, $elem_type_str)') + } else { // if it.op == .dot { // println('!! dot') @@ -847,8 +921,11 @@ fn (g mut Gen) const_decl(node ast.ConstDecl) { } } -fn (g mut Gen) call_args(args []ast.Expr) { +fn (g mut Gen) call_args(args []ast.Expr, muts []bool) { for i, expr in args { + if muts[i] { + g.write('&/*mut*/') + } g.expr(expr) if i != args.len - 1 { g.write(', ') @@ -860,19 +937,26 @@ fn verror(s string) { println('cgen error: $s') // exit(1) } + +const ( + builtins = ['string', 'array', 'KeyValue', 'map', 'Option'] +) + +fn (g mut Gen) write_builtin_types() { + mut builtin_types := []table.TypeSymbol // builtin types + // builtin types need to be on top + // everything except builtin will get sorted + for builtin_name in builtins { + builtin_types << g.table.types[g.table.type_idxs[builtin_name]] + } + g.write_types(builtin_types) +} + // C struct definitions, ordered // Sort the types, make sure types that are referenced by other types // are added before them. fn (g mut Gen) write_sorted_types() { mut types := []table.TypeSymbol // structs that need to be sorted - // builtin_types := [ - mut builtin_types := []table.TypeSymbol // builtin types - // builtin types need to be on top - builtins := ['string', 'array', 'KeyValue', 'map', 'Option'] - // everything except builtin will get sorted - for builtin_name in builtins { - builtin_types << g.table.types[g.table.type_idxs[builtin_name]] - } for typ in g.table.types { if !(typ.name in builtins) { types << typ @@ -882,7 +966,7 @@ fn (g mut Gen) write_sorted_types() { types_sorted := g.sort_structs(types) // Generate C code g.definitions.writeln('// builtin types:') - g.write_types(builtin_types) + // g.write_types(builtin_types) g.definitions.writeln('//------------------ #endbuiltin') g.write_types(types_sorted) } diff --git a/vlib/v/gen/cgen_test.v b/vlib/v/gen/cgen_test.v index 860a320190..09fb6295b8 100644 --- a/vlib/v/gen/cgen_test.v +++ b/vlib/v/gen/cgen_test.v @@ -7,14 +7,14 @@ import ( const ( nr_tests = 4 + term_ok = term.ok_message('OK') + term_fail = term.fail_message('FAIL') ) fn test_c_files() { println('Running V => C tests') vexe := os.getenv('VEXE') vroot := os.dir(vexe) - term_ok := term.ok_message('OK') - term_fail := term.fail_message('FAIL') for i in 1 .. (nr_tests + 1) { path := '$vroot/vlib/v/gen/tests/${i}.vv' mut ctext := os.read_file('$vroot/vlib/v/gen/tests/${i}.c') or { @@ -24,30 +24,31 @@ fn test_c_files() { mut b := builder.new_builder(pref.Preferences{}) b.module_search_paths = ['$vroot/vlib/v/gen/tests/'] res := b.gen_c([path]).after('#endbuiltin') - if compare_texts(res, ctext) { - eprintln('${term_ok} ${i}') + if compare_texts(res, ctext, path) { + println('${term_ok} ${i}') } else { - eprintln('${term_fail} ${i}') - eprintln('${path}: got\n$res') assert false } } } -fn compare_texts(a, b string) bool { +fn compare_texts(a, b, path string) bool { lines_a_ := a.trim_space().split_into_lines() lines_b_ := b.trim_space().split_into_lines() lines_a := lines_a_.filter(it != '') lines_b := lines_b_.filter(it != '') if lines_a.len != lines_b.len { println(term.red('different len')) - // return false + println('${path}: got\n$a') + return false } for i, line_a in lines_a { line_b := lines_b[i] if line_a.trim_space() != line_b.trim_space() { - println(term.red('i=$i V="$line_a" C="$line_b"')) + println('${path}: got\n$a') + println('${term_fail} ${i}') + println(term.red('i=$i "$line_a" expected="$line_b"')) // exit(1) return false } diff --git a/vlib/v/gen/cheaders.v b/vlib/v/gen/cheaders.v index aee5c6b642..8c2ad722e4 100644 --- a/vlib/v/gen/cheaders.v +++ b/vlib/v/gen/cheaders.v @@ -294,6 +294,7 @@ typedef array array_u32; typedef array array_u64; typedef map map_int; typedef map map_string; +typedef byte array_fixed_byte_300 [300]; #ifndef bool typedef int bool; #define true 1 diff --git a/vlib/v/gen/tests/1.c b/vlib/v/gen/tests/1.c index f9ff171db6..bad0fac993 100644 --- a/vlib/v/gen/tests/1.c +++ b/vlib/v/gen/tests/1.c @@ -52,7 +52,9 @@ int main() { localmod__pub_foo(); int ten = localmod__get_int_10(); println(localmod__pub_int_const); - int g = (int)(3.0); + int g = ((int)(3.0)); + byte* bytes = ((byte*)(0)); + User user_ptr = (User*)memdup(&(User){}, sizeof(User)); return 0; } diff --git a/vlib/v/gen/tests/1.vv b/vlib/v/gen/tests/1.vv index b423dbdb2e..d1854e0835 100644 --- a/vlib/v/gen/tests/1.vv +++ b/vlib/v/gen/tests/1.vv @@ -34,6 +34,8 @@ fn main() { ten := localmod.get_int_10() println(localmod.pub_int_const) g := int(3.0) + bytes := &byte(0) + user_ptr := &User{} } /* user := User{} diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 1453aa6b29..3ef5414068 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -75,6 +75,8 @@ fn (p mut Parser) fn_decl() ast.FnDecl { mut is_method := false mut rec_type := table.void_type mut rec_mut := false + mut args := []table.Var + mut ast_args := []ast.Arg if p.tok.kind == .lpar { is_method = true p.next() @@ -84,6 +86,15 @@ fn (p mut Parser) fn_decl() ast.FnDecl { rec_mut = true } rec_type = p.parse_type() + args << table.Var{ + // Receiver is the first arg + typ: rec_type + name: rec_name + } + ast_args << ast.Arg{ + name: rec_name + typ: rec_type + } // p.table.register_var(table.Var{ // name: rec_name // typ: rec_type @@ -111,8 +122,8 @@ fn (p mut Parser) fn_decl() ast.FnDecl { } // println('fn decl $name') // Args - mut args := []table.Var - ast_args,is_variadic := p.fn_args() + ast_args2,is_variadic := p.fn_args() + ast_args << ast_args2 for ast_arg in ast_args { var := table.Var{ name: ast_arg.name diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 1887ec9dc8..a917d6a019 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -44,6 +44,7 @@ mut: scope &ast.Scope imports map[string]string ast_imports []ast.Import + is_amp bool } // for tests @@ -55,7 +56,7 @@ 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} - + } p.init_parse_fns() p.read_first_token() @@ -79,7 +80,7 @@ pub fn parse_file(path string, table &table.Table, comments_mode scanner.Comment parent: 0 } // comments_mode: comments_mode - + } p.read_first_token() // p.scope = &ast.Scope{start_pos: p.tok.position(), parent: 0} @@ -558,7 +559,11 @@ pub fn (p mut Parser) name_expr() ast.Expr { // if name in table.builtin_type_names { if (name in p.table.type_idxs || name_w_mod in p.table.type_idxs) && !(name in ['C.stat', 'C.sigaction']) { // TODO handle C.stat() - to_typ := p.parse_type() + mut to_typ := p.parse_type() + if p.is_amp { + // Handle `&Foo(0)` + to_typ = table.type_to_ptr(to_typ) + } p.check(.lpar) mut expr := ast.Expr{} mut arg := ast.Expr{} @@ -613,7 +618,7 @@ pub fn (p mut Parser) name_expr() ast.Expr { p.expr_mod = '' return ast.EnumVal{ enum_name: enum_name // lp.prepend_mod(enum_name) - + val: val pos: p.tok.position() } @@ -810,8 +815,12 @@ pub fn (p mut Parser) expr(precedence int) ast.Expr { fn (p mut Parser) prefix_expr() ast.PrefixExpr { op := p.tok.kind + if op == .amp { + p.is_amp = true + } p.next() right := p.expr(1) + p.is_amp = false return ast.PrefixExpr{ op: op right: right @@ -940,7 +949,7 @@ fn (p mut Parser) infix_expr(left ast.Expr) ast.Expr { left: left right: right // right_type: typ - + op: op pos: pos } @@ -1051,7 +1060,7 @@ fn (p mut Parser) for_statement() ast.Stmt { p.scope.register_var(ast.Var{ name: var_name // expr: cond - + }) stmts := p.parse_block() // println('nr stmts=$stmts.len') @@ -1146,11 +1155,11 @@ fn (p mut Parser) if_expr() ast.Expr { stmts: stmts else_stmts: else_stmts // typ: typ - + pos: pos has_else: has_else // left: left - + } return node } @@ -1324,7 +1333,7 @@ fn (p mut Parser) const_decl() ast.ConstDecl { fields << ast.Field{ name: name // typ: typ - + } exprs << expr // TODO: once consts are fixed reg here & update in checker @@ -1715,7 +1724,6 @@ fn (p mut Parser) type_decl() ast.TypeDecl { sub_types: sum_variants } } - // type MyType int parent_type := p.parse_type() pid := table.type_idx(parent_type)