From e5c53cf412a67052ab0b694ab7b20863969456d9 Mon Sep 17 00:00:00 2001 From: lemon Date: Fri, 26 Aug 2022 21:18:02 +0900 Subject: [PATCH] native: match expr/stmt (#15537) --- vlib/v/gen/native/amd64.v | 73 ++++++++++++++++ vlib/v/gen/native/gen.v | 15 +++- vlib/v/gen/native/tests/match.vv | 125 +++++++++++++++++++++++++++ vlib/v/gen/native/tests/match.vv.out | 7 ++ 4 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 vlib/v/gen/native/tests/match.vv create mode 100644 vlib/v/gen/native/tests/match.vv.out diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index 7df355516..1bc168cd6 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -2572,3 +2572,76 @@ fn (mut g Gen) reverse_string(reg Register) { g.write8(0xf1) g.println('jmp 0xf') } + +fn (mut g Gen) gen_match_expr_amd64(expr ast.MatchExpr) { + branch_labels := []int{len: expr.branches.len, init: g.labels.new_label() + it * 0} // call new_label for all elements in the array + end_label := g.labels.new_label() + + if expr.is_sum_type { + // TODO + } else { + g.expr(expr.cond) + } + g.push(.rax) + + mut else_label := 0 + for i, branch in expr.branches { + if branch.is_else { + else_label = branch_labels[i] + } else { + for cond in branch.exprs { + match cond { + ast.RangeExpr { + g.pop(.rdx) + g.expr(cond.low) + g.cmp_reg(.rax, .rdx) + g.write([u8(0x0f), 0x9e, 0xc3]) + g.println('setle bl') + g.expr(cond.high) + g.cmp_reg(.rax, .rdx) + g.write([u8(0x0f), 0x9d, 0xc1]) + g.println('setge cl') + g.write([u8(0x20), 0xcb]) + g.println('and bl, cl') + g.write([u8(0x84), 0xdb]) + g.println('test bl, bl') + then_addr := g.cjmp(.jne) + g.labels.patches << LabelPatch{ + id: branch_labels[i] + pos: then_addr + } + g.push(.rdx) + } + else { + g.expr(cond) + g.pop(.rdx) + g.cmp_reg(.rax, .rdx) + then_addr := g.cjmp(.je) + g.labels.patches << LabelPatch{ + id: branch_labels[i] + pos: then_addr + } + g.push(.rdx) + } + } + } + } + } + g.pop(.rdx) + else_addr := g.jmp(0) + g.labels.patches << LabelPatch{ + id: else_label + pos: else_addr + } + for i, branch in expr.branches { + g.labels.addrs[branch_labels[i]] = g.pos() + for stmt in branch.stmts { + g.stmt(stmt) + } + g.labels.patches << LabelPatch{ + id: end_label + pos: g.jmp(0) + } + } + g.labels.addrs[end_label] = g.pos() +} diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index e7bdf1764..63855f599 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -482,6 +482,14 @@ fn (mut g Gen) call_fn(node ast.CallExpr) { } } +fn (mut g Gen) gen_match_expr(expr ast.MatchExpr) { + if g.pref.arch == .arm64 { + // g.gen_match_expr_arm64(expr) + } else { + g.gen_match_expr_amd64(expr) + } +} + fn (mut g Gen) gen_var_to_string(reg Register, var Var, config VarConfig) { typ := g.get_type_from_var(var) if typ.is_int() { @@ -601,7 +609,6 @@ g.expr ast.InfixExpr {} ast.IsRefType {} ast.MapInit {} - ast.MatchExpr {} ast.OrExpr {} ast.ParExpr {} ast.RangeExpr {} @@ -609,6 +616,9 @@ g.expr ast.SqlExpr {} ast.TypeNode {} */ + ast.MatchExpr { + g.gen_match_expr(expr) + } ast.TypeOf { g.gen_typeof_expr(expr, newline) } @@ -1045,6 +1055,9 @@ fn (mut g Gen) expr(node ast.Expr) { ast.GoExpr { g.v_error('native backend doesnt support threads yet', node.pos) } + ast.MatchExpr { + g.gen_match_expr(node) + } else { g.n_error('expr: unhandled node type: $node.type_name()') } diff --git a/vlib/v/gen/native/tests/match.vv b/vlib/v/gen/native/tests/match.vv new file mode 100644 index 000000000..8e2b087f9 --- /dev/null +++ b/vlib/v/gen/native/tests/match.vv @@ -0,0 +1,125 @@ +fn match_for_test() { // from for_loops_2_test.v + mut a := 2 + mut b := 0 + for { + match a { + 2 { + println('a == 2') + a = 0 + continue + } + 0 { + println('a == 0') + a = 5 + b++ + break + } + else { + println('unexpected branch') + break + } + } + } + assert a == 5 + assert b == 1 + println(b) + println(a) +} + +fn ifexpr_match_test() { // from if_expr_with_nested_match_expr_test.v + b := true // this is needed. why? + a := if b { + match 5 { + 5 { 0 } + else { 1 } + } + } else { + 3 + } + assert a == 0 + println(a) +} + +fn integer_match_test() { // from match_test.v + mut a := 3 + mut b := 0 + match a { + 2 { + println('two') + } + 3 { + println('three') + b = 3 + } + 4 { + println('four') + } + else { + println('???') + } + } + assert b == 3 + assert match 2 { + 1 { 2 } + 2 { 3 } + else { 5 } + } == 3 + assert match 0 { + 1 { 2 } + 2 { 3 } + else { 5 } + } == 5 + assert match 1 { + 2 { 0 } + else { 5 } + } == 5 + a = 0 + match 2 { + 0 { + a = 1 + } + 1 { + a = 2 + } + else { + a = 3 + } + } + assert a == 3 + a = 0 +/* match 1 { + 0 { + a = 1 + } + 1 { + a = 2 + a = a + 2 + a = a + 2 + } + else {} + } + assert a == 6 + a = 0 + match 1 { + 0 {} + else { a = -2 } + } + assert a == -2*/ +} + +fn multiple_test() { // from match_test.v + a := 9 + match a { + 1, 2, 3 { println('1-3') } + 4, 5 { println('4-5') } + 6...9 { println('6-9') } + else { println('other') } + } +} + +fn main() { + match_for_test() + ifexpr_match_test() + integer_match_test() + multiple_test() +} diff --git a/vlib/v/gen/native/tests/match.vv.out b/vlib/v/gen/native/tests/match.vv.out new file mode 100644 index 000000000..f7415a4b4 --- /dev/null +++ b/vlib/v/gen/native/tests/match.vv.out @@ -0,0 +1,7 @@ +a == 2 +a == 0 +1 +5 +0 +three +6-9 -- 2.30.2