diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 759497dc3e..e2f96a4665 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -5066,7 +5066,9 @@ fn (mut g Gen) if_expr(node ast.IfExpr) { g.stmt_path_pos << stmt_pos } } - g.writeln('}') + if node.branches.len > 0 { + g.writeln('}') + } g.set_current_pos_as_last_stmt_pos() if needs_tmp_var { if g.infix_left_var_name.len > 0 { diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index d37175b3f6..f08f1bff5e 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -2387,7 +2387,9 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) { g.stmts(branch.stmts) } } - g.writeln('}') + if node.branches.len > 0 { + g.writeln('}') + } if needs_tmp_var { g.write('$tmp') } diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index b256f734f2..93f401b77f 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -1268,22 +1268,32 @@ fn (mut g Gen) condition(infix_expr ast.InfixExpr, neg bool) int { } fn (mut g Gen) if_expr(node ast.IfExpr) { - branch := node.branches[0] - infix_expr := branch.cond as ast.InfixExpr - cjmp_addr := g.condition(infix_expr, false) if node.is_comptime { g.n_error('ignored comptime') } - g.stmts(branch.stmts) - // Now that we know where we need to jump if the condition is false, update the `jne` call. - // The value is the relative address, difference between current position and the location - // after `jne 00 00 00 00` - // println('after if g.pos=$g.pos() jneaddr=$cjmp_addr') - g.write32_at(cjmp_addr, int(g.pos() - cjmp_addr - 4)) // 4 is for "00 00 00 00" - if node.has_else { g.n_error('else statements not yet supported') } + if node.branches.len == 0 { + return + } + for idx in 0 .. node.branches.len { + branch := node.branches[idx] + if branch.cond is ast.BoolLiteral { + if branch.cond.val { + g.stmts(branch.stmts) + } + continue + } + infix_expr := branch.cond as ast.InfixExpr + cjmp_addr := g.condition(infix_expr, false) + g.stmts(branch.stmts) + // Now that we know where we need to jump if the condition is false, update the `jne` call. + // The value is the relative address, difference between current position and the location + // after `jne 00 00 00 00` + // println('after if g.pos=$g.pos() jneaddr=$cjmp_addr') + g.write32_at(cjmp_addr, int(g.pos() - cjmp_addr - 4)) // 4 is for "00 00 00 00" + } } fn (mut g Gen) infloop() { diff --git a/vlib/v/transformer/transformer.v b/vlib/v/transformer/transformer.v index a91a3a2776..3b79b27aee 100644 --- a/vlib/v/transformer/transformer.v +++ b/vlib/v/transformer/transformer.v @@ -56,10 +56,19 @@ pub fn (t Transformer) stmt(mut node ast.Stmt) { ast.DeferStmt {} ast.EnumDecl {} ast.ExprStmt { - expr := t.expr(node.expr) - node = &ast.ExprStmt{ - ...node - expr: expr + if node.expr is ast.IfExpr { + mut untrans_expr := node.expr as ast.IfExpr + expr := t.if_expr(mut untrans_expr) + node = &ast.ExprStmt{ + ...node + expr: expr + } + } else { + expr := t.expr(node.expr) + node = &ast.ExprStmt{ + ...node + expr: expr + } } } ast.FnDecl { @@ -69,7 +78,15 @@ pub fn (t Transformer) stmt(mut node ast.Stmt) { } ast.ForCStmt {} ast.ForInStmt {} - ast.ForStmt {} + ast.ForStmt { + node = &ast.ForStmt{ + ...node + cond: t.expr(node.cond) + } + if node.cond is ast.BoolLiteral && !(node.cond as ast.BoolLiteral).val { // for false { ... } should be eleminated + node = &ast.EmptyStmt{} + } + } ast.GlobalDecl {} ast.GotoLabel {} ast.GotoStmt {} @@ -89,12 +106,71 @@ pub fn (t Transformer) stmt(mut node ast.Stmt) { } pub fn (t Transformer) expr(node ast.Expr) ast.Expr { - match node { - ast.InfixExpr { return t.infix_expr(node) } - else { return node } + match mut node { + ast.InfixExpr { + return t.infix_expr(node) + } + ast.IndexExpr { + return ast.IndexExpr{ + ...node + index: t.expr(node.index) + } + } + ast.MatchExpr { + for mut branch in node.branches { + for mut stmt in branch.stmts { + t.stmt(mut stmt) + } + } + return node + } + else { + return node + } } } +pub fn (t Transformer) if_expr(mut original ast.IfExpr) ast.Expr { + mut stop_index, mut unreachable_branches := -1, []int{cap: original.branches.len} + for i, mut branch in original.branches { + for mut stmt in branch.stmts { + t.stmt(mut stmt) + } + cond := t.expr(branch.cond) + branch = ast.IfBranch{ + ...(*branch) + cond: cond + } + if cond is ast.BoolLiteral { + if cond.val { // eliminates remaining branches when reached first bool literal `true` + stop_index = i + break + } else { // discard unreachable branch when reached bool literal `false` + unreachable_branches << i + } + } + } + if stop_index != -1 { + unreachable_branches = unreachable_branches.filter(it < stop_index) + original.branches = original.branches[..stop_index + 1] + } + for unreachable_branches.len != 0 { + original.branches.delete(unreachable_branches.pop()) + } + if original.branches.len == 0 { // no remain branches to walk through + return ast.EmptyExpr{} + } + if original.branches.len == 1 && original.branches[0].cond.type_name() == 'unknown v.ast.Expr' { + original.branches[0] = &ast.IfBranch{ + ...original.branches[0] + cond: ast.BoolLiteral{ + val: true + } + } + } + return *original +} + pub fn (t Transformer) infix_expr(original ast.InfixExpr) ast.Expr { mut node := original node.left = t.expr(node.left) @@ -109,6 +185,16 @@ pub fn (t Transformer) infix_expr(original ast.InfixExpr) ast.Expr { match right_node { ast.BoolLiteral { match node.op { + .eq { + return ast.BoolLiteral{ + val: left_node.val == right_node.val + } + } + .ne { + return ast.BoolLiteral{ + val: left_node.val != right_node.val + } + } .and { return ast.BoolLiteral{ val: left_node.val && right_node.val @@ -133,6 +219,16 @@ pub fn (t Transformer) infix_expr(original ast.InfixExpr) ast.Expr { match right_node { ast.StringLiteral { match node.op { + .eq { + return ast.BoolLiteral{ + val: left_node.val == right_node.val + } + } + .ne { + return ast.BoolLiteral{ + val: left_node.val != right_node.val + } + } .plus { return ast.StringLiteral{ val: left_node.val + right_node.val @@ -155,6 +251,36 @@ pub fn (t Transformer) infix_expr(original ast.InfixExpr) ast.Expr { left_val := left_node.val.int() right_val := right_node.val.int() match node.op { + .eq { + return ast.BoolLiteral{ + val: left_node.val == right_node.val + } + } + .ne { + return ast.BoolLiteral{ + val: left_node.val != right_node.val + } + } + .gt { + return ast.BoolLiteral{ + val: left_node.val > right_node.val + } + } + .ge { + return ast.BoolLiteral{ + val: left_node.val >= right_node.val + } + } + .lt { + return ast.BoolLiteral{ + val: left_node.val < right_node.val + } + } + .le { + return ast.BoolLiteral{ + val: left_node.val <= right_node.val + } + } .plus { return ast.IntegerLiteral{ val: (left_val + right_val).str() @@ -203,6 +329,24 @@ pub fn (t Transformer) infix_expr(original ast.InfixExpr) ast.Expr { pos: pos } } + .left_shift { + return ast.IntegerLiteral{ + val: (left_val << right_val).str() + pos: pos + } + } + .right_shift { + return ast.IntegerLiteral{ + val: (left_val >> right_val).str() + pos: pos + } + } + .unsigned_right_shift { + return ast.IntegerLiteral{ + val: (left_val >>> right_val).str() + pos: pos + } + } else { return node }