Skip to content

Commit e5c53cf

Browse files
authored
native: match expr/stmt (#15537)
1 parent 02a47f4 commit e5c53cf

File tree

4 files changed

+219
-1
lines changed

4 files changed

+219
-1
lines changed

vlib/v/gen/native/amd64.v

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2572,3 +2572,76 @@ fn (mut g Gen) reverse_string(reg Register) {
25722572
g.write8(0xf1)
25732573
g.println('jmp 0xf')
25742574
}
2575+
2576+
fn (mut g Gen) gen_match_expr_amd64(expr ast.MatchExpr) {
2577+
branch_labels := []int{len: expr.branches.len, init: g.labels.new_label() + it * 0} // call new_label for all elements in the array
2578+
end_label := g.labels.new_label()
2579+
2580+
if expr.is_sum_type {
2581+
// TODO
2582+
} else {
2583+
g.expr(expr.cond)
2584+
}
2585+
g.push(.rax)
2586+
2587+
mut else_label := 0
2588+
for i, branch in expr.branches {
2589+
if branch.is_else {
2590+
else_label = branch_labels[i]
2591+
} else {
2592+
for cond in branch.exprs {
2593+
match cond {
2594+
ast.RangeExpr {
2595+
g.pop(.rdx)
2596+
g.expr(cond.low)
2597+
g.cmp_reg(.rax, .rdx)
2598+
g.write([u8(0x0f), 0x9e, 0xc3])
2599+
g.println('setle bl')
2600+
g.expr(cond.high)
2601+
g.cmp_reg(.rax, .rdx)
2602+
g.write([u8(0x0f), 0x9d, 0xc1])
2603+
g.println('setge cl')
2604+
g.write([u8(0x20), 0xcb])
2605+
g.println('and bl, cl')
2606+
g.write([u8(0x84), 0xdb])
2607+
g.println('test bl, bl')
2608+
then_addr := g.cjmp(.jne)
2609+
g.labels.patches << LabelPatch{
2610+
id: branch_labels[i]
2611+
pos: then_addr
2612+
}
2613+
g.push(.rdx)
2614+
}
2615+
else {
2616+
g.expr(cond)
2617+
g.pop(.rdx)
2618+
g.cmp_reg(.rax, .rdx)
2619+
then_addr := g.cjmp(.je)
2620+
g.labels.patches << LabelPatch{
2621+
id: branch_labels[i]
2622+
pos: then_addr
2623+
}
2624+
g.push(.rdx)
2625+
}
2626+
}
2627+
}
2628+
}
2629+
}
2630+
g.pop(.rdx)
2631+
else_addr := g.jmp(0)
2632+
g.labels.patches << LabelPatch{
2633+
id: else_label
2634+
pos: else_addr
2635+
}
2636+
for i, branch in expr.branches {
2637+
g.labels.addrs[branch_labels[i]] = g.pos()
2638+
for stmt in branch.stmts {
2639+
g.stmt(stmt)
2640+
}
2641+
g.labels.patches << LabelPatch{
2642+
id: end_label
2643+
pos: g.jmp(0)
2644+
}
2645+
}
2646+
g.labels.addrs[end_label] = g.pos()
2647+
}

vlib/v/gen/native/gen.v

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,14 @@ fn (mut g Gen) call_fn(node ast.CallExpr) {
482482
}
483483
}
484484

485+
fn (mut g Gen) gen_match_expr(expr ast.MatchExpr) {
486+
if g.pref.arch == .arm64 {
487+
// g.gen_match_expr_arm64(expr)
488+
} else {
489+
g.gen_match_expr_amd64(expr)
490+
}
491+
}
492+
485493
fn (mut g Gen) gen_var_to_string(reg Register, var Var, config VarConfig) {
486494
typ := g.get_type_from_var(var)
487495
if typ.is_int() {
@@ -601,14 +609,16 @@ g.expr
601609
ast.InfixExpr {}
602610
ast.IsRefType {}
603611
ast.MapInit {}
604-
ast.MatchExpr {}
605612
ast.OrExpr {}
606613
ast.ParExpr {}
607614
ast.RangeExpr {}
608615
ast.SelectExpr {}
609616
ast.SqlExpr {}
610617
ast.TypeNode {}
611618
*/
619+
ast.MatchExpr {
620+
g.gen_match_expr(expr)
621+
}
612622
ast.TypeOf {
613623
g.gen_typeof_expr(expr, newline)
614624
}
@@ -1045,6 +1055,9 @@ fn (mut g Gen) expr(node ast.Expr) {
10451055
ast.GoExpr {
10461056
g.v_error('native backend doesnt support threads yet', node.pos)
10471057
}
1058+
ast.MatchExpr {
1059+
g.gen_match_expr(node)
1060+
}
10481061
else {
10491062
g.n_error('expr: unhandled node type: $node.type_name()')
10501063
}

vlib/v/gen/native/tests/match.vv

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
fn match_for_test() { // from for_loops_2_test.v
2+
mut a := 2
3+
mut b := 0
4+
for {
5+
match a {
6+
2 {
7+
println('a == 2')
8+
a = 0
9+
continue
10+
}
11+
0 {
12+
println('a == 0')
13+
a = 5
14+
b++
15+
break
16+
}
17+
else {
18+
println('unexpected branch')
19+
break
20+
}
21+
}
22+
}
23+
assert a == 5
24+
assert b == 1
25+
println(b)
26+
println(a)
27+
}
28+
29+
fn ifexpr_match_test() { // from if_expr_with_nested_match_expr_test.v
30+
b := true // this is needed. why?
31+
a := if b {
32+
match 5 {
33+
5 { 0 }
34+
else { 1 }
35+
}
36+
} else {
37+
3
38+
}
39+
assert a == 0
40+
println(a)
41+
}
42+
43+
fn integer_match_test() { // from match_test.v
44+
mut a := 3
45+
mut b := 0
46+
match a {
47+
2 {
48+
println('two')
49+
}
50+
3 {
51+
println('three')
52+
b = 3
53+
}
54+
4 {
55+
println('four')
56+
}
57+
else {
58+
println('???')
59+
}
60+
}
61+
assert b == 3
62+
assert match 2 {
63+
1 { 2 }
64+
2 { 3 }
65+
else { 5 }
66+
} == 3
67+
assert match 0 {
68+
1 { 2 }
69+
2 { 3 }
70+
else { 5 }
71+
} == 5
72+
assert match 1 {
73+
2 { 0 }
74+
else { 5 }
75+
} == 5
76+
a = 0
77+
match 2 {
78+
0 {
79+
a = 1
80+
}
81+
1 {
82+
a = 2
83+
}
84+
else {
85+
a = 3
86+
}
87+
}
88+
assert a == 3
89+
a = 0
90+
/* match 1 {
91+
0 {
92+
a = 1
93+
}
94+
1 {
95+
a = 2
96+
a = a + 2
97+
a = a + 2
98+
}
99+
else {}
100+
}
101+
assert a == 6
102+
a = 0
103+
match 1 {
104+
0 {}
105+
else { a = -2 }
106+
}
107+
assert a == -2*/
108+
}
109+
110+
fn multiple_test() { // from match_test.v
111+
a := 9
112+
match a {
113+
1, 2, 3 { println('1-3') }
114+
4, 5 { println('4-5') }
115+
6...9 { println('6-9') }
116+
else { println('other') }
117+
}
118+
}
119+
120+
fn main() {
121+
match_for_test()
122+
ifexpr_match_test()
123+
integer_match_test()
124+
multiple_test()
125+
}

vlib/v/gen/native/tests/match.vv.out

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
a == 2
2+
a == 0
3+
1
4+
5
5+
0
6+
three
7+
6-9

0 commit comments

Comments
 (0)