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
|
return table.string_type
|
||||||
}
|
}
|
||||||
ast.AnonFn {
|
ast.AnonFn {
|
||||||
|
keep_ret_type := c.fn_return_type
|
||||||
c.fn_return_type = it.decl.return_type
|
c.fn_return_type = it.decl.return_type
|
||||||
c.stmts(it.decl.stmts)
|
c.stmts(it.decl.stmts)
|
||||||
|
c.fn_return_type = keep_ret_type
|
||||||
return it.typ
|
return it.typ
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -358,7 +358,10 @@ typedef struct {
|
||||||
.function {
|
.function {
|
||||||
info := typ.info as table.FnType
|
info := typ.info as table.FnType
|
||||||
func := info.func
|
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 {
|
fn_name := if func.is_c {
|
||||||
func.name.replace('.', '__')
|
func.name.replace('.', '__')
|
||||||
} else if info.is_anon {
|
} 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`')
|
println('build module `$g.module_built` fn `$it.name`')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
keep_fn_decl := g.fn_decl
|
||||||
g.fn_decl = it // &it
|
g.fn_decl = it // &it
|
||||||
if it.name == 'main' {
|
if it.name == 'main' {
|
||||||
// just remember `it`; main code will be generated in finish()
|
// just remember `it`; main code will be generated in finish()
|
||||||
|
@ -563,7 +567,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||||
} else {
|
} else {
|
||||||
g.gen_fn_decl(it)
|
g.gen_fn_decl(it)
|
||||||
}
|
}
|
||||||
g.fn_decl = 0
|
g.fn_decl = keep_fn_decl
|
||||||
if skip {
|
if skip {
|
||||||
g.out.go_back_to(pos)
|
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 {
|
if assign_stmt.is_static {
|
||||||
g.write('static ')
|
g.write('static ')
|
||||||
}
|
}
|
||||||
if assign_stmt.left.len > assign_stmt.right.len {
|
mut return_type := table.void_type
|
||||||
|
if assign_stmt.right[0] is ast.CallExpr {
|
||||||
|
it := assign_stmt.right[0] as ast.CallExpr
|
||||||
|
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
|
// multi return
|
||||||
mut or_stmts := []ast.Stmt{}
|
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
|
|
||||||
}
|
|
||||||
is_optional := return_type.flag_is(.optional)
|
is_optional := return_type.flag_is(.optional)
|
||||||
mr_var_name := 'mr_$assign_stmt.pos.pos'
|
mr_var_name := 'mr_$assign_stmt.pos.pos'
|
||||||
mr_styp := g.typ(return_type)
|
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)
|
styp := g.typ(ident_var_info.typ)
|
||||||
mut is_call := false
|
mut is_call := false
|
||||||
mut or_stmts := []ast.Stmt{}
|
mut or_stmts := []ast.Stmt{}
|
||||||
mut return_type := table.void_type
|
blank_assign := ident.kind == .blank_ident
|
||||||
match val {
|
match val {
|
||||||
ast.CallExpr {
|
ast.CallExpr {
|
||||||
is_call = true
|
is_call = true
|
||||||
|
@ -874,6 +885,9 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
}
|
}
|
||||||
ast.AnonFn {
|
ast.AnonFn {
|
||||||
// TODO: no buffer fiddling
|
// TODO: no buffer fiddling
|
||||||
|
if blank_assign {
|
||||||
|
g.write('{')
|
||||||
|
}
|
||||||
ret_styp := g.typ(it.decl.return_type)
|
ret_styp := g.typ(it.decl.return_type)
|
||||||
g.write('$ret_styp (*$ident.name) (')
|
g.write('$ret_styp (*$ident.name) (')
|
||||||
def_pos := g.definitions.len
|
def_pos := g.definitions.len
|
||||||
|
@ -882,13 +896,16 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
g.write(') = ')
|
g.write(') = ')
|
||||||
g.expr(*it)
|
g.expr(*it)
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
|
if blank_assign {
|
||||||
|
g.write('}')
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
gen_or := is_call && return_type.flag_is(.optional)
|
gen_or := is_call && return_type.flag_is(.optional)
|
||||||
g.is_assign_rhs = true
|
g.is_assign_rhs = true
|
||||||
if ident.kind == .blank_ident {
|
if blank_assign {
|
||||||
if is_call {
|
if is_call {
|
||||||
g.expr(val)
|
g.expr(val)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1909,8 +1926,13 @@ fn (mut g Gen) return_statement(node ast.Return) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fn_return_is_optional := g.fn_decl.return_type.flag_is(.optional)
|
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(' ')
|
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
|
||||||
|
@ -1933,7 +1955,7 @@ fn (mut g Gen) return_statement(node ast.Return) {
|
||||||
if fn_return_is_optional {
|
if fn_return_is_optional {
|
||||||
g.write(' }, sizeof($styp))')
|
g.write(' }, sizeof($styp))')
|
||||||
}
|
}
|
||||||
} else if node.exprs.len == 1 {
|
} else if node.exprs.len >= 1 {
|
||||||
// normal return
|
// normal return
|
||||||
g.write(' ')
|
g.write(' ')
|
||||||
return_sym := g.table.get_type_symbol(node.types[0])
|
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 {
|
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 }
|
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{
|
return t.register_type_symbol(TypeSymbol{
|
||||||
kind: .function
|
kind: .function
|
||||||
name: name
|
name: name
|
||||||
info: FnType{
|
info: FnType{
|
||||||
is_anon: f.name.len == 0 || is_anon
|
is_anon: anon
|
||||||
has_decl: has_decl
|
has_decl: has_decl
|
||||||
func: f
|
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 {
|
fn sqr(x int) int {
|
||||||
return x * x
|
return x * x
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue