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

native: match expr/stmt (#15537)

This commit is contained in:
lemon 2022-08-26 21:18:02 +09:00 committed by GitHub
parent 02a47f42f3
commit e5c53cf412
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 219 additions and 1 deletions

View File

@ -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()
}

View File

@ -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()')
}

View File

@ -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()
}

View File

@ -0,0 +1,7 @@
a == 2
a == 0
1
5
0
three
6-9