gen: access fields in multi-type sumtype match (#6541)

pull/6548/head
Enzo 2020-10-03 11:19:43 +02:00 committed by GitHub
parent 7b034a54e3
commit 677b0ba2d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 123 additions and 117 deletions

View File

@ -97,14 +97,7 @@ fn (mut f Fmt) find_comment(line_nr int) {
pub fn (mut f Fmt) write(s string) {
if !f.buffering {
if f.indent > 0 && f.empty_line {
if f.indent < tabs.len {
f.out.write(tabs[f.indent])
} else {
// too many indents, do it the slow way:
for _ in 0 .. f.indent {
f.out.write('\t')
}
}
f.write_indent()
f.line_len += f.indent * 4
}
f.out.write(s)
@ -133,8 +126,7 @@ pub fn (mut f Fmt) writeln(s string) {
f.precedences = []int{}
}
if f.indent > 0 && f.empty_line {
// println(f.indent.str() + s)
f.out.write(tabs[f.indent])
f.write_indent()
}
f.out.writeln(if empty_fifo {
''
@ -145,6 +137,17 @@ pub fn (mut f Fmt) writeln(s string) {
f.line_len = 0
}
fn (mut f Fmt) write_indent() {
if f.indent < tabs.len {
f.out.write(tabs[f.indent])
} else {
// too many indents, do it the slow way:
for _ in 0 .. f.indent {
f.out.write('\t')
}
}
}
// adjustments that can only be done after full line is processed. For now
// only prevents line breaks if everything fits in max_len[last] by increasing
// penalties to maximum
@ -1129,11 +1132,14 @@ pub fn (mut f Fmt) wrap_long_line(penalty int, add_indent bool) bool {
if f.out.buf[f.out.buf.len - 1] == ` ` {
f.out.go_back(1)
}
f.write('\n' + tabs[f.indent + if add_indent {
1
} else {
0
}])
f.write('\n')
if add_indent {
f.indent++
}
f.write_indent()
if add_indent {
f.indent--
}
f.line_len = 0
return true
}

View File

@ -2693,32 +2693,38 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) {
g.expr(node.cond)
g.writeln(';')
g.write(cur_line)
// TODO refactor, there are far too many indents
for j, branch in node.branches {
is_last := j == node.branches.len - 1
if branch.is_else || (node.is_expr && is_last) {
if node.branches.len > 1 {
if is_expr {
// TODO too many branches. maybe separate ?: matches
g.write(' : ')
} else {
g.writeln(' else {')
mut sumtype_index := 0
// iterates through all types in sumtype branches
// it loops only once for other types
for {
is_last := j == node.branches.len - 1
if branch.is_else || (node.is_expr && is_last) {
if node.branches.len > 1 {
if is_expr {
// TODO too many branches. maybe separate ?: matches
g.write(' : ')
} else {
g.writeln(' else {')
}
}
}
} else {
if j > 0 {
if is_expr {
g.write(' : ')
} else {
g.write(' else ')
}
}
if is_expr {
g.write('(')
} else {
g.write('if (')
}
for i, expr in branch.exprs {
if node.is_sum_type {
if j > 0 {
if is_expr {
g.write(' : ')
} else {
g.write(' else ')
}
}
if is_expr {
g.write('(')
} else {
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)
@ -2730,79 +2736,85 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) {
// g.write('._interface_idx == _${sym.name}_${branch_sym} ')
g.write('._interface_idx == ')
}
g.expr(expr)
} else if type_sym.kind == .string {
if (expr as ast.StringLiteral).val == '' {
g.write('${cond_var}.len == 0')
} else {
g.write('string_eq(')
g.write(cond_var)
g.write(', ')
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 as expr_low {
if node.cond_type in [table.u16_type, table.u32_type, table.u64_type] &&
expr_low.val == '0' {
skip_low = true
g.expr(branch.exprs[sumtype_index])
} else {
for i, expr in branch.exprs {
if i > 0 {
g.write(' || ')
}
if type_sym.kind == .string {
if (expr as ast.StringLiteral).val == '' {
g.write('${cond_var}.len == 0')
} else {
g.write('string_eq(')
g.write(cond_var)
g.write(', ')
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 as expr_low {
if node.cond_type in [table.u16_type, table.u32_type, table.u64_type] &&
expr_low.val == '0' {
skip_low = true
}
}
g.write('(')
if !skip_low {
g.write(cond_var)
g.write(' >= ')
g.expr(expr.low)
g.write(' && ')
}
g.write(cond_var)
g.write(' <= ')
g.expr(expr.high)
g.write(')')
} else {
g.write(cond_var)
g.write(' == ')
g.expr(expr)
}
}
g.write('(')
if !skip_low {
g.write(cond_var)
g.write(' >= ')
g.expr(expr.low)
g.write(' && ')
}
g.write(cond_var)
g.write(' <= ')
g.expr(expr.high)
g.write(')')
}
if is_expr {
g.write(') ? ')
} else {
g.write(cond_var)
g.write(' == ')
g.expr(expr)
}
if i < branch.exprs.len - 1 {
g.write(' || ')
g.writeln(') {')
}
}
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 node.is_sum_type && branch.exprs.len > 0 && !node.is_expr {
// The first node in expr is an ast.Type
// Use it to generate `it` variable.
first_expr := branch.exprs[0]
match first_expr {
ast.Type {
it_type := g.typ(first_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;')
// 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')
}
}
else {
verror('match sum type')
}
sumtype_index++
}
g.stmts(branch.stmts)
if g.inside_ternary == 0 && node.branches.len > 1 {
g.write('}')
}
if !node.is_sum_type || branch.exprs.len == 0 || sumtype_index == branch.exprs.len {
break
}
}
g.stmts(branch.stmts)
if g.inside_ternary == 0 && node.branches.len > 1 {
g.write('}')
}
}
if is_expr {

View File

@ -562,10 +562,6 @@ fn (mut p Parser) fn_args() ([]table.Param, bool, bool) {
return args, types_only, is_variadic
}
fn (p &Parser) fileis(s string) bool {
return p.file_name.contains(s)
}
fn (mut p Parser) check_fn_mutable_arguments(typ table.Type, pos token.Position) {
sym := p.table.get_type_symbol(typ)
if sym.kind !in [.array, .struct_, .map, .placeholder, .sum_type] && !typ.is_ptr() {

View File

@ -269,13 +269,6 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
fn (mut p Parser) struct_init(short_syntax bool) ast.StructInit {
first_pos := p.tok.position()
/*
defer {
if p.fileis('x.v') {
p.warn('end of struct init $short_syntax')
}
}
*/
typ := if short_syntax { table.void_type } else { p.parse_type() }
p.expr_mod = ''
// sym := p.table.get_type_symbol(typ)

View File

@ -189,12 +189,11 @@ type NATOAlphabet = Alfa | Bravo | Charlie
fn test_match_sum_type_multiple_type() {
a := Alfa{}
// TODO This currently works because cgen takes the first type as the type of `l`
// it would fail if we `a` was of type `Bravo`
match NATOAlphabet(a) as l {
Alfa, Bravo {
assert l.char == `a`
assert l.letter() == `a`
// TODO make methods work
// assert l.letter() == `a`
}
Charlie {
assert false