cgen: if/match expressions and other fixes
parent
3fecf154aa
commit
a011b8951a
|
@ -94,6 +94,7 @@ fn parse_flags(flag string, f mut flag.Instance, prefs mut flag.MainCmdPreferenc
|
||||||
println('V error: Error parsing flag. Expected value for `-$flag`.')
|
println('V error: Error parsing flag. Expected value for `-$flag`.')
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -313,6 +313,12 @@ fn (m map) get(key string, out voidptr) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
/*
|
||||||
|
fn (m &map) get2(key string, out voidptr) voidptr {
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
fn (m map) exists(key string) bool {
|
fn (m map) exists(key string) bool {
|
||||||
if m.value_bytes == 0 {
|
if m.value_bytes == 0 {
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -340,6 +340,7 @@ pub:
|
||||||
left Expr // `a` in `a := if ...`
|
left Expr // `a` in `a := if ...`
|
||||||
pos token.Position
|
pos token.Position
|
||||||
mut:
|
mut:
|
||||||
|
is_expr bool
|
||||||
typ table.Type
|
typ table.Type
|
||||||
has_else bool
|
has_else bool
|
||||||
}
|
}
|
||||||
|
@ -352,6 +353,7 @@ pub:
|
||||||
pos token.Position
|
pos token.Position
|
||||||
mut:
|
mut:
|
||||||
is_expr bool // returns a value
|
is_expr bool // returns a value
|
||||||
|
return_type table.Type
|
||||||
expr_type table.Type // type of `x` in `match x {`
|
expr_type table.Type // type of `x` in `match x {`
|
||||||
is_sum_type bool
|
is_sum_type bool
|
||||||
}
|
}
|
||||||
|
@ -591,6 +593,7 @@ pub:
|
||||||
|
|
||||||
pub struct SizeOf {
|
pub struct SizeOf {
|
||||||
pub:
|
pub:
|
||||||
|
typ table.Type
|
||||||
type_name string
|
type_name string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -641,6 +644,7 @@ enum BinaryOp {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
pub fn expr_is_blank_ident(expr Expr) bool {
|
pub fn expr_is_blank_ident(expr Expr) bool {
|
||||||
match expr {
|
match expr {
|
||||||
|
@ -663,7 +667,6 @@ pub fn expr_is_call(expr Expr) bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
false
|
false}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -270,6 +270,7 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
|
||||||
|
|
||||||
// TODO: clean this up, remove dupe code & consider merging method/fn call everywhere
|
// TODO: clean this up, remove dupe code & consider merging method/fn call everywhere
|
||||||
pub fn (c mut Checker) method_call_expr(method_call_expr mut ast.MethodCallExpr) table.Type {
|
pub fn (c mut Checker) method_call_expr(method_call_expr mut ast.MethodCallExpr) table.Type {
|
||||||
|
c.expected_type = table.void_type
|
||||||
typ := c.expr(method_call_expr.expr)
|
typ := c.expr(method_call_expr.expr)
|
||||||
method_call_expr.expr_type = typ
|
method_call_expr.expr_type = typ
|
||||||
typ_sym := c.table.get_type_symbol(typ)
|
typ_sym := c.table.get_type_symbol(typ)
|
||||||
|
@ -525,6 +526,7 @@ fn (c mut Checker) stmt(node ast.Stmt) {
|
||||||
c.expr(it.expr)
|
c.expr(it.expr)
|
||||||
}
|
}
|
||||||
ast.FnDecl {
|
ast.FnDecl {
|
||||||
|
c.expected_type = table.void_type
|
||||||
c.fn_return_type = it.return_type
|
c.fn_return_type = it.return_type
|
||||||
for stmt in it.stmts {
|
for stmt in it.stmts {
|
||||||
c.stmt(stmt)
|
c.stmt(stmt)
|
||||||
|
@ -815,14 +817,25 @@ pub fn (c mut Checker) match_expr(node mut ast.MatchExpr) table.Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// if ret_type != table.void_type {
|
||||||
|
// node.is_expr = c.expected_type != table.void_type
|
||||||
|
// node.expected_type = c.expected_type
|
||||||
|
// }
|
||||||
|
node.return_type = ret_type
|
||||||
node.expr_type = expr_type
|
node.expr_type = expr_type
|
||||||
// println('!m $expr_type')
|
// println('!m $expr_type')
|
||||||
return ret_type
|
return ret_type
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (c mut Checker) if_expr(node mut ast.IfExpr) table.Type {
|
pub fn (c mut Checker) if_expr(node mut ast.IfExpr) table.Type {
|
||||||
|
if c.expected_type != 0 {
|
||||||
|
// sym := c.table.get_type_symbol(c.expected_type)
|
||||||
|
// println('$c.file.path $node.pos.line_nr IF: checker exp type = ' + sym.name)
|
||||||
|
node.is_expr = true
|
||||||
|
}
|
||||||
typ := c.expr(node.cond)
|
typ := c.expr(node.cond)
|
||||||
node.typ = typ
|
node.typ = table.void_type
|
||||||
|
// node.typ = typ
|
||||||
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 {
|
||||||
|
|
|
@ -22,6 +22,7 @@ mut:
|
||||||
is_array_set bool
|
is_array_set bool
|
||||||
is_amp bool // for `&Foo{}` to merge PrefixExpr `&` and StructInit `Foo{}`; also for `&byte(0)` etc
|
is_amp bool // for `&Foo{}` to merge PrefixExpr `&` and StructInit `Foo{}`; also for `&byte(0)` etc
|
||||||
optionals []string // to avoid duplicates TODO perf, use map
|
optionals []string // to avoid duplicates TODO perf, use map
|
||||||
|
inside_ternary bool // ?: comma separated statements on a single line
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cgen(files []ast.File, table &table.Table) string {
|
pub fn cgen(files []ast.File, table &table.Table) string {
|
||||||
|
@ -191,9 +192,11 @@ pub fn (g mut Gen) reset_tmp_count() {
|
||||||
fn (g mut Gen) stmts(stmts []ast.Stmt) {
|
fn (g mut Gen) stmts(stmts []ast.Stmt) {
|
||||||
for stmt in stmts {
|
for stmt in stmts {
|
||||||
g.stmt(stmt)
|
g.stmt(stmt)
|
||||||
|
if !g.inside_ternary {
|
||||||
g.writeln('')
|
g.writeln('')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn (g mut Gen) stmt(node ast.Stmt) {
|
fn (g mut Gen) stmt(node ast.Stmt) {
|
||||||
// println('cgen.stmt()')
|
// println('cgen.stmt()')
|
||||||
|
@ -245,9 +248,11 @@ fn (g mut Gen) stmt(node ast.Stmt) {
|
||||||
// no ; after an if expression
|
// no ; after an if expression
|
||||||
ast.IfExpr {}
|
ast.IfExpr {}
|
||||||
else {
|
else {
|
||||||
|
if !g.inside_ternary {
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ast.FnDecl {
|
ast.FnDecl {
|
||||||
g.fn_decl = it // &it
|
g.fn_decl = it // &it
|
||||||
|
@ -427,7 +432,8 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
g.write(' = ')
|
g.write(' = ')
|
||||||
if !is_decl {
|
if !is_decl {
|
||||||
g.expr_with_cast(assign_stmt.left_types[i], ident_var_info.typ, val)
|
g.expr_with_cast(assign_stmt.left_types[i], ident_var_info.typ, val)
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
g.expr(val)
|
g.expr(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -811,7 +817,8 @@ fn (g mut Gen) expr(node ast.Expr) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ast.SizeOf {
|
ast.SizeOf {
|
||||||
g.write('sizeof($it.type_name)')
|
styp := g.typ(it.typ)
|
||||||
|
g.write('sizeof($styp)')
|
||||||
}
|
}
|
||||||
ast.StringLiteral {
|
ast.StringLiteral {
|
||||||
// In C calls we have to generate C strings
|
// In C calls we have to generate C strings
|
||||||
|
@ -966,6 +973,11 @@ fn (g mut Gen) match_expr(node ast.MatchExpr) {
|
||||||
g.writeln('// match 0')
|
g.writeln('// match 0')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
is_expr := node.return_type != table.void_type
|
||||||
|
if is_expr {
|
||||||
|
g.inside_ternary = true
|
||||||
|
// g.write('/* EM ret type=${g.typ(node.return_type)} */')
|
||||||
|
}
|
||||||
type_sym := g.table.get_type_symbol(node.expr_type)
|
type_sym := g.table.get_type_symbol(node.expr_type)
|
||||||
mut tmp := ''
|
mut tmp := ''
|
||||||
if type_sym.kind != .void {
|
if type_sym.kind != .void {
|
||||||
|
@ -979,13 +991,29 @@ fn (g mut Gen) match_expr(node ast.MatchExpr) {
|
||||||
for j, branch in node.branches {
|
for j, branch in node.branches {
|
||||||
if j == node.branches.len - 1 {
|
if j == node.branches.len - 1 {
|
||||||
// last block is an `else{}`
|
// last block is an `else{}`
|
||||||
|
if is_expr {
|
||||||
|
// TODO too many branches. maybe separate ?: matches
|
||||||
|
g.write(' : ')
|
||||||
|
}
|
||||||
|
else {
|
||||||
g.writeln('else {')
|
g.writeln('else {')
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if j > 0 {
|
if j > 0 {
|
||||||
|
if is_expr {
|
||||||
|
g.write(' : ')
|
||||||
|
}
|
||||||
|
else {
|
||||||
g.write('else ')
|
g.write('else ')
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if is_expr {
|
||||||
|
g.write('(')
|
||||||
|
}
|
||||||
|
else {
|
||||||
g.write('if (')
|
g.write('if (')
|
||||||
|
}
|
||||||
for i, expr in branch.exprs {
|
for i, expr in branch.exprs {
|
||||||
if node.is_sum_type {
|
if node.is_sum_type {
|
||||||
g.expr(node.cond)
|
g.expr(node.cond)
|
||||||
|
@ -1013,8 +1041,13 @@ g.write(', ')
|
||||||
g.write(' || ')
|
g.write(' || ')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if is_expr {
|
||||||
|
g.write(') ? ')
|
||||||
|
}
|
||||||
|
else {
|
||||||
g.writeln(') {')
|
g.writeln(') {')
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if node.is_sum_type && branch.exprs.len > 0 {
|
if node.is_sum_type && branch.exprs.len > 0 {
|
||||||
// The first node in expr is an ast.Type
|
// The first node in expr is an ast.Type
|
||||||
// Use it to generate `it` variable.
|
// Use it to generate `it` variable.
|
||||||
|
@ -1022,7 +1055,10 @@ g.write(', ')
|
||||||
match fe {
|
match fe {
|
||||||
ast.Type {
|
ast.Type {
|
||||||
it_type := g.typ(it.typ)
|
it_type := g.typ(it.typ)
|
||||||
g.writeln('$it_type* it = ($it_type*)${tmp}.obj; // ST it')
|
// g.writeln('$it_type* it = ($it_type*)${tmp}.obj; // ST it')
|
||||||
|
g.write('$it_type* it = ($it_type*)')
|
||||||
|
g.expr(node.cond)
|
||||||
|
g.writeln('.obj; // ST it')
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
verror('match sum type')
|
verror('match sum type')
|
||||||
|
@ -1030,9 +1066,12 @@ g.write(', ')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.stmts(branch.stmts)
|
g.stmts(branch.stmts)
|
||||||
|
if !g.inside_ternary {
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
g.inside_ternary = false
|
||||||
|
}
|
||||||
|
|
||||||
fn (g mut Gen) ident(node ast.Ident) {
|
fn (g mut Gen) ident(node ast.Ident) {
|
||||||
name := node.name.replace('.', '__')
|
name := node.name.replace('.', '__')
|
||||||
|
@ -1067,12 +1106,13 @@ 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.stmts.len == 1 && node.else_stmts.len == 1 && type_sym.kind != .void {
|
if node.is_expr && node.stmts.len == 1 && node.else_stmts.len == 1 && type_sym.kind != .void {
|
||||||
cond := node.cond
|
cond := node.cond
|
||||||
stmt1 := node.stmts[0]
|
stmt1 := node.stmts[0]
|
||||||
else_stmt1 := node.else_stmts[0]
|
else_stmt1 := node.else_stmts[0]
|
||||||
match stmt1 {
|
match stmt1 {
|
||||||
ast.ExprStmt {
|
ast.ExprStmt {
|
||||||
|
g.inside_ternary = true
|
||||||
g.expr(cond)
|
g.expr(cond)
|
||||||
g.write(' ? ')
|
g.write(' ? ')
|
||||||
expr_stmt := stmt1 as ast.ExprStmt
|
expr_stmt := stmt1 as ast.ExprStmt
|
||||||
|
@ -1096,6 +1136,7 @@ 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(node.cond)
|
||||||
g.writeln(') {')
|
g.writeln(') {')
|
||||||
|
@ -1113,8 +1154,9 @@ fn (g mut Gen) if_expr(node ast.IfExpr) {
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
if node.else_stmts.len > 0 {
|
if node.else_stmts.len > 0 {
|
||||||
if is_guard {
|
if is_guard {
|
||||||
g.writeln('if !$guard_ok { /* else */')
|
g.writeln('if (!$guard_ok) { /* else */')
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
g.writeln('else { ')
|
g.writeln('else { ')
|
||||||
}
|
}
|
||||||
for stmt in node.else_stmts {
|
for stmt in node.else_stmts {
|
||||||
|
@ -1123,6 +1165,7 @@ fn (g mut Gen) if_expr(node ast.IfExpr) {
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
g.inside_ternary = false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g mut Gen) index_expr(node ast.IndexExpr) {
|
fn (g mut Gen) index_expr(node ast.IndexExpr) {
|
||||||
|
@ -1210,6 +1253,10 @@ fn (g mut Gen) index_expr(node ast.IndexExpr) {
|
||||||
|
|
||||||
fn (g mut Gen) return_statement(it ast.Return) {
|
fn (g mut Gen) return_statement(it ast.Return) {
|
||||||
g.write('return')
|
g.write('return')
|
||||||
|
if g.fn_decl.name == 'main' {
|
||||||
|
g.writeln(' 0;')
|
||||||
|
return
|
||||||
|
}
|
||||||
// multiple returns
|
// multiple returns
|
||||||
if it.exprs.len > 1 {
|
if it.exprs.len > 1 {
|
||||||
typ_sym := g.table.get_type_symbol(g.fn_decl.return_type)
|
typ_sym := g.table.get_type_symbol(g.fn_decl.return_type)
|
||||||
|
|
|
@ -55,8 +55,8 @@ fn compare_texts(a, b, path string) bool {
|
||||||
println('${path}: got\n$a')
|
println('${path}: got\n$a')
|
||||||
println('${term_fail} ${i}')
|
println('${term_fail} ${i}')
|
||||||
println(term.red('i=$i "$line_a" expected="$line_b"'))
|
println(term.red('i=$i "$line_a" expected="$line_b"'))
|
||||||
// println(lines_b[i + 1])
|
println(lines_b[i + 1])
|
||||||
// println(lines_b[i + 2])
|
println(lines_b[i + 2])
|
||||||
// exit(1)
|
// exit(1)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,7 +149,6 @@ multi_return_int_string multi_return() {
|
||||||
void variadic(varg_int a) {
|
void variadic(varg_int a) {
|
||||||
int x = path_sep;
|
int x = path_sep;
|
||||||
int y = true ? 1 : 0;
|
int y = true ? 1 : 0;
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ensure_cap(int required, int cap) {
|
void ensure_cap(int required, int cap) {
|
||||||
|
@ -172,6 +171,9 @@ void matches() {
|
||||||
else {
|
else {
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
string x = (a == 10) ? tos3("ten") : (a == 30) ? tos3("thirty") : tos3("unknown");
|
||||||
|
int xx = (a == 10) ? 100 : (a == 30) ? 300 : 0;
|
||||||
|
println((a == 10) ? tos3("ten") : tos3("not ten"));
|
||||||
}
|
}
|
||||||
|
|
||||||
//10
|
//10
|
||||||
|
|
|
@ -156,6 +156,17 @@ fn matches() {
|
||||||
}
|
}
|
||||||
else{}
|
else{}
|
||||||
}
|
}
|
||||||
|
x := match a {
|
||||||
|
10 { 'ten' }
|
||||||
|
30 { 'thirty' }
|
||||||
|
else { 'unknown' }
|
||||||
|
}
|
||||||
|
xx := match a {
|
||||||
|
10 { 100 }
|
||||||
|
30 { 300 }
|
||||||
|
else { 0 }
|
||||||
|
}
|
||||||
|
println(match a { 10 { 'ten' } else { 'not ten' } })
|
||||||
/*
|
/*
|
||||||
n := match a {
|
n := match a {
|
||||||
1 { 10 }
|
1 { 10 }
|
||||||
|
|
|
@ -40,11 +40,11 @@ void println(string s) {
|
||||||
|
|
||||||
void handle_expr(Expr e) {
|
void handle_expr(Expr e) {
|
||||||
if (e.typ == _type_idx_IfExpr) {
|
if (e.typ == _type_idx_IfExpr) {
|
||||||
IfExpr* it = (IfExpr*)tmp1.obj; // ST it
|
IfExpr* it = (IfExpr*)e.obj; // ST it
|
||||||
println(tos3("if"));
|
println(tos3("if"));
|
||||||
}
|
}
|
||||||
else if (e.typ == _type_idx_IntegerLiteral) {
|
else if (e.typ == _type_idx_IntegerLiteral) {
|
||||||
IntegerLiteral* it = (IntegerLiteral*)tmp1.obj; // ST it
|
IntegerLiteral* it = (IntegerLiteral*)e.obj; // ST it
|
||||||
println(tos3("integer"));
|
println(tos3("integer"));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -748,10 +748,13 @@ pub fn (p mut Parser) expr(precedence int) ast.Expr {
|
||||||
if p.tok.kind == .amp {
|
if p.tok.kind == .amp {
|
||||||
p.next()
|
p.next()
|
||||||
}
|
}
|
||||||
type_name := p.check_name()
|
// type_name := p.check_name()
|
||||||
|
sizeof_type := p.parse_type()
|
||||||
p.check(.rpar)
|
p.check(.rpar)
|
||||||
node = ast.SizeOf{
|
node = ast.SizeOf{
|
||||||
type_name: type_name
|
typ: sizeof_type
|
||||||
|
// type_name: type_name
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Map `{"age": 20}` or `{ x | foo:bar, a:10 }`
|
// Map `{"age": 20}` or `{ x | foo:bar, a:10 }`
|
||||||
|
|
Loading…
Reference in New Issue