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:
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`.')
|
||||
exit(1)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -313,6 +313,12 @@ fn (m map) get(key string, out voidptr) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// TODO
|
||||
/*
|
||||
fn (m &map) get2(key string, out voidptr) voidptr {
|
||||
}
|
||||
*/
|
||||
|
||||
fn (m map) exists(key string) bool {
|
||||
if m.value_bytes == 0 {
|
||||
return false
|
||||
|
@ -10,15 +10,15 @@ import (
|
||||
|
||||
pub type TypeDecl = AliasTypeDecl | SumTypeDecl | FnTypeDecl
|
||||
|
||||
pub type Expr = InfixExpr | IfExpr | StringLiteral | IntegerLiteral | CharLiteral |
|
||||
FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr | PostfixExpr |
|
||||
AssignExpr | PrefixExpr | MethodCallExpr | IndexExpr | RangeExpr | MatchExpr |
|
||||
CastExpr | EnumVal | Assoc | SizeOf | None | MapInit | IfGuardExpr | ParExpr | OrExpr |
|
||||
pub type Expr = InfixExpr | IfExpr | StringLiteral | IntegerLiteral | CharLiteral |
|
||||
FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr | PostfixExpr |
|
||||
AssignExpr | PrefixExpr | MethodCallExpr | IndexExpr | RangeExpr | MatchExpr |
|
||||
CastExpr | EnumVal | Assoc | SizeOf | None | MapInit | IfGuardExpr | ParExpr | OrExpr |
|
||||
ConcatExpr | Type | AsCast
|
||||
|
||||
pub type Stmt = GlobalDecl | FnDecl | Return | Module | Import | ExprStmt |
|
||||
ForStmt | StructDecl | ForCStmt | ForInStmt | CompIf | ConstDecl | Attr | BranchStmt |
|
||||
HashStmt | AssignStmt | EnumDecl | TypeDecl | DeferStmt | GotoLabel | GotoStmt |
|
||||
pub type Stmt = GlobalDecl | FnDecl | Return | Module | Import | ExprStmt |
|
||||
ForStmt | StructDecl | ForCStmt | ForInStmt | CompIf | ConstDecl | Attr | BranchStmt |
|
||||
HashStmt | AssignStmt | EnumDecl | TypeDecl | DeferStmt | GotoLabel | GotoStmt |
|
||||
LineComment | MultiLineComment | AssertStmt | UnsafeStmt | GoStmt
|
||||
// pub type Type = StructType | ArrayType
|
||||
// pub struct StructType {
|
||||
@ -340,6 +340,7 @@ pub:
|
||||
left Expr // `a` in `a := if ...`
|
||||
pos token.Position
|
||||
mut:
|
||||
is_expr bool
|
||||
typ table.Type
|
||||
has_else bool
|
||||
}
|
||||
@ -351,7 +352,8 @@ pub:
|
||||
branches []MatchBranch
|
||||
pos token.Position
|
||||
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 {`
|
||||
is_sum_type bool
|
||||
}
|
||||
@ -591,6 +593,7 @@ pub:
|
||||
|
||||
pub struct SizeOf {
|
||||
pub:
|
||||
typ table.Type
|
||||
type_name string
|
||||
}
|
||||
|
||||
@ -641,6 +644,7 @@ enum BinaryOp {
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
[inline]
|
||||
pub fn expr_is_blank_ident(expr Expr) bool {
|
||||
match expr {
|
||||
@ -656,14 +660,13 @@ pub fn expr_is_blank_ident(expr Expr) bool {
|
||||
[inline]
|
||||
pub fn expr_is_call(expr Expr) bool {
|
||||
return match expr {
|
||||
CallExpr {
|
||||
CallExpr{
|
||||
true
|
||||
}
|
||||
MethodCallExpr {
|
||||
MethodCallExpr{
|
||||
true
|
||||
}
|
||||
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
|
||||
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)
|
||||
method_call_expr.expr_type = 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 {
|
||||
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)
|
||||
array_type := table.new_type(idx)
|
||||
array_init.typ = array_type
|
||||
@ -525,6 +526,7 @@ fn (c mut Checker) stmt(node ast.Stmt) {
|
||||
c.expr(it.expr)
|
||||
}
|
||||
ast.FnDecl {
|
||||
c.expected_type = table.void_type
|
||||
c.fn_return_type = it.return_type
|
||||
for stmt in it.stmts {
|
||||
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
|
||||
// println('!m $expr_type')
|
||||
return ret_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)
|
||||
node.typ = typ
|
||||
node.typ = table.void_type
|
||||
// node.typ = typ
|
||||
typ_sym := c.table.get_type_symbol(typ)
|
||||
// if typ_sym.kind != .bool {
|
||||
if table.type_idx(typ) != table.bool_type_idx {
|
||||
|
@ -22,6 +22,7 @@ mut:
|
||||
is_array_set bool
|
||||
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
|
||||
inside_ternary bool // ?: comma separated statements on a single line
|
||||
}
|
||||
|
||||
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 {
|
||||
fn_name := func.name.replace('.', '__')
|
||||
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))
|
||||
if i < func.args.len - 1 {
|
||||
g.definitions.write(',')
|
||||
@ -191,7 +192,9 @@ pub fn (g mut Gen) reset_tmp_count() {
|
||||
fn (g mut Gen) stmts(stmts []ast.Stmt) {
|
||||
for stmt in stmts {
|
||||
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
|
||||
ast.IfExpr {}
|
||||
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)
|
||||
fn (g mut Gen) expr_with_cast(got_type table.Type, exp_type table.Type, expr ast.Expr) {
|
||||
// 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)
|
||||
if exp_sym.kind == .sum_type {
|
||||
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(' = ')
|
||||
if !is_decl {
|
||||
g.expr_with_cast(assign_stmt.left_types[i], ident_var_info.typ, val)
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
g.expr(val)
|
||||
}
|
||||
}
|
||||
@ -811,7 +817,8 @@ fn (g mut Gen) expr(node ast.Expr) {
|
||||
*/
|
||||
|
||||
ast.SizeOf {
|
||||
g.write('sizeof($it.type_name)')
|
||||
styp := g.typ(it.typ)
|
||||
g.write('sizeof($styp)')
|
||||
}
|
||||
ast.StringLiteral {
|
||||
// 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')
|
||||
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)
|
||||
mut tmp := ''
|
||||
if type_sym.kind != .void {
|
||||
tmp = g.new_tmp_var()
|
||||
}
|
||||
//styp := g.typ(node.expr_type)
|
||||
//g.write('$styp $tmp = ')
|
||||
//g.expr(node.cond)
|
||||
//g.writeln(';') // $it.blocks.len')
|
||||
// styp := g.typ(node.expr_type)
|
||||
// g.write('$styp $tmp = ')
|
||||
// g.expr(node.cond)
|
||||
// g.writeln(';') // $it.blocks.len')
|
||||
// mut sum_type_str = ''
|
||||
for j, branch in node.branches {
|
||||
if j == node.branches.len - 1 {
|
||||
// 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 {
|
||||
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 {
|
||||
if node.is_sum_type {
|
||||
g.expr(node.cond )
|
||||
g.expr(node.cond)
|
||||
g.write('.typ == ')
|
||||
//g.write('${tmp}.typ == ')
|
||||
// g.write('${tmp}.typ == ')
|
||||
// sum_type_str
|
||||
}
|
||||
else if type_sym.kind == .string {
|
||||
g.write('string_eq(')
|
||||
//
|
||||
g.expr(node.cond)
|
||||
g.write(', ')
|
||||
//g.write('string_eq($tmp, ')
|
||||
g.expr(node.cond)
|
||||
g.write(', ')
|
||||
// g.write('string_eq($tmp, ')
|
||||
}
|
||||
else {
|
||||
g.expr(node.cond)
|
||||
g.write(' == ')
|
||||
//g.write('$tmp == ')
|
||||
// g.write('$tmp == ')
|
||||
}
|
||||
g.expr(expr)
|
||||
if type_sym.kind == .string {
|
||||
@ -1013,7 +1041,12 @@ g.write(', ')
|
||||
g.write(' || ')
|
||||
}
|
||||
}
|
||||
g.writeln(') {')
|
||||
if is_expr {
|
||||
g.write(') ? ')
|
||||
}
|
||||
else {
|
||||
g.writeln(') {')
|
||||
}
|
||||
}
|
||||
if node.is_sum_type && branch.exprs.len > 0 {
|
||||
// The first node in expr is an ast.Type
|
||||
@ -1022,7 +1055,10 @@ g.write(', ')
|
||||
match fe {
|
||||
ast.Type {
|
||||
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 {
|
||||
verror('match sum type')
|
||||
@ -1030,8 +1066,11 @@ g.write(', ')
|
||||
}
|
||||
}
|
||||
g.stmts(branch.stmts)
|
||||
g.writeln('}')
|
||||
if !g.inside_ternary {
|
||||
g.writeln('}')
|
||||
}
|
||||
}
|
||||
g.inside_ternary = false
|
||||
}
|
||||
|
||||
fn (g mut Gen) ident(node ast.Ident) {
|
||||
@ -1067,12 +1106,13 @@ fn (g mut Gen) if_expr(node ast.IfExpr) {
|
||||
}
|
||||
// one line ?:
|
||||
// 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
|
||||
stmt1 := node.stmts[0]
|
||||
else_stmt1 := node.else_stmts[0]
|
||||
match stmt1 {
|
||||
ast.ExprStmt {
|
||||
g.inside_ternary = true
|
||||
g.expr(cond)
|
||||
g.write(' ? ')
|
||||
expr_stmt := stmt1 as ast.ExprStmt
|
||||
@ -1081,7 +1121,7 @@ fn (g mut Gen) if_expr(node ast.IfExpr) {
|
||||
g.stmt(else_stmt1)
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
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)) {')
|
||||
}
|
||||
else {
|
||||
g.inside_ternary = false
|
||||
g.write('if (')
|
||||
g.expr(node.cond)
|
||||
g.writeln(') {')
|
||||
}
|
||||
}
|
||||
}
|
||||
for i, stmt in node.stmts {
|
||||
// Assign ret value
|
||||
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('}')
|
||||
if node.else_stmts.len > 0 {
|
||||
if is_guard {
|
||||
g.writeln('if !$guard_ok { /* else */')
|
||||
} else {
|
||||
g.writeln('if (!$guard_ok) { /* else */')
|
||||
}
|
||||
else {
|
||||
g.writeln('else { ')
|
||||
}
|
||||
for stmt in node.else_stmts {
|
||||
@ -1123,6 +1165,7 @@ fn (g mut Gen) if_expr(node ast.IfExpr) {
|
||||
g.writeln('}')
|
||||
}
|
||||
}
|
||||
g.inside_ternary = false
|
||||
}
|
||||
|
||||
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) {
|
||||
g.write('return')
|
||||
if g.fn_decl.name == 'main' {
|
||||
g.writeln(' 0;')
|
||||
return
|
||||
}
|
||||
// multiple returns
|
||||
if it.exprs.len > 1 {
|
||||
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('${term_fail} ${i}')
|
||||
println(term.red('i=$i "$line_a" expected="$line_b"'))
|
||||
// println(lines_b[i + 1])
|
||||
// println(lines_b[i + 2])
|
||||
println(lines_b[i + 1])
|
||||
println(lines_b[i + 2])
|
||||
// exit(1)
|
||||
return false
|
||||
}
|
||||
|
@ -149,7 +149,6 @@ multi_return_int_string multi_return() {
|
||||
void variadic(varg_int a) {
|
||||
int x = path_sep;
|
||||
int y = true ? 1 : 0;
|
||||
;
|
||||
}
|
||||
|
||||
void ensure_cap(int required, int cap) {
|
||||
@ -172,6 +171,9 @@ void matches() {
|
||||
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
|
||||
|
@ -156,6 +156,17 @@ fn matches() {
|
||||
}
|
||||
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 {
|
||||
1 { 10 }
|
||||
|
@ -40,11 +40,11 @@ void println(string s) {
|
||||
|
||||
void handle_expr(Expr e) {
|
||||
if (e.typ == _type_idx_IfExpr) {
|
||||
IfExpr* it = (IfExpr*)tmp1.obj; // ST it
|
||||
IfExpr* it = (IfExpr*)e.obj; // ST it
|
||||
println(tos3("if"));
|
||||
}
|
||||
else if (e.typ == _type_idx_IntegerLiteral) {
|
||||
IntegerLiteral* it = (IntegerLiteral*)tmp1.obj; // ST it
|
||||
IntegerLiteral* it = (IntegerLiteral*)e.obj; // ST it
|
||||
println(tos3("integer"));
|
||||
}
|
||||
else {
|
||||
|
@ -748,10 +748,13 @@ pub fn (p mut Parser) expr(precedence int) ast.Expr {
|
||||
if p.tok.kind == .amp {
|
||||
p.next()
|
||||
}
|
||||
type_name := p.check_name()
|
||||
// type_name := p.check_name()
|
||||
sizeof_type := p.parse_type()
|
||||
p.check(.rpar)
|
||||
node = ast.SizeOf{
|
||||
type_name: type_name
|
||||
typ: sizeof_type
|
||||
// type_name: type_name
|
||||
|
||||
}
|
||||
}
|
||||
// Map `{"age": 20}` or `{ x | foo:bar, a:10 }`
|
||||
|
Loading…
Reference in New Issue
Block a user