diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index cea9460a88..169330b9ec 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -9,8 +9,8 @@ import v.errors pub type TypeDecl = AliasTypeDecl | FnTypeDecl | SumTypeDecl -pub type Expr = AnonFn | ArrayInit | AsCast | Assoc | BoolLiteral | CallExpr | CastExpr | - ChanInit | CharLiteral | Comment | ComptimeCall | ConcatExpr | EnumVal | FloatLiteral | +pub type Expr = AnonFn | ArrayInit | AsCast | Assoc | BoolLiteral | CTempVar | CallExpr | + CastExpr | ChanInit | CharLiteral | Comment | ComptimeCall | ConcatExpr | EnumVal | FloatLiteral | Ident | IfExpr | IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral | Likely | LockExpr | MapInit | MatchExpr | None | OrExpr | ParExpr | PostfixExpr | PrefixExpr | RangeExpr | SelectExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | StringLiteral | StructInit | @@ -439,9 +439,9 @@ pub struct InfixExpr { pub: op token.Kind pos token.Position +pub mut: left Expr right Expr -pub mut: left_type table.Type right_type table.Type auto_locked string @@ -826,8 +826,9 @@ pub mut: pub struct AssertStmt { pub: - expr Expr pos token.Position +pub mut: + expr Expr } // `if [x := opt()] {` @@ -1025,6 +1026,7 @@ pub fn (expr Expr) position() token.Position { pub fn (expr Expr) is_lvalue() bool { match expr { Ident { return true } + CTempVar { return true } IndexExpr { return expr.left.is_lvalue() } SelectorExpr { return expr.expr.is_lvalue() } else {} @@ -1058,6 +1060,15 @@ pub fn (stmt Stmt) check_c_expr() ? { return error('unsupported statement (`${typeof(stmt)}`)') } +// CTempVar is used in cgen only, to hold nodes for temporary variables +pub struct CTempVar { +pub: + name string // the name of the C temporary variable; used by g.expr(x) + orig Expr // the original expression, which produced the C temp variable; used by x.str() + typ table.Type // the type of the original expression + is_ptr bool // whether the type is a pointer +} + pub fn (stmt Stmt) position() token.Position { match stmt { AssertStmt, AssignStmt, Block, ConstDecl, EnumDecl, ExprStmt, FnDecl, ForCStmt, ForInStmt, ForStmt, Import, Return, StructDecl { return stmt.pos } diff --git a/vlib/v/ast/str.v b/vlib/v/ast/str.v index 3f42cc9f3e..633bf223b2 100644 --- a/vlib/v/ast/str.v +++ b/vlib/v/ast/str.v @@ -177,6 +177,9 @@ pub fn (lit &StringInterLiteral) get_fspec_braces(i int) (string, bool) { // string representation of expr pub fn (x Expr) str() string { match x { + CTempVar { + return x.orig.str() + } BoolLiteral { return x.val.str() } @@ -188,6 +191,9 @@ pub fn (x Expr) str() string { if x.is_method { return '${x.left.str()}.${x.name}($sargs)' } + if x.name.starts_with('${x.mod}.') { + return util.strip_main_name('${x.name}($sargs)') + } return '${x.mod}.${x.name}($sargs)' } CharLiteral { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 3189f77c2f..ee9dbc85cf 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -2563,6 +2563,9 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type { return table.void_type } match mut node { + ast.CTempVar { + return node.typ + } ast.AnonFn { keep_fn := c.cur_fn c.cur_fn = &node.decl diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index 29450772f3..7503889cf1 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -711,6 +711,9 @@ pub fn (mut f Fmt) expr(node ast.Expr) { eprintln('expr: ${node.position():-42} | node: ${typeof(node):-20} | $node.str()') } match mut node { + ast.CTempVar { + eprintln('ast.CTempVar of $node.orig.str() should be generated/used only in cgen') + } ast.AnonFn { f.fn_decl(node.decl) } diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 7a75461bd6..8d884cc461 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -1272,8 +1272,40 @@ fn (mut g Gen) gen_attrs(attrs []table.Attr) { } } -fn (mut g Gen) gen_assert_stmt(a ast.AssertStmt) { +fn (mut g Gen) gen_assert_stmt(original_assert_statement ast.AssertStmt) { + mut a := original_assert_statement g.writeln('// assert') + mut tl_name := '' + mut tr_name := '' + if a.expr is ast.InfixExpr { + mut aie := a.expr as ast.InfixExpr + if aie.left is ast.CallExpr { + tl_styp := g.typ(aie.left_type) + tl_name = g.new_tmp_var() + g.write('$tl_styp $tl_name = ') + g.expr(aie.left) + g.writeln(';') + aie.left = ast.Expr(ast.CTempVar{ + name: tl_name + typ: aie.left_type + is_ptr: aie.left_type.is_ptr() + orig: aie.left + }) + } + if aie.right is ast.CallExpr { + tr_styp := g.typ(aie.right_type) + tr_name = g.new_tmp_var() + g.write('$tr_styp $tr_name = ') + g.expr(aie.right) + g.writeln(';') + aie.right = ast.Expr(ast.CTempVar{ + name: tr_name + typ: aie.right_type + is_ptr: aie.right_type.is_ptr() + orig: aie.right + }) + } + } g.inside_ternary++ g.write('if (') g.expr(a.expr) @@ -1338,7 +1370,7 @@ fn (mut g Gen) gen_assert_metainfo(a ast.AssertStmt) string { fn (mut g Gen) gen_assert_single_expr(e ast.Expr, t table.Type) { unknown_value := '*unknown value*' match e { - ast.CallExpr, ast.CastExpr, ast.IndexExpr, ast.PrefixExpr, ast.MatchExpr { + ast.CastExpr, ast.IndexExpr, ast.PrefixExpr, ast.MatchExpr { g.write(ctoslit(unknown_value)) } ast.Type { @@ -1962,6 +1994,7 @@ fn (mut g Gen) gen_anon_fn_decl(it ast.AnonFn) { fn (mut g Gen) expr(node ast.Expr) { // println('cgen expr() line_nr=$node.pos.line_nr') + // NB: please keep the type names in the match here in alphabetical order: match node { ast.AnonFn { // TODO: dont fiddle with buffers @@ -2084,6 +2117,10 @@ fn (mut g Gen) expr(node ast.Expr) { ast.ConcatExpr { g.concat_expr(node) } + ast.CTempVar { + // g.write('/*ctmp .orig: $node.orig.str() , .typ: $node.typ, .is_ptr: $node.is_ptr */ ') + g.write(node.name) + } ast.EnumVal { // g.write('${it.mod}${it.enum_name}_$it.val') styp := g.typ(node.typ) @@ -4366,6 +4403,11 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype table.Type) ?bool { g.write('($s)') } } + if expr is ast.CTempVar { + if expr.is_ptr { + g.write('*') + } + } g.expr(expr) if sym.kind == .struct_ && !sym_has_str_method { if is_p { diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index be32c18bce..02aaccba10 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -520,6 +520,9 @@ fn (mut g JsGen) stmt(node ast.Stmt) { fn (mut g JsGen) expr(node ast.Expr) { match node { + ast.CTempVar { + g.write('/* ast.CTempVar: node.name */') + } ast.AnonFn { g.gen_fn_decl(node.decl) } @@ -673,17 +676,17 @@ fn (mut g JsGen) gen_assert_stmt(a ast.AssertStmt) { mut mod_path := g.file.path.replace('\\', '\\\\') if g.is_test { g.writeln(' g_test_oks++;') - g.writeln(' cb_assertion_ok("$mod_path", ${a.pos.line_nr+1}, "assert $s_assertion", "${g.fn_decl.name}()" );') + g.writeln(' cb_assertion_ok("$mod_path", ${a.pos.line_nr + 1}, "assert $s_assertion", "${g.fn_decl.name}()" );') g.writeln('} else {') g.writeln(' g_test_fails++;') - g.writeln(' cb_assertion_failed("$mod_path", ${a.pos.line_nr+1}, "assert $s_assertion", "${g.fn_decl.name}()" );') + g.writeln(' cb_assertion_failed("$mod_path", ${a.pos.line_nr + 1}, "assert $s_assertion", "${g.fn_decl.name}()" );') g.writeln(' exit(1);') g.writeln('}') return } g.writeln('} else {') g.inc_indent() - g.writeln('builtin.eprintln("$mod_path:${a.pos.line_nr+1}: FAIL: fn ${g.fn_decl.name}(): assert $s_assertion");') + g.writeln('builtin.eprintln("$mod_path:${a.pos.line_nr + 1}: FAIL: fn ${g.fn_decl.name}(): assert $s_assertion");') g.writeln('builtin.exit(1);') g.dec_indent() g.writeln('}')