ast: first step merging CallExpr & MethodCallExpr

pull/4159/head
joe-conigliaro 2020-03-30 21:39:20 +11:00
parent 7785583b34
commit 3440d7edd8
No known key found for this signature in database
GPG Key ID: C12F7136C08206F1
5 changed files with 324 additions and 339 deletions

View File

@ -11,10 +11,10 @@ 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 |
AssignExpr | PrefixExpr | MethodCallExpr | IndexExpr | RangeExpr | MatchExpr | PostfixExpr | AssignExpr | PrefixExpr | IndexExpr | RangeExpr | MatchExpr | CastExpr |
CastExpr | EnumVal | Assoc | SizeOf | None | MapInit | IfGuardExpr | ParExpr | OrExpr | EnumVal | Assoc | SizeOf | None | MapInit | IfGuardExpr | ParExpr | OrExpr | ConcatExpr |
ConcatExpr | Type | AsCast | TypeOf | StringInterLiteral Type | AsCast | TypeOf | StringInterLiteral
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 |
@ -173,29 +173,16 @@ pub struct CallExpr {
pub: pub:
// tok token.Token // tok token.Token
pos token.Position pos token.Position
left Expr // `user` in `user.register()`
is_method bool
mut: mut:
// func Expr
name string name string
args []CallArg args []CallArg
exp_arg_types []table.Type exp_arg_types []table.Type
is_c bool is_c bool
muts []bool
or_block OrExpr or_block OrExpr
// has_or_block bool // has_or_block bool
return_type table.Type left_type table.Type // type of `user`
}
pub struct MethodCallExpr {
pub:
// tok token.Token
pos token.Position
expr Expr // `user` in `user.register()`
name string
args []CallArg
or_block OrExpr
mut:
exp_arg_types []table.Type
expr_type table.Type // type of `user`
receiver_type table.Type // User receiver_type table.Type // User
return_type table.Type return_type table.Type
} }
@ -711,9 +698,6 @@ pub fn expr_is_call(expr Expr) bool {
CallExpr{ CallExpr{
true true
} }
MethodCallExpr{
true
}
else { else {
false} false}
} }

View File

@ -168,8 +168,84 @@ fn (c mut Checker) assign_expr(assign_expr mut ast.AssignExpr) {
} }
pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type { pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
fn_name := call_expr.name
c.stmts(call_expr.or_block.stmts) c.stmts(call_expr.or_block.stmts)
if call_expr.is_method {
left_type := c.expr(call_expr.left)
call_expr.left_type = left_type
left_type_sym := c.table.get_type_symbol(left_type)
method_name := call_expr.name
// TODO: remove this for actual methods, use only for compiler magic
if left_type_sym.kind == .array && method_name in ['filter', 'clone', 'repeat', 'reverse', 'map', 'slice'] {
if method_name in ['filter', 'map'] {
array_info := left_type_sym.info as table.Array
mut scope := c.file.scope.innermost(call_expr.pos.pos)
scope.update_var_type('it', array_info.elem_type)
}
for i, arg in call_expr.args {
c.expr(arg.expr)
}
// need to return `array_xxx` instead of `array`
call_expr.return_type = left_type
if method_name == 'clone' {
// in ['clone', 'str'] {
call_expr.receiver_type = table.type_to_ptr(left_type)
// call_expr.return_type = call_expr.receiver_type
}
else {
call_expr.receiver_type = left_type
}
return left_type
}
else if left_type_sym.kind == .array && method_name in ['first', 'last'] {
info := left_type_sym.info as table.Array
call_expr.return_type = info.elem_type
call_expr.receiver_type = left_type
return info.elem_type
}
if method := c.table.type_find_method(left_type_sym, method_name) {
no_args := method.args.len - 1
min_required_args := method.args.len - if method.is_variadic && method.args.len > 1 { 2 } else { 1 }
if call_expr.args.len < min_required_args {
c.error('too few arguments in call to `${left_type_sym.name}.$method_name` ($call_expr.args.len instead of $min_required_args)', call_expr.pos)
}
else if !method.is_variadic && call_expr.args.len > no_args {
c.error('too many arguments in call to `${left_type_sym.name}.$method_name` ($call_expr.args.len instead of $no_args)', call_expr.pos)
}
// if method_name == 'clone' {
// println('CLONE nr args=$method.args.len')
// }
// call_expr.args << method.args[0].typ
// call_expr.exp_arg_types << method.args[0].typ
for i, arg in call_expr.args {
c.expected_type = if method.is_variadic && i >= method.args.len - 1 { method.args[method.args.len - 1].typ } else { method.args[i + 1].typ }
call_expr.args[i].typ = c.expr(arg.expr)
}
// TODO: typ optimize.. this node can get processed more than once
if call_expr.exp_arg_types.len == 0 {
for i in 1 .. method.args.len {
call_expr.exp_arg_types << method.args[i].typ
}
}
call_expr.receiver_type = method.args[0].typ
call_expr.return_type = method.return_type
return method.return_type
}
// TODO: str methods
if left_type_sym.kind == .map && method_name == 'str' {
call_expr.receiver_type = table.new_type(c.table.type_idxs['map_string'])
call_expr.return_type = table.string_type
return table.string_type
}
if left_type_sym.kind == .array && method_name == 'str' {
call_expr.receiver_type = left_type
call_expr.return_type = table.string_type
return table.string_type
}
c.error('unknown method: ${left_type_sym.name}.$method_name', call_expr.pos)
return table.void_type
}
else {
fn_name := call_expr.name
// TODO: impl typeof properly (probably not going to be a fn call) // TODO: impl typeof properly (probably not going to be a fn call)
if fn_name == 'typeof' { if fn_name == 'typeof' {
return table.string_type return table.string_type
@ -271,83 +347,6 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
} }
return f.return_type return f.return_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)
name := method_call_expr.name
c.stmts(method_call_expr.or_block.stmts)
// println('method call $name $method_call_expr.pos.line_nr')
// TODO: remove this for actual methods, use only for compiler magic
if typ_sym.kind == .array && name in ['filter', 'clone', 'repeat', 'reverse', 'map', 'slice'] {
if name in ['filter', 'map'] {
array_info := typ_sym.info as table.Array
mut scope := c.file.scope.innermost(method_call_expr.pos.pos)
scope.update_var_type('it', array_info.elem_type)
}
for i, arg in method_call_expr.args {
c.expr(arg.expr)
}
// need to return `array_xxx` instead of `array`
method_call_expr.return_type = typ
if name == 'clone' {
// in ['clone', 'str'] {
method_call_expr.receiver_type = table.type_to_ptr(typ)
// method_call_expr.return_type = method_call_expr.receiver_type
}
else {
method_call_expr.receiver_type = typ
}
return typ
}
else if typ_sym.kind == .array && name in ['first', 'last'] {
info := typ_sym.info as table.Array
method_call_expr.return_type = info.elem_type
method_call_expr.receiver_type = typ
return info.elem_type
}
if method := c.table.type_find_method(typ_sym, name) {
no_args := method.args.len - 1
min_required_args := method.args.len - if method.is_variadic && method.args.len > 1 { 2 } else { 1 }
if method_call_expr.args.len < min_required_args {
c.error('too few arguments in call to `${typ_sym.name}.$name` ($method_call_expr.args.len instead of $min_required_args)', method_call_expr.pos)
}
else if !method.is_variadic && method_call_expr.args.len > no_args {
c.error('too many arguments in call to `${typ_sym.name}.$name` ($method_call_expr.args.len instead of $no_args)', method_call_expr.pos)
}
// if name == 'clone' {
// println('CLONE nr args=$method.args.len')
// }
for i, arg in method_call_expr.args {
c.expected_type = if method.is_variadic && i >= method.args.len - 1 { method.args[method.args.len - 1].typ } else { method.args[i + 1].typ }
method_call_expr.args[i].typ = c.expr(arg.expr)
}
// TODO: typ optimize.. this node can get processed more than once
if method_call_expr.exp_arg_types.len == 0 {
for i in 1 .. method.args.len {
method_call_expr.exp_arg_types << method.args[i].typ
}
}
method_call_expr.receiver_type = method.args[0].typ
method_call_expr.return_type = method.return_type
return method.return_type
}
// TODO: str methods
if typ_sym.kind == .map && name == 'str' {
method_call_expr.receiver_type = table.new_type(c.table.type_idxs['map_string'])
method_call_expr.return_type = table.string_type
return table.string_type
}
if typ_sym.kind == .array && name == 'str' {
method_call_expr.receiver_type = typ
method_call_expr.return_type = table.string_type
return table.string_type
}
c.error('type `$typ_sym.name` has no method `$name`', method_call_expr.pos)
return table.void_type
} }
pub fn (c mut Checker) selector_expr(selector_expr mut ast.SelectorExpr) table.Type { pub fn (c mut Checker) selector_expr(selector_expr mut ast.SelectorExpr) table.Type {
@ -731,9 +730,6 @@ pub fn (c mut Checker) expr(node ast.Expr) table.Type {
ast.MatchExpr { ast.MatchExpr {
return c.match_expr(mut it) return c.match_expr(mut it)
} }
ast.MethodCallExpr {
return c.method_call_expr(mut it)
}
ast.PostfixExpr { ast.PostfixExpr {
return c.postfix_expr(it) return c.postfix_expr(it)
} }

View File

@ -388,11 +388,20 @@ fn (f mut Fmt) expr(node ast.Expr) {
f.write(')') f.write(')')
} }
ast.CallExpr { ast.CallExpr {
if it.is_method {
f.expr(it.left)
f.write('.' + it.name + '(')
f.call_args(it.args)
f.write(')')
f.or_expr(it.or_block)
}
else {
f.write('${it.name}(') f.write('${it.name}(')
f.call_args(it.args) f.call_args(it.args)
f.write(')') f.write(')')
f.or_expr(it.or_block) f.or_expr(it.or_block)
} }
}
ast.CharLiteral { ast.CharLiteral {
f.write('`$it.val`') f.write('`$it.val`')
} }
@ -510,13 +519,6 @@ fn (f mut Fmt) expr(node ast.Expr) {
f.indent-- f.indent--
f.write('}') f.write('}')
} }
ast.MethodCallExpr {
f.expr(it.expr)
f.write('.' + it.name + '(')
f.call_args(it.args)
f.write(')')
f.or_expr(it.or_block)
}
ast.None { ast.None {
f.write('none') f.write('none')
} }

View File

@ -578,9 +578,6 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
ast.CallExpr { ast.CallExpr {
return_type = it.return_type return_type = it.return_type
} }
ast.MethodCallExpr {
return_type = it.return_type
}
else { else {
panic('expected call') panic('expected call')
} }
@ -1041,70 +1038,6 @@ fn (g mut Gen) expr(node ast.Expr) {
g.write('new_map(1, sizeof($value_typ_str))') g.write('new_map(1, sizeof($value_typ_str))')
} }
} }
ast.MethodCallExpr {
// TODO: there are still due to unchecked exprs (opt/some fn arg)
if it.expr_type == 0 {
verror('method receiver type is 0, this means there are some uchecked exprs')
}
typ_sym := g.table.get_type_symbol(it.receiver_type)
// rec_sym := g.table.get_type_symbol(it.receiver_type)
mut receiver_name := typ_sym.name
if typ_sym.kind == .array && it.name == 'filter' {
g.gen_filter(it)
return
}
if typ_sym.kind == .array && it.name in
// TODO performance, detect `array` method differently
['repeat', 'sort_with_compare', 'free', 'push_many', 'trim',
//
'first', 'last', 'clone', 'reverse', 'slice'] {
// && rec_sym.name == 'array' {
// && rec_sym.name == 'array' && receiver_name.starts_with('array') {
// `array_byte_clone` => `array_clone`
receiver_name = 'array'
if it.name in ['last', 'first'] {
return_type_str := g.typ(it.return_type)
g.write('*($return_type_str*)')
}
}
name := '${receiver_name}_$it.name'.replace('.', '__')
// if it.receiver_type != 0 {
// g.write('/*${g.typ(it.receiver_type)}*/')
// g.write('/*expr_type=${g.typ(it.expr_type)} rec type=${g.typ(it.receiver_type)}*/')
// }
g.write('${name}(')
if table.type_is_ptr(it.receiver_type) && !table.type_is_ptr(it.expr_type) {
// The receiver is a reference, but the caller provided a value
// Add `&` automatically.
// TODO same logic in call_args()
g.write('&')
}
else if !table.type_is_ptr(it.receiver_type) && table.type_is_ptr(it.expr_type) {
g.write('/*rec*/*')
}
g.expr(it.expr)
is_variadic := it.exp_arg_types.len > 0 && table.type_is_variadic(it.exp_arg_types[it.exp_arg_types.len - 1])
if it.args.len > 0 || is_variadic {
g.write(', ')
}
// /////////
/*
if name.contains('subkeys') {
println('call_args $name $it.arg_types.len')
for t in it.arg_types {
sym := g.table.get_type_symbol(t)
print('$sym.name ')
}
println('')
}
*/
// ///////
g.call_args(it.args, it.exp_arg_types)
g.write(')')
if it.or_block.stmts.len > 0 {
g.or_block(it.or_block.stmts, it.return_type)
}
}
ast.None { ast.None {
g.write('opt_none()') g.write('opt_none()')
} }
@ -1673,7 +1606,7 @@ fn (g mut Gen) index_expr(node ast.IndexExpr) {
} }
} }
fn (g mut Gen) return_statement(it ast.Return) { fn (g mut Gen) return_statement(node ast.Return) {
g.write('return') g.write('return')
if g.fn_decl.name == 'main' { if g.fn_decl.name == 'main' {
g.writeln(' 0;') g.writeln(' 0;')
@ -1681,7 +1614,7 @@ fn (g mut Gen) return_statement(it ast.Return) {
} }
fn_return_is_optional := table.type_is_optional(g.fn_decl.return_type) fn_return_is_optional := table.type_is_optional(g.fn_decl.return_type)
// multiple returns // multiple returns
if it.exprs.len > 1 { if node.exprs.len > 1 {
g.write(' ') g.write(' ')
typ_sym := g.table.get_type_symbol(g.fn_decl.return_type) typ_sym := g.table.get_type_symbol(g.fn_decl.return_type)
mr_info := typ_sym.info as table.MultiReturn mr_info := typ_sym.info as table.MultiReturn
@ -1691,10 +1624,10 @@ fn (g mut Gen) return_statement(it ast.Return) {
g.write('opt_ok(& ($styp []) { ') g.write('opt_ok(& ($styp []) { ')
} }
g.write('($styp){') g.write('($styp){')
for i, expr in it.exprs { for i, expr in node.exprs {
g.write('.arg$i=') g.write('.arg$i=')
g.expr(expr) g.expr(expr)
if i < it.exprs.len - 1 { if i < node.exprs.len - 1 {
g.write(',') g.write(',')
} }
} }
@ -1704,36 +1637,39 @@ fn (g mut Gen) return_statement(it ast.Return) {
} }
} }
// normal return // normal return
else if it.exprs.len == 1 { else if node.exprs.len == 1 {
g.write(' ') g.write(' ')
// `return opt_ok(expr)` for functions that expect an optional // `return opt_ok(expr)` for functions that expect an optional
if fn_return_is_optional && !table.type_is_optional(it.types[0]) { if fn_return_is_optional && !table.type_is_optional(node.types[0]) {
mut is_none := false mut is_none := false
mut is_error := false mut is_error := false
expr0 := it.exprs[0] expr0 := node.exprs[0]
match expr0 { match expr0 {
ast.None { ast.None {
is_none = true is_none = true
} }
ast.CallExpr { ast.CallExpr {
// TODO: why?
if !it.is_method {
is_error = true // TODO check name 'error' is_error = true // TODO check name 'error'
} }
}
else {} else {}
} }
if !is_none && !is_error { if !is_none && !is_error {
styp := g.typ(g.fn_decl.return_type)[7..] // remove 'Option_' styp := g.typ(g.fn_decl.return_type)[7..] // remove 'Option_'
g.write('opt_ok(& ($styp []) { ') g.write('opt_ok(& ($styp []) { ')
g.expr(it.exprs[0]) g.expr(node.exprs[0])
g.writeln(' }, sizeof($styp));') g.writeln(' }, sizeof($styp));')
return return
} }
// g.write('/*OPTIONAL*/') // g.write('/*OPTIONAL*/')
} }
if !table.type_is_ptr(g.fn_decl.return_type) && table.type_is_ptr(it.types[0]) { if !table.type_is_ptr(g.fn_decl.return_type) && table.type_is_ptr(node.types[0]) {
// Automatic Dereference // Automatic Dereference
g.write('*') g.write('*')
} }
g.expr_with_cast(it.exprs[0], it.types[0], g.fn_decl.return_type) g.expr_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type)
} }
g.writeln(';') g.writeln(';')
} }
@ -2168,7 +2104,7 @@ fn (g mut Gen) string_inter_literal(node ast.StringInterLiteral) {
} }
// `nums.filter(it % 2 == 0)` // `nums.filter(it % 2 == 0)`
fn (g mut Gen) gen_filter(node ast.MethodCallExpr) { fn (g mut Gen) gen_filter(node ast.CallExpr) {
tmp := g.new_tmp_var() tmp := g.new_tmp_var()
buf := g.out.buf[g.stmt_start_pos..] buf := g.out.buf[g.stmt_start_pos..]
s := string(buf.clone()) // the already generated part of current statement s := string(buf.clone()) // the already generated part of current statement
@ -2182,12 +2118,12 @@ fn (g mut Gen) gen_filter(node ast.MethodCallExpr) {
styp := g.typ(node.return_type) styp := g.typ(node.return_type)
elem_type_str := g.typ(info.elem_type) elem_type_str := g.typ(info.elem_type)
g.write('\nint ${tmp}_len = ') g.write('\nint ${tmp}_len = ')
g.expr(node.expr) g.expr(node.left)
g.writeln('.len;') g.writeln('.len;')
g.writeln('$styp $tmp = new_array(0, ${tmp}_len, sizeof($elem_type_str));') g.writeln('$styp $tmp = new_array(0, ${tmp}_len, sizeof($elem_type_str));')
g.writeln('for (int i = 0; i < ${tmp}_len; i++) {') g.writeln('for (int i = 0; i < ${tmp}_len; i++) {')
g.write(' $elem_type_str it = (($elem_type_str*) ') g.write(' $elem_type_str it = (($elem_type_str*) ')
g.expr(node.expr) g.expr(node.left)
g.writeln('.data)[i];') g.writeln('.data)[i];')
g.write('if (') g.write('if (')
g.expr(node.args[0].expr) // the first arg is the filter condition g.expr(node.args[0].expr) // the first arg is the filter condition
@ -2204,10 +2140,75 @@ fn (g mut Gen) insert_before(s string) {
g.write(cur_line) g.write(cur_line)
} }
fn (g mut Gen) call_expr(it ast.CallExpr) { fn (g mut Gen) call_expr(node ast.CallExpr) {
mut name := it.name if node.is_method {
// TODO: there are still due to unchecked exprs (opt/some fn arg)
if node.left_type == 0 {
verror('method receiver type is 0, this means there are some uchecked exprs')
}
typ_sym := g.table.get_type_symbol(node.receiver_type)
// rec_sym := g.table.get_type_symbol(node.receiver_type)
mut receiver_name := typ_sym.name
if typ_sym.kind == .array && node.name == 'filter' {
g.gen_filter(node)
return
}
if typ_sym.kind == .array && node.name in
// TODO performance, detect `array` method differently
['repeat', 'sort_with_compare', 'free', 'push_many', 'trim',
//
'first', 'last', 'clone', 'reverse', 'slice'] {
// && rec_sym.name == 'array' {
// && rec_sym.name == 'array' && receiver_name.starts_with('array') {
// `array_byte_clone` => `array_clone`
receiver_name = 'array'
if node.name in ['last', 'first'] {
return_type_str := g.typ(node.return_type)
g.write('*($return_type_str*)')
}
}
name := '${receiver_name}_$node.name'.replace('.', '__')
// if node.receiver_type != 0 {
// g.write('/*${g.typ(node.receiver_type)}*/')
// g.write('/*expr_type=${g.typ(node.left_type)} rec type=${g.typ(node.receiver_type)}*/')
// }
g.write('${name}(')
if table.type_is_ptr(node.receiver_type) && !table.type_is_ptr(node.left_type) {
// The receiver is a reference, but the caller provided a value
// Add `&` automatically.
// TODO same logic in call_args()
g.write('&')
}
else if !table.type_is_ptr(node.receiver_type) && table.type_is_ptr(node.left_type) {
g.write('/*rec*/*')
}
g.expr(node.left)
is_variadic := node.exp_arg_types.len > 0 && table.type_is_variadic(node.exp_arg_types[node.exp_arg_types.len - 1])
if node.args.len > 0 || is_variadic {
g.write(', ')
}
// /////////
/*
if name.contains('subkeys') {
println('call_args $name $node.arg_types.len')
for t in node.arg_types {
sym := g.table.get_type_symbol(t)
print('$sym.name ')
}
println('')
}
*/
// ///////
g.call_args(node.args, node.exp_arg_types)
g.write(')')
if node.or_block.stmts.len > 0 {
g.or_block(node.or_block.stmts, node.return_type)
}
}
else {
mut name := node.name
is_print := name == 'println' is_print := name == 'println'
if it.is_c { if node.is_c {
// Skip "C." // Skip "C."
g.is_c_call = true g.is_c_call = true
name = name[2..].replace('.', '__') name = name[2..].replace('.', '__')
@ -2218,7 +2219,7 @@ fn (g mut Gen) call_expr(it ast.CallExpr) {
// Generate tmp vars for values that have to be freed. // Generate tmp vars for values that have to be freed.
/* /*
mut tmps := []string mut tmps := []string
for arg in it.args { for arg in node.args {
if arg.typ == table.string_type_idx || is_print { if arg.typ == table.string_type_idx || is_print {
tmp := g.new_tmp_var() tmp := g.new_tmp_var()
tmps << tmp tmps << tmp
@ -2229,8 +2230,8 @@ fn (g mut Gen) call_expr(it ast.CallExpr) {
} }
*/ */
if is_print && it.args[0].typ != table.string_type_idx { if is_print && node.args[0].typ != table.string_type_idx {
typ := it.args[0].typ typ := node.args[0].typ
mut styp := g.typ(typ) mut styp := g.typ(typ)
sym := g.table.get_type_symbol(typ) sym := g.table.get_type_symbol(typ)
if !sym.has_method('str') && !(int(typ) in g.str_types) { if !sym.has_method('str') && !(int(typ) in g.str_types) {
@ -2245,27 +2246,28 @@ fn (g mut Gen) call_expr(it ast.CallExpr) {
tmp := g.new_tmp_var() tmp := g.new_tmp_var()
// tmps << tmp // tmps << tmp
g.write('string $tmp = ${styp}_str(') g.write('string $tmp = ${styp}_str(')
g.expr(it.args[0].expr) g.expr(node.args[0].expr)
g.writeln('); println($tmp); string_free($tmp); //MEM2 $styp') g.writeln('); println($tmp); string_free($tmp); //MEM2 $styp')
} }
else { else {
// `println(int_str(10))` // `println(int_str(10))`
// sym := g.table.get_type_symbol(it.args[0].typ) // sym := g.table.get_type_symbol(node.args[0].typ)
g.write('println(${styp}_str(') g.write('println(${styp}_str(')
g.expr(it.args[0].expr) g.expr(node.args[0].expr)
g.write('))') g.write('))')
} }
} }
else { else {
g.write('${name}(') g.write('${name}(')
g.call_args(it.args, it.exp_arg_types) g.call_args(node.args, node.exp_arg_types)
g.write(')') g.write(')')
} }
if it.or_block.stmts.len > 0 { if node.or_block.stmts.len > 0 {
g.or_block(it.or_block.stmts, it.return_type) g.or_block(node.or_block.stmts, node.return_type)
} }
g.is_c_call = false g.is_c_call = false
} }
}
fn (g mut Gen) or_block(stmts []ast.Stmt, return_type table.Type) { fn (g mut Gen) or_block(stmts []ast.Stmt, return_type table.Type) {
// `foo() or { return }` // `foo() or { return }`

View File

@ -1005,11 +1005,12 @@ fn (p mut Parser) dot_expr(left ast.Expr) ast.Expr {
or_stmts = p.parse_block_no_scope() or_stmts = p.parse_block_no_scope()
p.close_scope() p.close_scope()
} }
mcall_expr := ast.MethodCallExpr{ mcall_expr := ast.CallExpr{
expr: left left: left
name: field_name name: field_name
args: args args: args
pos: pos pos: pos
is_method: true
or_block: ast.OrExpr{ or_block: ast.OrExpr{
stmts: or_stmts stmts: or_stmts
} }