cgen: pass around functions
parent
4de48e86d2
commit
b16281d6e4
|
@ -1614,8 +1614,10 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
|||
return table.string_type
|
||||
}
|
||||
ast.AnonFn {
|
||||
keep_ret_type := c.fn_return_type
|
||||
c.fn_return_type = it.decl.return_type
|
||||
c.stmts(it.decl.stmts)
|
||||
c.fn_return_type = keep_ret_type
|
||||
return it.typ
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -358,7 +358,10 @@ typedef struct {
|
|||
.function {
|
||||
info := typ.info as table.FnType
|
||||
func := info.func
|
||||
if !info.has_decl && !info.is_anon {
|
||||
sym := g.table.get_type_symbol(func.return_type)
|
||||
is_multi := sym.kind == .multi_return
|
||||
is_fn_sig := func.name == ''
|
||||
if !info.has_decl && (!info.is_anon || is_fn_sig) && !is_multi {
|
||||
fn_name := if func.is_c {
|
||||
func.name.replace('.', '__')
|
||||
} else if info.is_anon {
|
||||
|
@ -556,6 +559,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
println('build module `$g.module_built` fn `$it.name`')
|
||||
}
|
||||
}
|
||||
keep_fn_decl := g.fn_decl
|
||||
g.fn_decl = it // &it
|
||||
if it.name == 'main' {
|
||||
// just remember `it`; main code will be generated in finish()
|
||||
|
@ -563,7 +567,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
} else {
|
||||
g.gen_fn_decl(it)
|
||||
}
|
||||
g.fn_decl = 0
|
||||
g.fn_decl = keep_fn_decl
|
||||
if skip {
|
||||
g.out.go_back_to(pos)
|
||||
}
|
||||
|
@ -820,15 +824,22 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
if assign_stmt.is_static {
|
||||
g.write('static ')
|
||||
}
|
||||
if assign_stmt.left.len > assign_stmt.right.len {
|
||||
// multi return
|
||||
mut or_stmts := []ast.Stmt{}
|
||||
mut return_type := table.void_type
|
||||
if assign_stmt.right[0] is ast.CallExpr {
|
||||
it := assign_stmt.right[0] as ast.CallExpr
|
||||
or_stmts = it.or_block.stmts
|
||||
return_type = it.return_type
|
||||
}
|
||||
mut is_multi := false
|
||||
// json_test failed w/o this check
|
||||
if return_type != 0 {
|
||||
sym := g.table.get_type_symbol(return_type)
|
||||
// the left vs. right is ugly and should be removed
|
||||
is_multi = sym.kind == .multi_return || assign_stmt.left.len > assign_stmt.right.len ||
|
||||
assign_stmt.left.len > 1
|
||||
}
|
||||
if is_multi {
|
||||
// multi return
|
||||
mut or_stmts := []ast.Stmt{}
|
||||
is_optional := return_type.flag_is(.optional)
|
||||
mr_var_name := 'mr_$assign_stmt.pos.pos'
|
||||
mr_styp := g.typ(return_type)
|
||||
|
@ -865,7 +876,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
styp := g.typ(ident_var_info.typ)
|
||||
mut is_call := false
|
||||
mut or_stmts := []ast.Stmt{}
|
||||
mut return_type := table.void_type
|
||||
blank_assign := ident.kind == .blank_ident
|
||||
match val {
|
||||
ast.CallExpr {
|
||||
is_call = true
|
||||
|
@ -874,6 +885,9 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
}
|
||||
ast.AnonFn {
|
||||
// TODO: no buffer fiddling
|
||||
if blank_assign {
|
||||
g.write('{')
|
||||
}
|
||||
ret_styp := g.typ(it.decl.return_type)
|
||||
g.write('$ret_styp (*$ident.name) (')
|
||||
def_pos := g.definitions.len
|
||||
|
@ -882,13 +896,16 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
g.write(') = ')
|
||||
g.expr(*it)
|
||||
g.writeln(';')
|
||||
if blank_assign {
|
||||
g.write('}')
|
||||
}
|
||||
continue
|
||||
}
|
||||
else {}
|
||||
}
|
||||
gen_or := is_call && return_type.flag_is(.optional)
|
||||
g.is_assign_rhs = true
|
||||
if ident.kind == .blank_ident {
|
||||
if blank_assign {
|
||||
if is_call {
|
||||
g.expr(val)
|
||||
} else {
|
||||
|
@ -1909,8 +1926,13 @@ fn (mut g Gen) return_statement(node ast.Return) {
|
|||
return
|
||||
}
|
||||
fn_return_is_optional := g.fn_decl.return_type.flag_is(.optional)
|
||||
// multiple returns
|
||||
if node.exprs.len > 1 {
|
||||
|
||||
// got to do a correct check for multireturn
|
||||
sym := g.table.get_type_symbol(g.fn_decl.return_type)
|
||||
fn_return_is_multi := sym.kind == .multi_return
|
||||
|
||||
// optional multi not supported
|
||||
if fn_return_is_multi && !fn_return_is_optional {
|
||||
g.write(' ')
|
||||
// typ_sym := g.table.get_type_symbol(g.fn_decl.return_type)
|
||||
// mr_info := typ_sym.info as table.MultiReturn
|
||||
|
@ -1933,7 +1955,7 @@ fn (mut g Gen) return_statement(node ast.Return) {
|
|||
if fn_return_is_optional {
|
||||
g.write(' }, sizeof($styp))')
|
||||
}
|
||||
} else if node.exprs.len == 1 {
|
||||
} else if node.exprs.len >= 1 {
|
||||
// normal return
|
||||
g.write(' ')
|
||||
return_sym := g.table.get_type_symbol(node.types[0])
|
||||
|
|
|
@ -369,11 +369,12 @@ pub fn (mut t Table) find_or_register_multi_return(mr_typs []Type) int {
|
|||
|
||||
pub fn (mut t Table) find_or_register_fn_type(f Fn, is_anon, has_decl bool) int {
|
||||
name := if f.name.len == 0 { 'anon_fn_$f.signature()' } else { f.name }
|
||||
anon := f.name.len == 0 || is_anon
|
||||
return t.register_type_symbol(TypeSymbol{
|
||||
kind: .function
|
||||
name: name
|
||||
info: FnType{
|
||||
is_anon: f.name.len == 0 || is_anon
|
||||
is_anon: anon
|
||||
has_decl: has_decl
|
||||
func: f
|
||||
}
|
||||
|
|
|
@ -120,6 +120,58 @@ fn high_fn_multi_return(a int, b fn (c []int, d []string) ([]int, []string)) {
|
|||
|
||||
}
|
||||
|
||||
fn high_fn_return_single_anon() (fn(int)f32) {
|
||||
_ := 1
|
||||
correct := fn(n int)f32 {
|
||||
return n * n
|
||||
}
|
||||
return correct
|
||||
}
|
||||
fn high_fn_return_multi_anons() (fn(int)f32, fn(int)string) {
|
||||
// parsing trap
|
||||
_ := fn(n int)byte {
|
||||
return 0x00
|
||||
}
|
||||
correct_second := fn(n int)string {
|
||||
return '$n'
|
||||
}
|
||||
correct_first := fn(n int)f32 {
|
||||
return n * n
|
||||
}
|
||||
// parsing trap
|
||||
_ := fn(n int)[]int {
|
||||
return [n]
|
||||
}
|
||||
return correct_first, correct_second
|
||||
}
|
||||
fn high_fn_return_named_fn() (fn(int)int) {
|
||||
return sqr
|
||||
}
|
||||
fn test_high_fn_ret_anons() {
|
||||
param := 13
|
||||
func_sqr1 := high_fn_return_single_anon()
|
||||
assert func_sqr1(param) == param * param
|
||||
|
||||
func_sqr2, func_repr := high_fn_return_multi_anons()
|
||||
assert func_sqr2(param) == (param * param)
|
||||
assert func_repr(param) == '$param'
|
||||
|
||||
top_lvl_sqr := high_fn_return_named_fn()
|
||||
assert top_lvl_sqr(param) == param * param
|
||||
}
|
||||
|
||||
fn high_fn_applier(arg int, func fn(a int)string) string {
|
||||
return func(arg)
|
||||
}
|
||||
fn test_high_fn_applier() {
|
||||
arg := 13
|
||||
expect := '$arg $arg'
|
||||
func := fn (arg int) string {
|
||||
return '$arg $arg'
|
||||
}
|
||||
assert expect == high_fn_applier(arg, func)
|
||||
}
|
||||
|
||||
fn sqr(x int) int {
|
||||
return x * x
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue