1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

cgen: if/match expressions and other fixes

This commit is contained in:
Alexander Medvednikov 2020-03-18 08:41:49 +01:00
parent 3fecf154aa
commit a011b8951a
10 changed files with 134 additions and 48 deletions

View File

@ -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
} }
} }
} }

View File

@ -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

View File

@ -10,15 +10,15 @@ import (
pub type TypeDecl = AliasTypeDecl | SumTypeDecl | FnTypeDecl pub type TypeDecl = AliasTypeDecl | SumTypeDecl | FnTypeDecl
pub type Expr = InfixExpr | IfExpr | StringLiteral | IntegerLiteral | CharLiteral | pub type Expr = InfixExpr | IfExpr | StringLiteral | IntegerLiteral | CharLiteral |
FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr | PostfixExpr | FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr | PostfixExpr |
AssignExpr | PrefixExpr | MethodCallExpr | IndexExpr | RangeExpr | MatchExpr | AssignExpr | PrefixExpr | MethodCallExpr | IndexExpr | RangeExpr | MatchExpr |
CastExpr | EnumVal | Assoc | SizeOf | None | MapInit | IfGuardExpr | ParExpr | OrExpr | CastExpr | EnumVal | Assoc | SizeOf | None | MapInit | IfGuardExpr | ParExpr | OrExpr |
ConcatExpr | Type | AsCast ConcatExpr | Type | AsCast
pub type Stmt = GlobalDecl | FnDecl | Return | Module | Import | ExprStmt | pub type Stmt = GlobalDecl | FnDecl | Return | Module | Import | ExprStmt |
ForStmt | StructDecl | ForCStmt | ForInStmt | CompIf | ConstDecl | Attr | BranchStmt | ForStmt | StructDecl | ForCStmt | ForInStmt | CompIf | ConstDecl | Attr | BranchStmt |
HashStmt | AssignStmt | EnumDecl | TypeDecl | DeferStmt | GotoLabel | GotoStmt | HashStmt | AssignStmt | EnumDecl | TypeDecl | DeferStmt | GotoLabel | GotoStmt |
LineComment | MultiLineComment | AssertStmt | UnsafeStmt | GoStmt LineComment | MultiLineComment | AssertStmt | UnsafeStmt | GoStmt
// pub type Type = StructType | ArrayType // pub type Type = StructType | ArrayType
// pub struct StructType { // pub struct StructType {
@ -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
} }
@ -351,7 +352,8 @@ pub:
branches []MatchBranch branches []MatchBranch
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 {
@ -656,14 +660,13 @@ pub fn expr_is_blank_ident(expr Expr) bool {
[inline] [inline]
pub fn expr_is_call(expr Expr) bool { pub fn expr_is_call(expr Expr) bool {
return match expr { return match expr {
CallExpr { CallExpr{
true true
} }
MethodCallExpr { MethodCallExpr{
true true
} }
else { else {
false false}
}
} }
} }

View File

@ -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)
@ -492,7 +493,7 @@ pub fn (c mut Checker) array_init(array_init mut ast.ArrayInit) table.Type {
else { else {
c.error('expecting `int` for fixed size', array_init.pos) c.error('expecting `int` for fixed size', array_init.pos)
} }
} }
idx := c.table.find_or_register_array_fixed(array_init.elem_type, fixed_size, 1) idx := c.table.find_or_register_array_fixed(array_init.elem_type, fixed_size, 1)
array_type := table.new_type(idx) array_type := table.new_type(idx)
array_init.typ = array_type array_init.typ = array_type
@ -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 {

View File

@ -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 {
@ -116,7 +117,7 @@ pub fn (g mut Gen) write_typedef_types() {
if !info.has_decl && !info.is_anon { if !info.has_decl && !info.is_anon {
fn_name := func.name.replace('.', '__') fn_name := func.name.replace('.', '__')
g.definitions.write('typedef ${g.typ(func.return_type)} (*$fn_name)(') g.definitions.write('typedef ${g.typ(func.return_type)} (*$fn_name)(')
for i,arg in func.args { for i, arg in func.args {
g.definitions.write(g.typ(arg.typ)) g.definitions.write(g.typ(arg.typ))
if i < func.args.len - 1 { if i < func.args.len - 1 {
g.definitions.write(',') g.definitions.write(',')
@ -191,7 +192,9 @@ 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)
g.writeln('') if !g.inside_ternary {
g.writeln('')
}
} }
} }
@ -245,7 +248,9 @@ fn (g mut Gen) stmt(node ast.Stmt) {
// no ; after an if expression // no ; after an if expression
ast.IfExpr {} ast.IfExpr {}
else { else {
g.writeln(';') if !g.inside_ternary {
g.writeln(';')
}
} }
} }
} }
@ -342,7 +347,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
// use instead of expr() when you need to cast to sum type (can add other casts also) // use instead of expr() when you need to cast to sum type (can add other casts also)
fn (g mut Gen) expr_with_cast(got_type table.Type, exp_type table.Type, expr ast.Expr) { fn (g mut Gen) expr_with_cast(got_type table.Type, exp_type table.Type, expr ast.Expr) {
// cast to sum type // cast to sum type
if exp_type != table.void_type && exp_type != 0 && got_type != 0{ if exp_type != table.void_type && exp_type != 0 && got_type != 0 {
exp_sym := g.table.get_type_symbol(exp_type) exp_sym := g.table.get_type_symbol(exp_type)
if exp_sym.kind == .sum_type { if exp_sym.kind == .sum_type {
sum_info := exp_sym.info as table.SumType sum_info := exp_sym.info as table.SumType
@ -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,44 +973,65 @@ 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 {
tmp = g.new_tmp_var() tmp = g.new_tmp_var()
} }
//styp := g.typ(node.expr_type) // styp := g.typ(node.expr_type)
//g.write('$styp $tmp = ') // g.write('$styp $tmp = ')
//g.expr(node.cond) // g.expr(node.cond)
//g.writeln(';') // $it.blocks.len') // g.writeln(';') // $it.blocks.len')
// mut sum_type_str = '' // mut sum_type_str = ''
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{}`
g.writeln('else {') if is_expr {
// TODO too many branches. maybe separate ?: matches
g.write(' : ')
}
else {
g.writeln('else {')
}
} }
else { else {
if j > 0 { if j > 0 {
g.write('else ') if is_expr {
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)
g.write('.typ == ') g.write('.typ == ')
//g.write('${tmp}.typ == ') // g.write('${tmp}.typ == ')
// sum_type_str // sum_type_str
} }
else if type_sym.kind == .string { else if type_sym.kind == .string {
g.write('string_eq(') g.write('string_eq(')
// //
g.expr(node.cond) g.expr(node.cond)
g.write(', ') g.write(', ')
//g.write('string_eq($tmp, ') // g.write('string_eq($tmp, ')
} }
else { else {
g.expr(node.cond) g.expr(node.cond)
g.write(' == ') g.write(' == ')
//g.write('$tmp == ') // g.write('$tmp == ')
} }
g.expr(expr) g.expr(expr)
if type_sym.kind == .string { if type_sym.kind == .string {
@ -1013,7 +1041,12 @@ g.write(', ')
g.write(' || ') g.write(' || ')
} }
} }
g.writeln(') {') if is_expr {
g.write(') ? ')
}
else {
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
@ -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,8 +1066,11 @@ g.write(', ')
} }
} }
g.stmts(branch.stmts) g.stmts(branch.stmts)
g.writeln('}') if !g.inside_ternary {
g.writeln('}')
}
} }
g.inside_ternary = false
} }
fn (g mut Gen) ident(node ast.Ident) { fn (g mut Gen) ident(node ast.Ident) {
@ -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
@ -1081,7 +1121,7 @@ fn (g mut Gen) if_expr(node ast.IfExpr) {
g.stmt(else_stmt1) g.stmt(else_stmt1)
} }
else {} else {}
} }
} }
else { else {
mut is_guard := false mut is_guard := false
@ -1096,11 +1136,12 @@ 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(') {')
} }
} }
for i, stmt in node.stmts { for i, stmt in node.stmts {
// 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 {}
@ -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)

View File

@ -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
} }

View File

@ -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

View File

@ -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 }

View File

@ -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 {

View File

@ -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 }`