1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

cgen: print results of failed callexprs in assert fn() == fn2() (#6665)

This commit is contained in:
Delyan Angelov 2020-10-21 22:58:40 +03:00 committed by GitHub
parent 6d11caf784
commit ab137e4164
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 77 additions and 9 deletions

View File

@ -9,8 +9,8 @@ import v.errors
pub type TypeDecl = AliasTypeDecl | FnTypeDecl | SumTypeDecl pub type TypeDecl = AliasTypeDecl | FnTypeDecl | SumTypeDecl
pub type Expr = AnonFn | ArrayInit | AsCast | Assoc | BoolLiteral | CallExpr | CastExpr | pub type Expr = AnonFn | ArrayInit | AsCast | Assoc | BoolLiteral | CTempVar | CallExpr |
ChanInit | CharLiteral | Comment | ComptimeCall | ConcatExpr | EnumVal | FloatLiteral | CastExpr | ChanInit | CharLiteral | Comment | ComptimeCall | ConcatExpr | EnumVal | FloatLiteral |
Ident | IfExpr | IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral | Likely | LockExpr | Ident | IfExpr | IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral | Likely | LockExpr |
MapInit | MatchExpr | None | OrExpr | ParExpr | PostfixExpr | PrefixExpr | RangeExpr | MapInit | MatchExpr | None | OrExpr | ParExpr | PostfixExpr | PrefixExpr | RangeExpr |
SelectExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | StringLiteral | StructInit | SelectExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | StringLiteral | StructInit |
@ -439,9 +439,9 @@ pub struct InfixExpr {
pub: pub:
op token.Kind op token.Kind
pos token.Position pos token.Position
pub mut:
left Expr left Expr
right Expr right Expr
pub mut:
left_type table.Type left_type table.Type
right_type table.Type right_type table.Type
auto_locked string auto_locked string
@ -826,8 +826,9 @@ pub mut:
pub struct AssertStmt { pub struct AssertStmt {
pub: pub:
expr Expr
pos token.Position pos token.Position
pub mut:
expr Expr
} }
// `if [x := opt()] {` // `if [x := opt()] {`
@ -1025,6 +1026,7 @@ pub fn (expr Expr) position() token.Position {
pub fn (expr Expr) is_lvalue() bool { pub fn (expr Expr) is_lvalue() bool {
match expr { match expr {
Ident { return true } Ident { return true }
CTempVar { return true }
IndexExpr { return expr.left.is_lvalue() } IndexExpr { return expr.left.is_lvalue() }
SelectorExpr { return expr.expr.is_lvalue() } SelectorExpr { return expr.expr.is_lvalue() }
else {} else {}
@ -1058,6 +1060,15 @@ pub fn (stmt Stmt) check_c_expr() ? {
return error('unsupported statement (`${typeof(stmt)}`)') 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 { pub fn (stmt Stmt) position() token.Position {
match stmt { match stmt {
AssertStmt, AssignStmt, Block, ConstDecl, EnumDecl, ExprStmt, FnDecl, ForCStmt, ForInStmt, ForStmt, Import, Return, StructDecl { return stmt.pos } AssertStmt, AssignStmt, Block, ConstDecl, EnumDecl, ExprStmt, FnDecl, ForCStmt, ForInStmt, ForStmt, Import, Return, StructDecl { return stmt.pos }

View File

@ -177,6 +177,9 @@ pub fn (lit &StringInterLiteral) get_fspec_braces(i int) (string, bool) {
// string representation of expr // string representation of expr
pub fn (x Expr) str() string { pub fn (x Expr) str() string {
match x { match x {
CTempVar {
return x.orig.str()
}
BoolLiteral { BoolLiteral {
return x.val.str() return x.val.str()
} }
@ -188,6 +191,9 @@ pub fn (x Expr) str() string {
if x.is_method { if x.is_method {
return '${x.left.str()}.${x.name}($sargs)' 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)' return '${x.mod}.${x.name}($sargs)'
} }
CharLiteral { CharLiteral {

View File

@ -2563,6 +2563,9 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
return table.void_type return table.void_type
} }
match mut node { match mut node {
ast.CTempVar {
return node.typ
}
ast.AnonFn { ast.AnonFn {
keep_fn := c.cur_fn keep_fn := c.cur_fn
c.cur_fn = &node.decl c.cur_fn = &node.decl

View File

@ -711,6 +711,9 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
eprintln('expr: ${node.position():-42} | node: ${typeof(node):-20} | $node.str()') eprintln('expr: ${node.position():-42} | node: ${typeof(node):-20} | $node.str()')
} }
match mut node { match mut node {
ast.CTempVar {
eprintln('ast.CTempVar of $node.orig.str() should be generated/used only in cgen')
}
ast.AnonFn { ast.AnonFn {
f.fn_decl(node.decl) f.fn_decl(node.decl)
} }

View File

@ -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') 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.inside_ternary++
g.write('if (') g.write('if (')
g.expr(a.expr) 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) { fn (mut g Gen) gen_assert_single_expr(e ast.Expr, t table.Type) {
unknown_value := '*unknown value*' unknown_value := '*unknown value*'
match e { 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)) g.write(ctoslit(unknown_value))
} }
ast.Type { 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) { fn (mut g Gen) expr(node ast.Expr) {
// println('cgen expr() line_nr=$node.pos.line_nr') // println('cgen expr() line_nr=$node.pos.line_nr')
// NB: please keep the type names in the match here in alphabetical order:
match node { match node {
ast.AnonFn { ast.AnonFn {
// TODO: dont fiddle with buffers // TODO: dont fiddle with buffers
@ -2084,6 +2117,10 @@ fn (mut g Gen) expr(node ast.Expr) {
ast.ConcatExpr { ast.ConcatExpr {
g.concat_expr(node) 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 { ast.EnumVal {
// g.write('${it.mod}${it.enum_name}_$it.val') // g.write('${it.mod}${it.enum_name}_$it.val')
styp := g.typ(node.typ) 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)') g.write('($s)')
} }
} }
if expr is ast.CTempVar {
if expr.is_ptr {
g.write('*')
}
}
g.expr(expr) g.expr(expr)
if sym.kind == .struct_ && !sym_has_str_method { if sym.kind == .struct_ && !sym_has_str_method {
if is_p { if is_p {

View File

@ -520,6 +520,9 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
fn (mut g JsGen) expr(node ast.Expr) { fn (mut g JsGen) expr(node ast.Expr) {
match node { match node {
ast.CTempVar {
g.write('/* ast.CTempVar: node.name */')
}
ast.AnonFn { ast.AnonFn {
g.gen_fn_decl(node.decl) 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('\\', '\\\\') mut mod_path := g.file.path.replace('\\', '\\\\')
if g.is_test { if g.is_test {
g.writeln(' g_test_oks++;') 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('} else {')
g.writeln(' g_test_fails++;') 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(' exit(1);')
g.writeln('}') g.writeln('}')
return return
} }
g.writeln('} else {') g.writeln('} else {')
g.inc_indent() 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.writeln('builtin.exit(1);')
g.dec_indent() g.dec_indent()
g.writeln('}') g.writeln('}')