gen: separate sumtype from classic match (#6547)

pull/6562/head
Enzo 2020-10-04 19:50:23 +02:00 committed by GitHub
parent 2622070f14
commit 35a83464d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 162 additions and 122 deletions

View File

@ -2671,17 +2671,6 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) {
g.inside_ternary++ g.inside_ternary++
// g.write('/* EM ret type=${g.typ(node.return_type)} expected_type=${g.typ(node.expected_type)} */') // g.write('/* EM ret type=${g.typ(node.return_type)} expected_type=${g.typ(node.expected_type)} */')
} }
type_sym := g.table.get_type_symbol(node.cond_type)
if node.is_sum_type {
g.match_sumtype_exprs << node.cond
g.match_sumtype_syms << type_sym
}
defer {
if node.is_sum_type {
g.match_sumtype_exprs.pop()
g.match_sumtype_syms.pop()
}
}
cur_line := if is_expr { cur_line := if is_expr {
g.empty_line = true g.empty_line = true
g.go_before_stmt(0) g.go_before_stmt(0)
@ -2693,12 +2682,101 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) {
g.expr(node.cond) g.expr(node.cond)
g.writeln(';') g.writeln(';')
g.write(cur_line) g.write(cur_line)
// TODO refactor, there are far too many indents if node.is_sum_type {
g.match_expr_sumtype(node, is_expr, cond_var)
} else {
g.match_expr_classic(node, is_expr, cond_var)
}
if is_expr {
g.decrement_inside_ternary()
}
}
fn (mut g Gen) match_expr_sumtype(node ast.MatchExpr, is_expr bool, cond_var string) {
type_sym := g.table.get_type_symbol(node.cond_type)
g.match_sumtype_exprs << node.cond
g.match_sumtype_syms << type_sym
defer {
g.match_sumtype_exprs.pop()
g.match_sumtype_syms.pop()
}
for j, branch in node.branches { for j, branch in node.branches {
mut sumtype_index := 0 mut sumtype_index := 0
// iterates through all types in sumtype branches // iterates through all types in sumtype branches
// it loops only once for other types
for { for {
is_last := j == node.branches.len - 1
if branch.is_else || (node.is_expr && is_last) {
if is_expr {
// TODO too many branches. maybe separate ?: matches
g.write(' : ')
} else {
g.writeln(' else {')
}
} else {
if j > 0 || sumtype_index > 0 {
if is_expr {
g.write(' : ')
} else {
g.write(' else ')
}
}
if is_expr {
g.write('(')
} else {
g.write('if (')
}
g.write(cond_var)
sym := g.table.get_type_symbol(node.cond_type)
// branch_sym := g.table.get_type_symbol(branch.typ)
if sym.kind == .sum_type {
dot_or_ptr := if node.cond_type.is_ptr() { '->' } else { '.' }
g.write(dot_or_ptr)
g.write('typ == ')
} else if sym.kind == .interface_ {
// g.write('._interface_idx == _${sym.name}_${branch_sym} ')
g.write('._interface_idx == ')
}
g.expr(branch.exprs[sumtype_index])
if is_expr {
g.write(') ? ')
} else {
g.writeln(') {')
}
}
// g.writeln('/* M sum_type=$node.is_sum_type is_expr=$node.is_expr exp_type=${g.typ(node.expected_type)}*/')
if !branch.is_else && !node.is_expr {
// Use the nodes in the expr to generate `it` variable.
type_expr := branch.exprs[sumtype_index]
if type_expr !is ast.Type {
verror('match sum type')
}
it_type := g.typ((type_expr as ast.Type).typ)
// g.writeln('$it_type* it = ($it_type*)${tmp}.obj; // ST it')
g.write('\t$it_type* it = ($it_type*)')
g.write(cond_var)
dot_or_ptr := if node.cond_type.is_ptr() { '->' } else { '.' }
g.write(dot_or_ptr)
g.writeln('_object; // ST it')
if node.var_name.len > 0 {
// for now we just copy it
g.writeln('\t$it_type* $node.var_name = it;')
}
}
g.stmts(branch.stmts)
if g.inside_ternary == 0 {
g.write('}')
}
sumtype_index++
if branch.exprs.len == 0 || sumtype_index == branch.exprs.len {
break
}
}
}
}
fn (mut g Gen) match_expr_classic(node ast.MatchExpr, is_expr bool, cond_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 is_last := j == node.branches.len - 1
if branch.is_else || (node.is_expr && is_last) { if branch.is_else || (node.is_expr && is_last) {
if node.branches.len > 1 { if node.branches.len > 1 {
@ -2722,22 +2800,6 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) {
} else { } else {
g.write('if (') g.write('if (')
} }
if node.is_sum_type && branch.exprs.len > 0 {
// the multiple expressions of sumtypes are treated by the immediate `for` loop
// TODO move sumtype match to there own function
g.write(cond_var)
sym := g.table.get_type_symbol(node.cond_type)
// branch_sym := g.table.get_type_symbol(branch.typ)
if sym.kind == .sum_type {
dot_or_ptr := if node.cond_type.is_ptr() { '->' } else { '.' }
g.write(dot_or_ptr)
g.write('typ == ')
} else if sym.kind == .interface_ {
// g.write('._interface_idx == _${sym.name}_${branch_sym} ')
g.write('._interface_idx == ')
}
g.expr(branch.exprs[sumtype_index])
} else {
for i, expr in branch.exprs { for i, expr in branch.exprs {
if i > 0 { if i > 0 {
g.write(' || ') g.write(' || ')
@ -2778,47 +2840,16 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) {
g.expr(expr) g.expr(expr)
} }
} }
}
if is_expr { if is_expr {
g.write(') ? ') g.write(') ? ')
} else { } else {
g.writeln(') {') g.writeln(') {')
} }
} }
// g.writeln('/* M sum_type=$node.is_sum_type is_expr=$node.is_expr exp_type=${g.typ(node.expected_type)}*/')
if node.is_sum_type && branch.exprs.len > 0 {
if !node.is_expr {
// Use the nodes in the expr to generate `it` variable.
type_expr := branch.exprs[sumtype_index]
if type_expr is ast.Type {
it_type := g.typ(type_expr.typ)
// g.writeln('$it_type* it = ($it_type*)${tmp}.obj; // ST it')
g.write('\t$it_type* it = ($it_type*)')
g.write(cond_var)
dot_or_ptr := if node.cond_type.is_ptr() { '->' } else { '.' }
g.write(dot_or_ptr)
g.writeln('_object; // ST it')
if node.var_name.len > 0 {
// for now we just copy it
g.writeln('\t$it_type* $node.var_name = it;')
}
} else {
verror('match sum type')
}
}
sumtype_index++
}
g.stmts(branch.stmts) g.stmts(branch.stmts)
if g.inside_ternary == 0 && node.branches.len > 1 { if g.inside_ternary == 0 && node.branches.len > 1 {
g.write('}') g.write('}')
} }
if !node.is_sum_type || branch.exprs.len == 0 || sumtype_index == branch.exprs.len {
break
}
}
}
if is_expr {
g.decrement_inside_ternary()
} }
} }
@ -3008,11 +3039,7 @@ fn (mut g Gen) ident(node ast.Ident) {
fn (mut g Gen) should_write_asterisk_due_to_match_sumtype(expr ast.Expr) bool { fn (mut g Gen) should_write_asterisk_due_to_match_sumtype(expr ast.Expr) bool {
if expr is ast.Ident { if expr is ast.Ident {
typ := if expr.info is ast.IdentVar { (expr.info as ast.IdentVar).typ } else { (expr.info as ast.IdentFn).typ } typ := if expr.info is ast.IdentVar { (expr.info as ast.IdentVar).typ } else { (expr.info as ast.IdentFn).typ }
return if typ.is_ptr() && g.match_sumtype_has_no_struct_and_contains(expr) { return typ.is_ptr() && g.match_sumtype_has_no_struct_and_contains(expr)
true
} else {
false
}
} else { } else {
return false return false
} }

View File

@ -40,15 +40,9 @@ pub mut:
} }
fn (f &Fn) method_equals(o &Fn) bool { fn (f &Fn) method_equals(o &Fn) bool {
return f.params[1..].equals(o.params[1..]) && return f.params[1..].equals(o.params[1..]) && f.return_type == o.return_type && f.return_type_source_name ==
f.return_type == o.return_type && o.return_type_source_name && f.is_variadic == o.is_variadic && f.language == o.language &&
f.return_type_source_name == o.return_type_source_name && f.is_generic == o.is_generic && f.is_pub == o.is_pub && f.mod == o.mod && f.name == o.name
f.is_variadic == o.is_variadic &&
f.language == o.language &&
f.is_generic == o.is_generic &&
f.is_pub == o.is_pub &&
f.mod == o.mod &&
f.name == o.name
} }
pub struct Param { pub struct Param {
@ -62,11 +56,8 @@ pub:
} }
fn (p &Param) equals(o &Param) bool { fn (p &Param) equals(o &Param) bool {
return p.name == o.name return p.name == o.name && p.is_mut == o.is_mut && p.typ == o.typ && p.type_source_name ==
&& p.is_mut == o.is_mut o.type_source_name && p.is_hidden == o.is_hidden
&& p.typ == o.typ
&& p.type_source_name == o.type_source_name
&& p.is_hidden == o.is_hidden
} }
fn (p []Param) equals(o []Param) bool { fn (p []Param) equals(o []Param) bool {

View File

@ -165,6 +165,20 @@ fn test_sum_type_name() {
assert f(a) == 'A1' assert f(a) == 'A1'
} }
fn f_else(s Sum) string {
match s {
A1 { return typeof(s) }
else { return '' }
}
}
fn test_sum_type_else() {
a := A1{
pos: 22
}
assert f_else(a) == 'A1'
}
struct Alfa { struct Alfa {
char rune = `a` char rune = `a`
} }
@ -183,11 +197,13 @@ fn (b Bravo) letter() rune {
return b.char return b.char
} }
struct Charlie {} struct Charlie {
char rune = `c`
}
type NATOAlphabet = Alfa | Bravo | Charlie type NATOAlphabet = Alfa | Bravo | Charlie
fn test_match_sum_type_multiple_type() { fn test_match_sumtype_multiple_types() {
a := Alfa{} a := Alfa{}
match NATOAlphabet(a) as l { match NATOAlphabet(a) as l {
Alfa, Bravo { Alfa, Bravo {
@ -199,4 +215,10 @@ fn test_match_sum_type_multiple_type() {
assert false assert false
} }
} }
// test one branch
match NATOAlphabet(a) as l {
Alfa, Bravo, Charlie {
assert l.char == `a`
}
}
} }