cgen: optional multiple return values
parent
12221fb999
commit
d0afa748ff
|
@ -130,6 +130,7 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
||||||
}
|
}
|
||||||
g.init()
|
g.init()
|
||||||
//
|
//
|
||||||
|
mut tests_inited := false
|
||||||
mut autofree_used := false
|
mut autofree_used := false
|
||||||
for file in files {
|
for file in files {
|
||||||
g.file = file
|
g.file = file
|
||||||
|
@ -147,6 +148,12 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
||||||
g.autofree = true
|
g.autofree = true
|
||||||
autofree_used = true
|
autofree_used = true
|
||||||
}
|
}
|
||||||
|
// anon fn may include assert and thus this needs
|
||||||
|
// to be included before any test contents are written
|
||||||
|
if g.is_test && !tests_inited {
|
||||||
|
g.write_tests_main()
|
||||||
|
tests_inited = true
|
||||||
|
}
|
||||||
g.stmts(file.stmts)
|
g.stmts(file.stmts)
|
||||||
}
|
}
|
||||||
if autofree_used {
|
if autofree_used {
|
||||||
|
@ -158,9 +165,6 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
||||||
// no init in builtin.o
|
// no init in builtin.o
|
||||||
g.write_init_function()
|
g.write_init_function()
|
||||||
}
|
}
|
||||||
if g.is_test {
|
|
||||||
g.write_tests_main()
|
|
||||||
}
|
|
||||||
//
|
//
|
||||||
g.finish()
|
g.finish()
|
||||||
//
|
//
|
||||||
|
@ -856,7 +860,15 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
g.expr(assign_stmt.right[0])
|
g.expr(assign_stmt.right[0])
|
||||||
g.is_assign_rhs = false
|
g.is_assign_rhs = false
|
||||||
if is_optional {
|
if is_optional {
|
||||||
g.or_block(mr_var_name, or_stmts, return_type)
|
val := assign_stmt.right[0]
|
||||||
|
match val {
|
||||||
|
ast.CallExpr {
|
||||||
|
or_stmts = it.or_block.stmts
|
||||||
|
return_type = it.return_type
|
||||||
|
g.or_block(mr_var_name, or_stmts, return_type)
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
for i, ident in assign_stmt.left {
|
for i, ident in assign_stmt.left {
|
||||||
|
@ -1972,22 +1984,35 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) return_statement(node ast.Return) {
|
fn (mut g 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;')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fn_return_is_optional := g.fn_decl.return_type.flag_is(.optional)
|
|
||||||
// got to do a correct check for multireturn
|
// got to do a correct check for multireturn
|
||||||
sym := g.table.get_type_symbol(g.fn_decl.return_type)
|
sym := g.table.get_type_symbol(g.fn_decl.return_type)
|
||||||
fn_return_is_multi := sym.kind == .multi_return
|
fn_return_is_multi := sym.kind == .multi_return
|
||||||
// optional multi not supported
|
fn_return_is_optional := g.fn_decl.return_type.flag_is(.optional)
|
||||||
if fn_return_is_multi && !fn_return_is_optional {
|
// handle none/error for optional
|
||||||
g.write(' ')
|
if fn_return_is_optional {
|
||||||
|
optional_none := node.exprs[0] is ast.None
|
||||||
|
mut optional_error := false
|
||||||
|
match node.exprs[0] {
|
||||||
|
ast.CallExpr { optional_error = it.name == 'error' }
|
||||||
|
else { false }
|
||||||
|
}
|
||||||
|
if optional_none || optional_error {
|
||||||
|
g.expr_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type)
|
||||||
|
g.write(';')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// regular cases
|
||||||
|
if fn_return_is_multi { // not_optional_none { //&& !fn_return_is_optional {
|
||||||
// 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
|
||||||
mut styp := ''
|
mut styp := ''
|
||||||
if fn_return_is_optional { // && !node.types[0].flag_is(.optional) && node.types[0] !=
|
if fn_return_is_optional {
|
||||||
styp = g.base_type(g.fn_decl.return_type)
|
styp = g.base_type(g.fn_decl.return_type)
|
||||||
g.write('opt_ok(&($styp/*X*/[]) { ')
|
g.write('opt_ok(&($styp/*X*/[]) { ')
|
||||||
} else {
|
} else {
|
||||||
|
@ -2007,37 +2032,24 @@ fn (mut g Gen) return_statement(node ast.Return) {
|
||||||
}
|
}
|
||||||
} else if node.exprs.len >= 1 {
|
} else if node.exprs.len >= 1 {
|
||||||
// normal return
|
// normal return
|
||||||
g.write(' ')
|
|
||||||
return_sym := g.table.get_type_symbol(node.types[0])
|
return_sym := g.table.get_type_symbol(node.types[0])
|
||||||
// `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 && !node.types[0].flag_is(.optional) && return_sym.name !=
|
if fn_return_is_optional && !node.types[0].flag_is(.optional) && return_sym.name !=
|
||||||
'Option' {
|
'Option' {
|
||||||
mut is_none := false
|
styp := g.base_type(g.fn_decl.return_type)
|
||||||
mut is_error := false
|
g.write('/*:)$return_sym.name*/opt_ok(&($styp[]) { ')
|
||||||
expr0 := node.exprs[0]
|
if !g.fn_decl.return_type.is_ptr() && node.types[0].is_ptr() {
|
||||||
match expr0 {
|
// Automatic Dereference for optional
|
||||||
ast.None {
|
g.write('*')
|
||||||
is_none = true
|
|
||||||
}
|
|
||||||
ast.CallExpr {
|
|
||||||
if it.name == 'error' {
|
|
||||||
is_error = true // TODO check name 'error'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {}
|
|
||||||
}
|
}
|
||||||
if !is_none && !is_error {
|
for i, expr in node.exprs {
|
||||||
styp := g.base_type(g.fn_decl.return_type)
|
g.expr(expr)
|
||||||
g.write('/*:)$return_sym.name*/opt_ok(&($styp[]) { ')
|
if i < node.exprs.len - 1 {
|
||||||
if !g.fn_decl.return_type.is_ptr() && node.types[0].is_ptr() {
|
g.write(', ')
|
||||||
// Automatic Dereference for optional
|
|
||||||
g.write('*')
|
|
||||||
}
|
}
|
||||||
g.expr(node.exprs[0])
|
|
||||||
g.writeln(' }, sizeof($styp));')
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
// g.write('/*OPTIONAL*/')
|
g.writeln(' }, sizeof($styp));')
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if !g.fn_decl.return_type.is_ptr() && node.types[0].is_ptr() {
|
if !g.fn_decl.return_type.is_ptr() && node.types[0].is_ptr() {
|
||||||
// Automatic Dereference
|
// Automatic Dereference
|
||||||
|
|
|
@ -133,15 +133,3 @@ fn test_assigning_fns() {
|
||||||
//
|
//
|
||||||
// End assigning functions (IdentFn)
|
// End assigning functions (IdentFn)
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,3 +17,58 @@ fn fn_mr_get_user() (string, int, []string, UserData) {
|
||||||
data := UserData{test: 'Test Data'}
|
data := UserData{test: 'Test Data'}
|
||||||
return 'joe', 34, groups, data
|
return 'joe', 34, groups, data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn split_to_two(s string) ?(string, string) {
|
||||||
|
mut tokens := s.split_nth(' ', 2)
|
||||||
|
if s.len == 0 {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
if tokens.len != 2 {
|
||||||
|
return error('error')
|
||||||
|
}
|
||||||
|
return tokens[0], tokens[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn returnable_fail() string {
|
||||||
|
_,_ := split_to_two('bad') or {
|
||||||
|
return 'ok'
|
||||||
|
}
|
||||||
|
return 'nok'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_multiple_ret() {
|
||||||
|
// returnable test
|
||||||
|
assert returnable_fail() == 'ok'
|
||||||
|
|
||||||
|
// good case
|
||||||
|
res1_1, res1_2 := split_to_two("fish house") or {
|
||||||
|
assert false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert res1_1 == 'fish'
|
||||||
|
assert res1_2 == 'house'
|
||||||
|
|
||||||
|
// none case
|
||||||
|
wrapper1 := fn()(string, string){
|
||||||
|
res2_1, res2_2 := split_to_two("") or {
|
||||||
|
assert err == ''
|
||||||
|
return 'replaced', 'val'
|
||||||
|
}
|
||||||
|
return res2_1, res2_2
|
||||||
|
}
|
||||||
|
res2_1, res2_2 := wrapper1()
|
||||||
|
assert res2_1 == 'replaced'
|
||||||
|
assert res2_2 == 'val'
|
||||||
|
|
||||||
|
// error case
|
||||||
|
wrapper2 := fn()(string, string){
|
||||||
|
res3_1, res3_2 := split_to_two('fishhouse') or {
|
||||||
|
assert err == 'error'
|
||||||
|
return 'replaced', 'val'
|
||||||
|
}
|
||||||
|
return res3_1, res3_2
|
||||||
|
}
|
||||||
|
res3_1, res3_2 := wrapper2()
|
||||||
|
assert res3_1 == 'replaced'
|
||||||
|
assert res3_2 == 'val'
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue