diff --git a/cmd/v/flag.v b/cmd/v/flag.v index 790b5c2fe5..3aeea75dfd 100644 --- a/cmd/v/flag.v +++ b/cmd/v/flag.v @@ -94,6 +94,7 @@ fn parse_flags(flag string, f mut flag.Instance, prefs mut flag.MainCmdPreferenc println('V error: Error parsing flag. Expected value for `-$flag`.') exit(1) } + return } } } diff --git a/vlib/builtin/map.v b/vlib/builtin/map.v index 950657aad0..4afdfbdf98 100644 --- a/vlib/builtin/map.v +++ b/vlib/builtin/map.v @@ -313,6 +313,12 @@ fn (m map) get(key string, out voidptr) bool { return false } +// TODO +/* +fn (m &map) get2(key string, out voidptr) voidptr { +} +*/ + fn (m map) exists(key string) bool { if m.value_bytes == 0 { return false diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 6410e4d724..94aeac1663 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -10,15 +10,15 @@ import ( pub type TypeDecl = AliasTypeDecl | SumTypeDecl | FnTypeDecl -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 | GoStmt // pub type Type = StructType | ArrayType // pub struct StructType { @@ -340,6 +340,7 @@ pub: left Expr // `a` in `a := if ...` pos token.Position mut: + is_expr bool typ table.Type has_else bool } @@ -351,7 +352,8 @@ pub: branches []MatchBranch pos token.Position mut: -is_expr bool // returns a value + is_expr bool // returns a value + return_type table.Type expr_type table.Type // type of `x` in `match x {` is_sum_type bool } @@ -591,6 +593,7 @@ pub: pub struct SizeOf { pub: + typ table.Type type_name string } @@ -641,6 +644,7 @@ enum BinaryOp { } */ + [inline] pub fn expr_is_blank_ident(expr Expr) bool { match expr { @@ -656,14 +660,13 @@ pub fn expr_is_blank_ident(expr Expr) bool { [inline] pub fn expr_is_call(expr Expr) bool { return match expr { - CallExpr { + CallExpr{ true } - MethodCallExpr { + MethodCallExpr{ true } else { - false - } + false} } } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index a8ddd7534d..809473d113 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -270,6 +270,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 { + c.expected_type = table.void_type typ := c.expr(method_call_expr.expr) method_call_expr.expr_type = typ typ_sym := c.table.get_type_symbol(typ) @@ -492,7 +493,7 @@ pub fn (c mut Checker) array_init(array_init mut ast.ArrayInit) table.Type { else { c.error('expecting `int` for fixed size', array_init.pos) } - } + } idx := c.table.find_or_register_array_fixed(array_init.elem_type, fixed_size, 1) array_type := table.new_type(idx) array_init.typ = array_type @@ -525,6 +526,7 @@ fn (c mut Checker) stmt(node ast.Stmt) { c.expr(it.expr) } ast.FnDecl { + c.expected_type = table.void_type c.fn_return_type = it.return_type for stmt in it.stmts { c.stmt(stmt) @@ -815,14 +817,25 @@ pub fn (c mut Checker) match_expr(node mut ast.MatchExpr) table.Type { } } } + // if ret_type != table.void_type { + // node.is_expr = c.expected_type != table.void_type + // node.expected_type = c.expected_type + // } + node.return_type = ret_type node.expr_type = expr_type // println('!m $expr_type') return ret_type } pub fn (c mut Checker) if_expr(node mut ast.IfExpr) table.Type { + if c.expected_type != 0 { + // sym := c.table.get_type_symbol(c.expected_type) + // println('$c.file.path $node.pos.line_nr IF: checker exp type = ' + sym.name) + node.is_expr = true + } typ := c.expr(node.cond) - node.typ = typ + node.typ = table.void_type + // node.typ = typ typ_sym := c.table.get_type_symbol(typ) // if typ_sym.kind != .bool { if table.type_idx(typ) != table.bool_type_idx { diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 22ffab2b6d..bb58f54c99 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -22,6 +22,7 @@ mut: is_array_set bool is_amp bool // for `&Foo{}` to merge PrefixExpr `&` and StructInit `Foo{}`; also for `&byte(0)` etc optionals []string // to avoid duplicates TODO perf, use map + inside_ternary bool // ?: comma separated statements on a single line } pub fn cgen(files []ast.File, table &table.Table) string { @@ -116,7 +117,7 @@ pub fn (g mut Gen) write_typedef_types() { if !info.has_decl && !info.is_anon { fn_name := func.name.replace('.', '__') g.definitions.write('typedef ${g.typ(func.return_type)} (*$fn_name)(') - for i,arg in func.args { + for i, arg in func.args { g.definitions.write(g.typ(arg.typ)) if i < func.args.len - 1 { g.definitions.write(',') @@ -191,7 +192,9 @@ pub fn (g mut Gen) reset_tmp_count() { fn (g mut Gen) stmts(stmts []ast.Stmt) { for stmt in stmts { g.stmt(stmt) - g.writeln('') + if !g.inside_ternary { + g.writeln('') + } } } @@ -245,7 +248,9 @@ fn (g mut Gen) stmt(node ast.Stmt) { // no ; after an if expression ast.IfExpr {} else { - g.writeln(';') + if !g.inside_ternary { + g.writeln(';') + } } } } @@ -342,7 +347,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { // use instead of expr() when you need to cast to sum type (can add other casts also) fn (g mut Gen) expr_with_cast(got_type table.Type, exp_type table.Type, expr ast.Expr) { // cast to sum type - if exp_type != table.void_type && exp_type != 0 && got_type != 0{ + if exp_type != table.void_type && exp_type != 0 && got_type != 0 { exp_sym := g.table.get_type_symbol(exp_type) if exp_sym.kind == .sum_type { sum_info := exp_sym.info as table.SumType @@ -427,7 +432,8 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { g.write(' = ') if !is_decl { g.expr_with_cast(assign_stmt.left_types[i], ident_var_info.typ, val) - } else { + } + else { g.expr(val) } } @@ -811,7 +817,8 @@ fn (g mut Gen) expr(node ast.Expr) { */ ast.SizeOf { - g.write('sizeof($it.type_name)') + styp := g.typ(it.typ) + g.write('sizeof($styp)') } ast.StringLiteral { // In C calls we have to generate C strings @@ -966,44 +973,65 @@ fn (g mut Gen) match_expr(node ast.MatchExpr) { g.writeln('// match 0') return } + is_expr := node.return_type != table.void_type + if is_expr { + g.inside_ternary = true + // g.write('/* EM ret type=${g.typ(node.return_type)} */') + } type_sym := g.table.get_type_symbol(node.expr_type) mut tmp := '' if type_sym.kind != .void { tmp = g.new_tmp_var() } - //styp := g.typ(node.expr_type) - //g.write('$styp $tmp = ') - //g.expr(node.cond) - //g.writeln(';') // $it.blocks.len') + // styp := g.typ(node.expr_type) + // g.write('$styp $tmp = ') + // g.expr(node.cond) + // g.writeln(';') // $it.blocks.len') // mut sum_type_str = '' for j, branch in node.branches { if j == node.branches.len - 1 { // last block is an `else{}` - g.writeln('else {') + if is_expr { + // TODO too many branches. maybe separate ?: matches + g.write(' : ') + } + else { + g.writeln('else {') + } } else { if j > 0 { - g.write('else ') + if is_expr { + g.write(' : ') + } + else { + g.write('else ') + } + } + if is_expr { + g.write('(') + } + else { + g.write('if (') } - g.write('if (') for i, expr in branch.exprs { if node.is_sum_type { - g.expr(node.cond ) + g.expr(node.cond) g.write('.typ == ') - //g.write('${tmp}.typ == ') + // g.write('${tmp}.typ == ') // sum_type_str } else if type_sym.kind == .string { g.write('string_eq(') // -g.expr(node.cond) -g.write(', ') - //g.write('string_eq($tmp, ') + g.expr(node.cond) + g.write(', ') + // g.write('string_eq($tmp, ') } else { g.expr(node.cond) g.write(' == ') - //g.write('$tmp == ') + // g.write('$tmp == ') } g.expr(expr) if type_sym.kind == .string { @@ -1013,7 +1041,12 @@ g.write(', ') g.write(' || ') } } - g.writeln(') {') + if is_expr { + g.write(') ? ') + } + else { + g.writeln(') {') + } } if node.is_sum_type && branch.exprs.len > 0 { // The first node in expr is an ast.Type @@ -1022,7 +1055,10 @@ g.write(', ') match fe { ast.Type { it_type := g.typ(it.typ) - g.writeln('$it_type* it = ($it_type*)${tmp}.obj; // ST it') + // g.writeln('$it_type* it = ($it_type*)${tmp}.obj; // ST it') + g.write('$it_type* it = ($it_type*)') + g.expr(node.cond) + g.writeln('.obj; // ST it') } else { verror('match sum type') @@ -1030,8 +1066,11 @@ g.write(', ') } } g.stmts(branch.stmts) - g.writeln('}') + if !g.inside_ternary { + g.writeln('}') + } } + g.inside_ternary = false } fn (g mut Gen) ident(node ast.Ident) { @@ -1067,12 +1106,13 @@ fn (g mut Gen) if_expr(node ast.IfExpr) { } // one line ?: // TODO clean this up once `is` is supported - if node.stmts.len == 1 && node.else_stmts.len == 1 && type_sym.kind != .void { + if node.is_expr && node.stmts.len == 1 && node.else_stmts.len == 1 && type_sym.kind != .void { cond := node.cond stmt1 := node.stmts[0] else_stmt1 := node.else_stmts[0] match stmt1 { ast.ExprStmt { + g.inside_ternary = true g.expr(cond) g.write(' ? ') expr_stmt := stmt1 as ast.ExprStmt @@ -1081,7 +1121,7 @@ fn (g mut Gen) if_expr(node ast.IfExpr) { g.stmt(else_stmt1) } else {} - } + } } else { mut is_guard := false @@ -1096,11 +1136,12 @@ fn (g mut Gen) if_expr(node ast.IfExpr) { g.writeln('if (($guard_ok = ${it.var_name}.ok)) {') } else { + g.inside_ternary = false g.write('if (') g.expr(node.cond) g.writeln(') {') } - } + } for i, stmt in node.stmts { // Assign ret value if i == node.stmts.len - 1 && type_sym.kind != .void {} @@ -1113,8 +1154,9 @@ fn (g mut Gen) if_expr(node ast.IfExpr) { g.writeln('}') if node.else_stmts.len > 0 { if is_guard { - g.writeln('if !$guard_ok { /* else */') - } else { + g.writeln('if (!$guard_ok) { /* else */') + } + else { g.writeln('else { ') } for stmt in node.else_stmts { @@ -1123,6 +1165,7 @@ fn (g mut Gen) if_expr(node ast.IfExpr) { g.writeln('}') } } + g.inside_ternary = false } fn (g mut Gen) index_expr(node ast.IndexExpr) { @@ -1210,6 +1253,10 @@ fn (g mut Gen) index_expr(node ast.IndexExpr) { fn (g mut Gen) return_statement(it ast.Return) { g.write('return') + if g.fn_decl.name == 'main' { + g.writeln(' 0;') + return + } // multiple returns if it.exprs.len > 1 { typ_sym := g.table.get_type_symbol(g.fn_decl.return_type) diff --git a/vlib/v/gen/cgen_test.v b/vlib/v/gen/cgen_test.v index 1fda2f3692..4bc320b576 100644 --- a/vlib/v/gen/cgen_test.v +++ b/vlib/v/gen/cgen_test.v @@ -55,8 +55,8 @@ fn compare_texts(a, b, path string) bool { println('${path}: got\n$a') println('${term_fail} ${i}') println(term.red('i=$i "$line_a" expected="$line_b"')) - // println(lines_b[i + 1]) - // println(lines_b[i + 2]) + println(lines_b[i + 1]) + println(lines_b[i + 2]) // exit(1) return false } diff --git a/vlib/v/gen/tests/1.c b/vlib/v/gen/tests/1.c index 8ebca07f48..d85b2fff52 100644 --- a/vlib/v/gen/tests/1.c +++ b/vlib/v/gen/tests/1.c @@ -149,7 +149,6 @@ multi_return_int_string multi_return() { void variadic(varg_int a) { int x = path_sep; int y = true ? 1 : 0; -; } void ensure_cap(int required, int cap) { @@ -172,6 +171,9 @@ void matches() { else { } ; + string x = (a == 10) ? tos3("ten") : (a == 30) ? tos3("thirty") : tos3("unknown"); + int xx = (a == 10) ? 100 : (a == 30) ? 300 : 0; + println((a == 10) ? tos3("ten") : tos3("not ten")); } //10 diff --git a/vlib/v/gen/tests/1.vv b/vlib/v/gen/tests/1.vv index e31302772c..29c20e6b2d 100644 --- a/vlib/v/gen/tests/1.vv +++ b/vlib/v/gen/tests/1.vv @@ -156,6 +156,17 @@ fn matches() { } else{} } + x := match a { + 10 { 'ten' } + 30 { 'thirty' } + else { 'unknown' } + } + xx := match a { + 10 { 100 } + 30 { 300 } + else { 0 } + } + println(match a { 10 { 'ten' } else { 'not ten' } }) /* n := match a { 1 { 10 } diff --git a/vlib/v/gen/tests/3.c b/vlib/v/gen/tests/3.c index decd7407b7..9804a496b3 100644 --- a/vlib/v/gen/tests/3.c +++ b/vlib/v/gen/tests/3.c @@ -40,11 +40,11 @@ void println(string s) { void handle_expr(Expr e) { if (e.typ == _type_idx_IfExpr) { - IfExpr* it = (IfExpr*)tmp1.obj; // ST it + IfExpr* it = (IfExpr*)e.obj; // ST it println(tos3("if")); } else if (e.typ == _type_idx_IntegerLiteral) { - IntegerLiteral* it = (IntegerLiteral*)tmp1.obj; // ST it + IntegerLiteral* it = (IntegerLiteral*)e.obj; // ST it println(tos3("integer")); } else { diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 6cf6ddce95..230916a03d 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -748,10 +748,13 @@ pub fn (p mut Parser) expr(precedence int) ast.Expr { if p.tok.kind == .amp { p.next() } - type_name := p.check_name() + // type_name := p.check_name() + sizeof_type := p.parse_type() p.check(.rpar) node = ast.SizeOf{ - type_name: type_name + typ: sizeof_type + // type_name: type_name + } } // Map `{"age": 20}` or `{ x | foo:bar, a:10 }`