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