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) { pub fn (mut f Fmt) write(s string) {
if !f.buffering { if !f.buffering {
if f.indent > 0 && f.empty_line { if f.indent > 0 && f.empty_line {
if f.indent < tabs.len { f.write_indent()
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.line_len += f.indent * 4 f.line_len += f.indent * 4
} }
f.out.write(s) f.out.write(s)
@ -133,8 +126,7 @@ pub fn (mut f Fmt) writeln(s string) {
f.precedences = []int{} f.precedences = []int{}
} }
if f.indent > 0 && f.empty_line { if f.indent > 0 && f.empty_line {
// println(f.indent.str() + s) f.write_indent()
f.out.write(tabs[f.indent])
} }
f.out.writeln(if empty_fifo { f.out.writeln(if empty_fifo {
'' ''
@ -145,6 +137,17 @@ pub fn (mut f Fmt) writeln(s string) {
f.line_len = 0 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 // 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 // only prevents line breaks if everything fits in max_len[last] by increasing
// penalties to maximum // 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] == ` ` { if f.out.buf[f.out.buf.len - 1] == ` ` {
f.out.go_back(1) f.out.go_back(1)
} }
f.write('\n' + tabs[f.indent + if add_indent { f.write('\n')
1 if add_indent {
} else { f.indent++
0 }
}]) f.write_indent()
if add_indent {
f.indent--
}
f.line_len = 0 f.line_len = 0
return true return true
} }

View File

@ -2693,32 +2693,38 @@ 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
for j, branch in node.branches { for j, branch in node.branches {
is_last := j == node.branches.len - 1 mut sumtype_index := 0
if branch.is_else || (node.is_expr && is_last) { // iterates through all types in sumtype branches
if node.branches.len > 1 { // it loops only once for other types
if is_expr { for {
// TODO too many branches. maybe separate ?: matches is_last := j == node.branches.len - 1
g.write(' : ') if branch.is_else || (node.is_expr && is_last) {
} else { if node.branches.len > 1 {
g.writeln(' else {') 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 { } else {
g.write('if (') if j > 0 {
} if is_expr {
for i, expr in branch.exprs { g.write(' : ')
if node.is_sum_type { } 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) g.write(cond_var)
sym := g.table.get_type_symbol(node.cond_type) sym := g.table.get_type_symbol(node.cond_type)
// branch_sym := g.table.get_type_symbol(branch.typ) // 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 == _${sym.name}_${branch_sym} ')
g.write('._interface_idx == ') g.write('._interface_idx == ')
} }
g.expr(expr) g.expr(branch.exprs[sumtype_index])
} else if type_sym.kind == .string { } else {
if (expr as ast.StringLiteral).val == '' { for i, expr in branch.exprs {
g.write('${cond_var}.len == 0') if i > 0 {
} else { g.write(' || ')
g.write('string_eq(') }
g.write(cond_var) if type_sym.kind == .string {
g.write(', ') if (expr as ast.StringLiteral).val == '' {
g.expr(expr) g.write('${cond_var}.len == 0')
g.write(')') } else {
} g.write('string_eq(')
} else if expr is ast.RangeExpr { g.write(cond_var)
// if type is unsigned and low is 0, check is unneeded g.write(', ')
mut skip_low := false g.expr(expr)
if expr.low is ast.IntegerLiteral as expr_low { g.write(')')
if node.cond_type in [table.u16_type, table.u32_type, table.u64_type] && }
expr_low.val == '0' { } else if expr is ast.RangeExpr {
skip_low = true // 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 { if is_expr {
g.write(cond_var) g.write(') ? ')
g.write(' >= ')
g.expr(expr.low)
g.write(' && ')
}
g.write(cond_var)
g.write(' <= ')
g.expr(expr.high)
g.write(')')
} else { } else {
g.write(cond_var) g.writeln(') {')
g.write(' == ')
g.expr(expr)
}
if i < branch.exprs.len - 1 {
g.write(' || ')
} }
} }
if is_expr { // g.writeln('/* M sum_type=$node.is_sum_type is_expr=$node.is_expr exp_type=${g.typ(node.expected_type)}*/')
g.write(') ? ') if node.is_sum_type && branch.exprs.len > 0 {
} else { if !node.is_expr {
g.writeln(') {') // Use the nodes in the expr to generate `it` variable.
} type_expr := branch.exprs[sumtype_index]
} if type_expr is ast.Type {
// g.writeln('/* M sum_type=$node.is_sum_type is_expr=$node.is_expr exp_type=${g.typ(node.expected_type)}*/') it_type := g.typ(type_expr.typ)
if node.is_sum_type && branch.exprs.len > 0 && !node.is_expr { // g.writeln('$it_type* it = ($it_type*)${tmp}.obj; // ST it')
// The first node in expr is an ast.Type g.write('\t$it_type* it = ($it_type*)')
// Use it to generate `it` variable. g.write(cond_var)
first_expr := branch.exprs[0] dot_or_ptr := if node.cond_type.is_ptr() { '->' } else { '.' }
match first_expr { g.write(dot_or_ptr)
ast.Type { g.writeln('_object; // ST it')
it_type := g.typ(first_expr.typ) if node.var_name.len > 0 {
// g.writeln('$it_type* it = ($it_type*)${tmp}.obj; // ST it') // for now we just copy it
g.write('\t$it_type* it = ($it_type*)') g.writeln('\t$it_type* $node.var_name = it;')
g.write(cond_var) }
dot_or_ptr := if node.cond_type.is_ptr() { '->' } else { '.' } } else {
g.write(dot_or_ptr) verror('match sum type')
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 { sumtype_index++
verror('match sum type') }
} 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 { 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 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) { fn (mut p Parser) check_fn_mutable_arguments(typ table.Type, pos token.Position) {
sym := p.table.get_type_symbol(typ) sym := p.table.get_type_symbol(typ)
if sym.kind !in [.array, .struct_, .map, .placeholder, .sum_type] && !typ.is_ptr() { 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 { fn (mut p Parser) struct_init(short_syntax bool) ast.StructInit {
first_pos := p.tok.position() 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() } typ := if short_syntax { table.void_type } else { p.parse_type() }
p.expr_mod = '' p.expr_mod = ''
// sym := p.table.get_type_symbol(typ) // 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() { fn test_match_sum_type_multiple_type() {
a := Alfa{} 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 { match NATOAlphabet(a) as l {
Alfa, Bravo { Alfa, Bravo {
assert l.char == `a` assert l.char == `a`
assert l.letter() == `a` // TODO make methods work
// assert l.letter() == `a`
} }
Charlie { Charlie {
assert false assert false