js: match support (#11269)
parent
b80777df4b
commit
dd486bb0fb
|
@ -713,7 +713,7 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
||||||
g.gen_map_init_expr(node)
|
g.gen_map_init_expr(node)
|
||||||
}
|
}
|
||||||
ast.MatchExpr {
|
ast.MatchExpr {
|
||||||
// TODO
|
g.match_expr(node)
|
||||||
}
|
}
|
||||||
ast.None {
|
ast.None {
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -801,8 +801,10 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
||||||
g.gen_struct_init(node)
|
g.gen_struct_init(node)
|
||||||
}
|
}
|
||||||
ast.TypeNode {
|
ast.TypeNode {
|
||||||
// skip: JS has no types
|
typ := g.unwrap_generic(node.typ)
|
||||||
// TODO maybe?
|
sym := g.table.get_type_symbol(typ)
|
||||||
|
name := sym.name.replace_once('${g.ns.name}.', '')
|
||||||
|
g.write('$name')
|
||||||
}
|
}
|
||||||
ast.Likely {
|
ast.Likely {
|
||||||
g.write('(')
|
g.write('(')
|
||||||
|
@ -1734,6 +1736,249 @@ fn (mut g JsGen) gen_lock_expr(node ast.LockExpr) {
|
||||||
// TODO: implement this
|
// TODO: implement this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g JsGen) need_tmp_var_in_match(node ast.MatchExpr) bool {
|
||||||
|
if node.is_expr && node.return_type != ast.void_type && node.return_type != 0 {
|
||||||
|
sym := g.table.get_type_symbol(node.return_type)
|
||||||
|
if sym.kind == .multi_return {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for branch in node.branches {
|
||||||
|
if branch.stmts.len > 1 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if branch.stmts.len == 1 {
|
||||||
|
if branch.stmts[0] is ast.ExprStmt {
|
||||||
|
stmt := branch.stmts[0] as ast.ExprStmt
|
||||||
|
if stmt.expr is ast.CallExpr || stmt.expr is ast.IfExpr
|
||||||
|
|| stmt.expr is ast.MatchExpr || (stmt.expr is ast.IndexExpr
|
||||||
|
&& (stmt.expr as ast.IndexExpr).or_expr.kind != .absent) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g JsGen) match_expr_classic(node ast.MatchExpr, is_expr bool, cond_var string, tmp_var string) {
|
||||||
|
type_sym := g.table.get_type_symbol(node.cond_type)
|
||||||
|
for j, branch in node.branches {
|
||||||
|
is_last := j == node.branches.len - 1
|
||||||
|
if branch.is_else || (node.is_expr && is_last && tmp_var.len == 0) {
|
||||||
|
if node.branches.len > 1 {
|
||||||
|
if is_expr && tmp_var.len == 0 {
|
||||||
|
// TODO too many branches. maybe separate ?: matches
|
||||||
|
g.write(' : ')
|
||||||
|
} else {
|
||||||
|
g.writeln('')
|
||||||
|
g.write_v_source_line_info(branch.pos)
|
||||||
|
g.writeln('else {')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if j > 0 {
|
||||||
|
if is_expr && tmp_var.len == 0 {
|
||||||
|
g.write(' : ')
|
||||||
|
} else {
|
||||||
|
g.writeln('')
|
||||||
|
g.write_v_source_line_info(branch.pos)
|
||||||
|
g.write('else ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if is_expr && tmp_var.len == 0 {
|
||||||
|
g.write('(')
|
||||||
|
} else {
|
||||||
|
if j == 0 {
|
||||||
|
g.writeln('')
|
||||||
|
}
|
||||||
|
g.write_v_source_line_info(branch.pos)
|
||||||
|
g.write('if (')
|
||||||
|
}
|
||||||
|
for i, expr in branch.exprs {
|
||||||
|
if i > 0 {
|
||||||
|
g.write(' || ')
|
||||||
|
}
|
||||||
|
match type_sym.kind {
|
||||||
|
.array {
|
||||||
|
g.write('vEq($cond_var, ')
|
||||||
|
g.expr(expr)
|
||||||
|
g.write(')')
|
||||||
|
}
|
||||||
|
.array_fixed {
|
||||||
|
g.write('vEq($cond_var, ')
|
||||||
|
g.expr(expr)
|
||||||
|
g.write(')')
|
||||||
|
}
|
||||||
|
.map {
|
||||||
|
g.write('vEq($cond_var, ')
|
||||||
|
g.expr(expr)
|
||||||
|
g.write(')')
|
||||||
|
}
|
||||||
|
.string {
|
||||||
|
g.write('vEq($cond_var, ')
|
||||||
|
g.expr(expr)
|
||||||
|
g.write(')')
|
||||||
|
}
|
||||||
|
.struct_ {
|
||||||
|
g.write('vEq($cond_var, ')
|
||||||
|
g.expr(expr)
|
||||||
|
g.write(')')
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if expr is ast.RangeExpr {
|
||||||
|
// if type is unsigned and low is 0, check is unneeded
|
||||||
|
mut skip_low := false
|
||||||
|
if expr.low is ast.IntegerLiteral {
|
||||||
|
if node.cond_type in [ast.u16_type, ast.u32_type, ast.u64_type]
|
||||||
|
&& expr.low.val == '0' {
|
||||||
|
skip_low = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.write('(')
|
||||||
|
if !skip_low {
|
||||||
|
g.write('$cond_var >= ')
|
||||||
|
g.expr(expr.low)
|
||||||
|
g.write(' && ')
|
||||||
|
}
|
||||||
|
g.write('$cond_var <= ')
|
||||||
|
g.expr(expr.high)
|
||||||
|
g.write(')')
|
||||||
|
} else {
|
||||||
|
g.write('vEq($cond_var,')
|
||||||
|
g.expr(expr)
|
||||||
|
g.write(')')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if is_expr && tmp_var.len == 0 {
|
||||||
|
g.write(') ? ')
|
||||||
|
} else {
|
||||||
|
g.writeln(') {')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.stmts_with_tmp_var(branch.stmts, tmp_var)
|
||||||
|
if !g.inside_ternary && node.branches.len >= 1 {
|
||||||
|
g.write('}')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g JsGen) match_expr(node ast.MatchExpr) {
|
||||||
|
if node.cond_type == 0 {
|
||||||
|
g.writeln('// match 0')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
prev := g.inside_ternary
|
||||||
|
need_tmp_var := g.need_tmp_var_in_match(node)
|
||||||
|
is_expr := (node.is_expr && node.return_type != ast.void_type) || g.inside_ternary
|
||||||
|
mut cond_var := ''
|
||||||
|
mut tmp_var := ''
|
||||||
|
if is_expr && !need_tmp_var {
|
||||||
|
g.inside_ternary = true
|
||||||
|
}
|
||||||
|
|
||||||
|
cond_var = g.new_tmp_var()
|
||||||
|
g.write('let $cond_var = ')
|
||||||
|
g.expr(node.cond)
|
||||||
|
g.write(';')
|
||||||
|
if need_tmp_var {
|
||||||
|
tmp_var = g.new_tmp_var()
|
||||||
|
g.writeln('let $tmp_var = undefined;')
|
||||||
|
}
|
||||||
|
if is_expr && !need_tmp_var {
|
||||||
|
g.write('(')
|
||||||
|
}
|
||||||
|
if node.is_sum_type {
|
||||||
|
g.match_expr_sumtype(node, is_expr, cond_var, tmp_var)
|
||||||
|
} else {
|
||||||
|
g.match_expr_classic(node, is_expr, cond_var, tmp_var)
|
||||||
|
}
|
||||||
|
if need_tmp_var {
|
||||||
|
g.write('$tmp_var')
|
||||||
|
}
|
||||||
|
if is_expr && !need_tmp_var {
|
||||||
|
g.write(')')
|
||||||
|
g.inside_ternary = prev
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g JsGen) stmts_with_tmp_var(stmts []ast.Stmt, tmp_var string) {
|
||||||
|
g.inc_indent()
|
||||||
|
if g.inside_ternary {
|
||||||
|
g.write('(')
|
||||||
|
}
|
||||||
|
for i, stmt in stmts {
|
||||||
|
if i == stmts.len - 1 && tmp_var != '' {
|
||||||
|
g.write('$tmp_var = ')
|
||||||
|
g.stmt(stmt)
|
||||||
|
g.writeln('')
|
||||||
|
} else {
|
||||||
|
g.stmt(stmt)
|
||||||
|
}
|
||||||
|
if g.inside_ternary && i < stmts.len - 1 {
|
||||||
|
g.write(',')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.dec_indent()
|
||||||
|
if g.inside_ternary {
|
||||||
|
g.write(')')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g JsGen) match_expr_sumtype(node ast.MatchExpr, is_expr bool, cond_var string, tmp_var string) {
|
||||||
|
for j, branch in node.branches {
|
||||||
|
mut sumtype_index := 0
|
||||||
|
for {
|
||||||
|
is_last := j == node.branches.len - 1
|
||||||
|
sym := g.table.get_type_symbol(node.cond_type)
|
||||||
|
if branch.is_else || (node.is_expr && is_last && tmp_var.len == 0) {
|
||||||
|
if is_expr && tmp_var.len == 0 {
|
||||||
|
g.write(' : ')
|
||||||
|
} else {
|
||||||
|
g.writeln('')
|
||||||
|
g.writeln('else {')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if j > 0 || sumtype_index > 0 {
|
||||||
|
if is_expr && tmp_var.len == 0 {
|
||||||
|
g.write(' : ')
|
||||||
|
} else {
|
||||||
|
g.write('else ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_expr && tmp_var.len == 0 {
|
||||||
|
g.write('(')
|
||||||
|
} else {
|
||||||
|
g.write('if (')
|
||||||
|
}
|
||||||
|
g.write(cond_var)
|
||||||
|
if sym.kind == .sum_type {
|
||||||
|
g.write(' instanceof ')
|
||||||
|
g.expr(branch.exprs[sumtype_index])
|
||||||
|
} else {
|
||||||
|
panic('TODO: Generate match for interfaces')
|
||||||
|
}
|
||||||
|
if is_expr && tmp_var.len == 0 {
|
||||||
|
g.write(') ? ')
|
||||||
|
} else {
|
||||||
|
g.writeln(') {')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.stmts_with_tmp_var(branch.stmts, tmp_var)
|
||||||
|
if !g.inside_ternary {
|
||||||
|
g.writeln('}')
|
||||||
|
}
|
||||||
|
sumtype_index++
|
||||||
|
if branch.exprs.len == 0 || sumtype_index == branch.exprs.len {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
|
fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
|
||||||
if node.is_comptime {
|
if node.is_comptime {
|
||||||
g.comp_if(node)
|
g.comp_if(node)
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Vec2d(42,43)
|
||||||
|
Vec2d(46,74,21)
|
||||||
|
life
|
||||||
|
V is running on JS
|
|
@ -0,0 +1,57 @@
|
||||||
|
struct Vec2d {
|
||||||
|
x int
|
||||||
|
y int
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Vec3d {
|
||||||
|
x int
|
||||||
|
y int
|
||||||
|
z int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Vec = Vec2d | Vec3d
|
||||||
|
|
||||||
|
fn match_vec(v Vec) {
|
||||||
|
match v {
|
||||||
|
Vec2d {
|
||||||
|
println('Vec2d($v.x,$v.y)')
|
||||||
|
}
|
||||||
|
Vec3d {
|
||||||
|
println('Vec2d($v.x,$v.y,$v.z)')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn match_classic_num() {
|
||||||
|
match 42 {
|
||||||
|
0 {
|
||||||
|
assert (false)
|
||||||
|
}
|
||||||
|
1 {
|
||||||
|
assert (false)
|
||||||
|
}
|
||||||
|
42 {
|
||||||
|
println('life')
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert (false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn match_classic_string() {
|
||||||
|
os := 'JS'
|
||||||
|
print('V is running on ')
|
||||||
|
match os {
|
||||||
|
'darwin' { println('macOS.') }
|
||||||
|
'linux' { println('Linux.') }
|
||||||
|
else { println(os) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match_vec(Vec2d{42, 43})
|
||||||
|
match_vec(Vec3d{46, 74, 21})
|
||||||
|
match_classic_num()
|
||||||
|
match_classic_string()
|
||||||
|
}
|
Loading…
Reference in New Issue