From 2c5a2c86c178f35d51d61f0aa008f2b98340a180 Mon Sep 17 00:00:00 2001 From: SheatNoisette <45624871+SheatNoisette@users.noreply.github.com> Date: Sat, 3 Jan 2026 07:32:26 +0100 Subject: [PATCH] wasm: support basic match keyword handling (#26246) --- vlib/v/gen/wasm/gen.v | 86 ++++++++++++++- vlib/v/gen/wasm/mem.v | 3 + vlib/v/gen/wasm/tests/match.vv | 108 +++++++++++++++++++ vlib/v/gen/wasm/tests/match.vv.out | 13 +++ vlib/v/gen/wasm/tests/match_ranges.vv | 126 ++++++++++++++++++++++ vlib/v/gen/wasm/tests/match_ranges.vv.out | 11 ++ 6 files changed, 346 insertions(+), 1 deletion(-) create mode 100644 vlib/v/gen/wasm/tests/match.vv create mode 100644 vlib/v/gen/wasm/tests/match.vv.out create mode 100644 vlib/v/gen/wasm/tests/match_ranges.vv create mode 100644 vlib/v/gen/wasm/tests/match_ranges.vv.out diff --git a/vlib/v/gen/wasm/gen.v b/vlib/v/gen/wasm/gen.v index 449dce4ed..bd6f2d80c 100644 --- a/vlib/v/gen/wasm/gen.v +++ b/vlib/v/gen/wasm/gen.v @@ -553,6 +553,90 @@ pub fn (mut g Gen) if_expr(ifexpr ast.IfExpr, expected ast.Type, existing_rvars g.if_branch(ifexpr, expected, params, 0, existing_rvars) } +pub fn (mut g Gen) match_expr(node ast.MatchExpr, expected ast.Type, existing_rvars []Var) { + results := if expected == ast.void_type { + []wasm.ValType{} + } else if existing_rvars.len == 0 { + g.unpack_type(expected).map(g.get_wasm_type(it)) + } else { + g.unpack_type(expected).filter(!g.is_param_type(it)).map(g.get_wasm_type(it)) + } + g.match_branch(node, expected, results, 0, existing_rvars) +} + +fn (mut g Gen) match_branch(node ast.MatchExpr, expected ast.Type, unpacked_params []wasm.ValType, branch_idx int, existing_rvars []Var) { + if branch_idx >= node.branches.len { + return + } + + branch := node.branches[branch_idx] + mut is_last_branch := branch_idx + 1 >= node.branches.len + mut has_else := branch.is_else + + if has_else { + if branch.stmts.len > 0 { + g.rvar_expr_stmts(branch.stmts, expected, existing_rvars) + } + return + } + + if branch.exprs.len > 0 { + g.match_branch_exprs(node, expected, unpacked_params, branch_idx, 0, existing_rvars, + branch) + } else { + if branch.stmts.len > 0 { + g.rvar_expr_stmts(branch.stmts, expected, existing_rvars) + } + if !is_last_branch { + g.match_branch(node, expected, unpacked_params, branch_idx + 1, existing_rvars) + } + } +} + +fn (mut g Gen) match_branch_exprs(node ast.MatchExpr, expected ast.Type, unpacked_params []wasm.ValType, branch_idx int, expr_idx int, existing_rvars []Var, branch ast.MatchBranch) { + if expr_idx >= branch.exprs.len { + return + } + + mut is_last_branch := branch_idx + 1 >= node.branches.len + mut is_last_expr := expr_idx + 1 >= branch.exprs.len + + wasm_type := g.as_numtype(g.get_wasm_type(node.cond_type)) + + expr := branch.exprs[expr_idx] + + if expr is ast.RangeExpr { + is_signed := node.cond_type.is_signed() + + g.expr(node.cond, node.cond_type) + g.expr(expr.high, node.cond_type) + g.func.le(wasm_type, is_signed) + } else { + g.expr(node.cond, node.cond_type) + g.expr(expr, node.cond_type) + g.func.eq(wasm_type) + } + + blk := g.func.c_if([], unpacked_params) + { + if branch.stmts.len > 0 { + g.rvar_expr_stmts(branch.stmts, expected, existing_rvars) + } + } + { + g.func.c_else(blk) + if is_last_expr { + if !is_last_branch { + g.match_branch(node, expected, unpacked_params, branch_idx + 1, existing_rvars) + } + } else { + g.match_branch_exprs(node, expected, unpacked_params, branch_idx, expr_idx + 1, + existing_rvars, branch) + } + } + g.func.c_end(blk) +} + pub fn (mut g Gen) call_expr(node ast.CallExpr, expected ast.Type, existing_rvars []Var) { mut wasm_ns := ?string(none) mut name := node.name @@ -850,7 +934,7 @@ pub fn (mut g Gen) expr(node ast.Expr, expected ast.Type) { g.cast(node.typ, expected) } ast.MatchExpr { - g.w_error('wasm backend does not support match expressions yet') + g.match_expr(node, expected, []) } ast.EnumVal { type_name := g.table.get_type_name(node.typ) diff --git a/vlib/v/gen/wasm/mem.v b/vlib/v/gen/wasm/mem.v index 51eee10ba..5fe912250 100644 --- a/vlib/v/gen/wasm/mem.v +++ b/vlib/v/gen/wasm/mem.v @@ -654,6 +654,9 @@ pub fn (mut g Gen) set_with_multi_expr(init ast.Expr, expected ast.Type, existin ast.IfExpr { g.if_expr(init, expected, existing_rvars) } + ast.MatchExpr { + g.match_expr(init, expected, existing_rvars) + } ast.CallExpr { g.call_expr(init, expected, existing_rvars) } diff --git a/vlib/v/gen/wasm/tests/match.vv b/vlib/v/gen/wasm/tests/match.vv new file mode 100644 index 000000000..d63aa1387 --- /dev/null +++ b/vlib/v/gen/wasm/tests/match.vv @@ -0,0 +1,108 @@ +enum BasicTestEnum { + first_element + second_element + other_element +} + +fn function_matches(value u8) { + match value { + 42 { + println('function_matches: OK') + } + else { + println('function_matches: Error') + } + } +} + +fn main() { + a := 1 + match a { + 1 { println('1') } + else { println('other') } + } + + b := 2 + match b { + 1 { println('1') } + 2 { println('2') } + 3 { println('3') } + 4 { println('4') } + 5 { println('5') } + 6 { println('6') } + 7 { println('7') } + 8 { println('8') } + 9 { println('9') } + else { println('other') } + } + + c := 3 + match c { + 1, 2 { println('1 or 2') } + else { println('other') } + } + + d := match a { + 1 { 10 } + else { 30 } + } + println(d) + + e := match b { + 1 { 100 } + 2 { 200 } + 3, 4 { 340 } + else { 300 } + } + println(e) + + println(match c { + 1, 2 { i64(1000) } + else { i64(2000) } + }) + + println('Enum matches -------') + + f := BasicTestEnum.first_element + println(match f { + .first_element { 'First Element' } + .second_element { 'Second Element' } + else { 'Other Element' } + }) + + println('Bool matches -------') + + println(match true { + true { + 'OK' + } + else { + 'ERROR' + } + }) + + g := false + println(match g { + false { + 'OK' + } + else { + 'ERROR' + } + }) + + println('Function calling matches -------') + function_matches(42) + + /* + println("Strings matches -------") + + // This doesn't work yet because string comparison is not ready ( + h := 'Hello' + println(match h { + 'NotHello' { 'Not Hello string' } + 'Hello' { 'Hello string' } + else { 'Unknown' } + }) + */ +} diff --git a/vlib/v/gen/wasm/tests/match.vv.out b/vlib/v/gen/wasm/tests/match.vv.out new file mode 100644 index 000000000..f95430f8e --- /dev/null +++ b/vlib/v/gen/wasm/tests/match.vv.out @@ -0,0 +1,13 @@ +1 +2 +other +10 +200 +2000 +Enum matches ------- +First Element +Bool matches ------- +OK +OK +Function calling matches ------- +function_matches: OK \ No newline at end of file diff --git a/vlib/v/gen/wasm/tests/match_ranges.vv b/vlib/v/gen/wasm/tests/match_ranges.vv new file mode 100644 index 000000000..2c7929775 --- /dev/null +++ b/vlib/v/gen/wasm/tests/match_ranges.vv @@ -0,0 +1,126 @@ +fn main() { + g := 32 + result1 := match g { + 1...64 { + 'Right' + } + else { + 'Wrong' + } + } + println(result1) + + h := 100 + result2 := match h { + 1...64 { + 'Wrong' + } + else { + 'Right' + } + } + println(result2) + + i := 1 + result3 := match i { + 1...10 { + 'Right' + } + else { + 'Wrong' + } + } + println(result3) + + j := 10 + result4 := match j { + 1...10 { + 'Right' + } + else { + 'Wrong' + } + } + println(result4) + + k := 50 + result5 := match k { + 1...32 { + 'Wrong' + } + 33...64 { + 'Right' + } + else { + 'Wrong' + } + } + println(result5) + + n := 15 + result6 := match n { + 1...10 { + 10 + } + 11...20 { + 20 + } + else { + 0 + } + } + println(result6) + + o := i64(500) + result7 := match o { + i64(1)...i64(1000) { + 'Right' + } + else { + 'Wrong' + } + } + println(result7) + + p := u32(50) + result8 := match p { + u32(0)...u32(100) { + 'Right' + } + else { + 'Wrong' + } + } + println(result8) + + r := -5 + result9 := match r { + -10...-1 { + 'Right' + } + else { + 'Wrong' + } + } + println(result9) + + s := 0 + result10 := match s { + -10...25 { + 'Right' + } + else { + 'Wrong' + } + } + println(result10) + + println(match 1234 { + -1200...1 { + 'Wrong' + } + else { + 'Right' + } + }) +} diff --git a/vlib/v/gen/wasm/tests/match_ranges.vv.out b/vlib/v/gen/wasm/tests/match_ranges.vv.out new file mode 100644 index 000000000..f2285819c --- /dev/null +++ b/vlib/v/gen/wasm/tests/match_ranges.vv.out @@ -0,0 +1,11 @@ +Right +Right +Right +Right +Right +20 +Right +Right +Right +Right +Right \ No newline at end of file -- 2.39.5