ast/cgen/parser: combine IfExpr branches into single node

pull/4078/head
Joe Conigliaro 2020-03-21 00:39:56 +11:00
parent c993489fe9
commit a331abf675
7 changed files with 182 additions and 167 deletions

View File

@ -337,9 +337,7 @@ mut:
pub struct IfExpr { pub struct IfExpr {
pub: pub:
tok_kind token.Kind tok_kind token.Kind
cond Expr branches []IfBranch
stmts []Stmt
else_stmts []Stmt
left Expr // `a` in `a := if ...` left Expr // `a` in `a := if ...`
pos token.Position pos token.Position
mut: mut:
@ -348,6 +346,13 @@ mut:
has_else bool has_else bool
} }
pub struct IfBranch {
pub:
cond Expr
stmts []Stmt
pos token.Position
}
pub struct MatchExpr { pub struct MatchExpr {
pub: pub:
tok_kind token.Kind tok_kind token.Kind

View File

@ -909,20 +909,22 @@ pub fn (c mut Checker) if_expr(node mut ast.IfExpr) table.Type {
// println('$c.file.path $node.pos.line_nr IF: checker exp type = ' + sym.name) // println('$c.file.path $node.pos.line_nr IF: checker exp type = ' + sym.name)
node.is_expr = true node.is_expr = true
} }
typ := c.expr(node.cond)
node.typ = table.void_type node.typ = table.void_type
// node.typ = typ for i, branch in node.branches {
typ := c.expr(branch.cond)
if i < node.branches.len-1 || !node.has_else {
typ_sym := c.table.get_type_symbol(typ) typ_sym := c.table.get_type_symbol(typ)
// if typ_sym.kind != .bool { // if typ_sym.kind != .bool {
if table.type_idx(typ) != table.bool_type_idx { if table.type_idx(typ) != table.bool_type_idx {
c.error('non-bool (`$typ_sym.name`) used as if condition', node.pos) c.error('non-bool (`$typ_sym.name`) used as if condition', node.pos)
} }
c.stmts(node.stmts)
if node.else_stmts.len > 0 {
c.stmts(node.else_stmts)
} }
if node.stmts.len > 0 { c.stmts(branch.stmts)
match node.stmts[node.stmts.len - 1] { }
if node.has_else && node.is_expr {
last_branch := node.branches[node.branches.len-1]
if last_branch.stmts.len > 0 {
match last_branch.stmts[last_branch.stmts.len - 1] {
ast.ExprStmt { ast.ExprStmt {
// type_sym := p.table.get_type_symbol(it.typ) // type_sym := p.table.get_type_symbol(it.typ)
// p.warn('if expr ret $type_sym.name') // p.warn('if expr ret $type_sym.name')
@ -933,8 +935,8 @@ pub fn (c mut Checker) if_expr(node mut ast.IfExpr) table.Type {
else {} else {}
} }
} }
return typ }
// return table.void_type return table.bool_type
} }
pub fn (c mut Checker) postfix_expr(node ast.PostfixExpr) table.Type { pub fn (c mut Checker) postfix_expr(node ast.PostfixExpr) table.Type {

View File

@ -378,38 +378,38 @@ fn (f mut Fmt) expr(node ast.Expr) {
f.write(it.val) f.write(it.val)
} }
ast.IfExpr { ast.IfExpr {
single_line := it.stmts.len == 1 && it.else_stmts.len == 1 && it.typ != table.void_type single_line := it.branches.len == 2 && it.has_else //
&& it.branches[0].stmts.len == 1 && it.branches[1].stmts.len == 1
f.single_line_if = single_line f.single_line_if = single_line
for i, branch in it.branches {
if i == 0 {
f.write('if ') f.write('if ')
f.expr(it.cond) f.expr(branch.cond)
if single_line {
f.write(' {') f.write(' {')
} }
else { else if i < it.branches.len-1 || !it.has_else {
f.writeln(' {') f.write('} else if ')
f.expr(branch.cond)
f.write(' {')
} }
f.stmts(it.stmts) else if i == it.branches.len-1 && it.has_else {
if single_line { f.write('} else {')
f.write(' ')
} }
f.write('}')
if it.has_else {
f.write(' else ')
}
else if it.else_stmts.len > 0 {
f.write(' else {')
if single_line { if single_line {
f.write(' ') f.write(' ')
} }
else { else {
f.writeln('') f.writeln('')
} }
f.stmts(it.else_stmts) f.stmts(branch.stmts)
if single_line { if single_line {
f.write(' ') f.write(' ')
} }
f.write('}')
} }
// if !single_line {
// f.writeln('')
// }
f.write('}')
f.single_line_if = false f.single_line_if = false
} }
ast.Ident { ast.Ident {

View File

@ -1176,27 +1176,27 @@ fn (g mut Gen) if_expr(node ast.IfExpr) {
} }
// one line ?: // one line ?:
// TODO clean this up once `is` is supported // TODO clean this up once `is` is supported
if node.is_expr && node.stmts.len == 1 && node.else_stmts.len == 1 && type_sym.kind != .void { // TODO: make sure only one stmt in eac branch
cond := node.cond if node.is_expr && node.branches.len >= 2 && node.has_else && type_sym.kind != .void {
stmt1 := node.stmts[0]
else_stmt1 := node.else_stmts[0]
match stmt1 {
ast.ExprStmt {
g.inside_ternary = true g.inside_ternary = true
g.expr(cond) for i, branch in node.branches {
g.write(' ? ') if i > 0 {
expr_stmt := stmt1 as ast.ExprStmt
g.expr(expr_stmt.expr)
g.write(' : ') g.write(' : ')
g.stmt(else_stmt1)
} }
else {} if i < node.branches.len-1 || !node.has_else {
g.expr(branch.cond)
g.write(' ? ')
} }
g.stmts(branch.stmts)
}
g.inside_ternary = false
} }
else { else {
mut is_guard := false
guard_ok := g.new_tmp_var() guard_ok := g.new_tmp_var()
match node.cond { mut is_guard := false
for i, branch in node.branches {
if i == 0 {
match branch.cond {
ast.IfGuardExpr { ast.IfGuardExpr {
is_guard = true is_guard = true
g.writeln('bool $guard_ok;') g.writeln('bool $guard_ok;')
@ -1206,34 +1206,38 @@ fn (g mut Gen) if_expr(node ast.IfExpr) {
g.writeln('if (($guard_ok = ${it.var_name}.ok)) {') g.writeln('if (($guard_ok = ${it.var_name}.ok)) {')
} }
else { else {
g.inside_ternary = false
g.write('if (') g.write('if (')
g.expr(node.cond) g.expr(branch.cond)
g.writeln(') {') g.writeln(') {')
} }
} }
for i, stmt in node.stmts {
}
else if i < node.branches.len-1 || !node.has_else {
g.writeln('} else if (')
g.expr(branch.cond)
g.write(') {')
}
else if i == node.branches.len-1 && node.has_else {
if is_guard {
g.writeln('} if (!$guard_ok) { /* else */')
}
else {
g.writeln('} else {')
}
}
// Assign ret value // Assign ret value
if i == node.stmts.len - 1 && type_sym.kind != .void {} // if i == node.stmts.len - 1 && type_sym.kind != .void {}
// g.writeln('$tmp =') // g.writeln('$tmp =')
g.stmt(stmt) //
g.stmts(branch.stmts)
// g.writeln('')
} }
if is_guard { if is_guard {
g.write('}') g.write('}')
} }
g.writeln('}') g.writeln('}')
if node.else_stmts.len > 0 {
if is_guard {
g.writeln('if (!$guard_ok) { /* else */')
} }
else {
g.writeln('else { ')
}
g.stmts(node.else_stmts)
g.writeln('}')
}
}
g.inside_ternary = false
} }
fn (g mut Gen) index_expr(node ast.IndexExpr) { fn (g mut Gen) index_expr(node ast.IndexExpr) {

View File

@ -34,6 +34,12 @@ pub fn (g mut JsGen) writeln(s string) {
g.out.writeln(s) g.out.writeln(s)
} }
fn (g mut JsGen) stmts(stmts []ast.Stmt) {
for stmt in stmts {
g.stmt(stmt)
}
}
fn (g mut JsGen) stmt(node ast.Stmt) { fn (g mut JsGen) stmt(node ast.Stmt) {
match node { match node {
ast.FnDecl { ast.FnDecl {
@ -163,14 +169,24 @@ fn (g mut JsGen) expr(node ast.Expr) {
} }
} }
ast.IfExpr { ast.IfExpr {
for i, branch in it.branches {
if i == 0 {
g.write('if (') g.write('if (')
g.expr(it.cond) g.expr(branch.cond)
g.writeln(') {') g.writeln(') {')
for stmt in it.stmts {
g.stmt(stmt)
} }
else if i < it.branches.len-1 || !it.has_else {
g.write('else if (')
g.expr(branch.cond)
g.writeln(') {')
}
else {
g.write('else {')
}
g.stmts(branch.stmts)
g.writeln('}') g.writeln('}')
} }
}
else { else {
println(term.red('jsgen.expr(): bad node')) println(term.red('jsgen.expr(): bad node'))
} }

View File

@ -1175,16 +1175,33 @@ fn (p mut Parser) for_statement() ast.Stmt {
} }
} }
fn (p mut Parser) if_expr() ast.Expr { fn (p mut Parser) if_expr() ast.IfExpr {
p.inside_if = true p.inside_if = true
// defer {
// }
mut node := ast.Expr{}
p.check(.key_if)
pos := p.tok.position() pos := p.tok.position()
// `if x := opt() {` mut branches := []ast.IfBranch
mut has_else := false
for p.tok.kind in [.key_if, .key_else] {
branch_pos := p.tok.position()
if p.tok.kind == .key_if {
p.check(.key_if)
}
else {
p.check(.key_else)
if p.tok.kind == .key_if {
p.check(.key_if)
}
else {
has_else = true
branches << ast.IfBranch{
stmts: p.parse_block()
pos: branch_pos
}
break
}
}
mut cond := ast.Expr{} mut cond := ast.Expr{}
mut is_or := false mut is_or := false
// `if x := opt() {`
if p.peek_tok.kind == .decl_assign { if p.peek_tok.kind == .decl_assign {
is_or = true is_or = true
p.open_scope() p.open_scope()
@ -1204,53 +1221,24 @@ fn (p mut Parser) if_expr() ast.Expr {
cond = p.expr(0) cond = p.expr(0)
} }
p.inside_if = false p.inside_if = false
mut has_else := false
stmts := p.parse_block() stmts := p.parse_block()
mut else_stmts := []ast.Stmt
if p.tok.kind == .key_else {
p.check(.key_else)
if p.tok.kind == .key_if {
// The next if block is handled by next if_expr()
has_else = true
}
// p.if_expr()
else {
else_stmts = p.parse_block()
}
}
if is_or { if is_or {
p.close_scope() p.close_scope()
} }
// mut typ := table.void_type branches << ast.IfBranch{
// mut left := ast.Expr{}
// If the last statement is an expression, return its type
/*
if stmts.len > 0 {
match stmts[stmts.len - 1] {
ast.ExprStmt {
type_sym := p.table.get_type_symbol(it.typ)
p.warn('if expr ret $type_sym.name')
typ = it.typ
// return node,it.ti
// left =
}
else {}
}
}
*/
node = ast.IfExpr{
cond: cond cond: cond
stmts: stmts stmts: stmts
else_stmts: else_stmts pos: branch_pos
// typ: typ }
if p.tok.kind != .key_else {
break
}
}
return ast.IfExpr{
branches: branches
pos: pos pos: pos
has_else: has_else has_else: has_else
// left: left
} }
return node
} }
fn (p mut Parser) string_expr() ast.Expr { fn (p mut Parser) string_expr() ast.Expr {