mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
cgen: optional multiple return values
This commit is contained in:
parent
12221fb999
commit
d0afa748ff
@ -130,6 +130,7 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
||||
}
|
||||
g.init()
|
||||
//
|
||||
mut tests_inited := false
|
||||
mut autofree_used := false
|
||||
for file in files {
|
||||
g.file = file
|
||||
@ -147,6 +148,12 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
||||
g.autofree = 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)
|
||||
}
|
||||
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
|
||||
g.write_init_function()
|
||||
}
|
||||
if g.is_test {
|
||||
g.write_tests_main()
|
||||
}
|
||||
//
|
||||
g.finish()
|
||||
//
|
||||
@ -856,7 +860,15 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||
g.expr(assign_stmt.right[0])
|
||||
g.is_assign_rhs = false
|
||||
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(';')
|
||||
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) {
|
||||
g.write('return')
|
||||
g.write('return ')
|
||||
if g.fn_decl.name == 'main' {
|
||||
g.writeln(' 0;')
|
||||
g.writeln('0;')
|
||||
return
|
||||
}
|
||||
fn_return_is_optional := g.fn_decl.return_type.flag_is(.optional)
|
||||
// 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(' ')
|
||||
fn_return_is_optional := g.fn_decl.return_type.flag_is(.optional)
|
||||
// handle none/error for optional
|
||||
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)
|
||||
// mr_info := typ_sym.info as table.MultiReturn
|
||||
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)
|
||||
g.write('opt_ok(&($styp/*X*/[]) { ')
|
||||
} else {
|
||||
@ -2007,37 +2032,24 @@ fn (mut g Gen) return_statement(node ast.Return) {
|
||||
}
|
||||
} else if node.exprs.len >= 1 {
|
||||
// normal return
|
||||
g.write(' ')
|
||||
return_sym := g.table.get_type_symbol(node.types[0])
|
||||
// `return opt_ok(expr)` for functions that expect an optional
|
||||
if fn_return_is_optional && !node.types[0].flag_is(.optional) && return_sym.name !=
|
||||
'Option' {
|
||||
mut is_none := false
|
||||
mut is_error := false
|
||||
expr0 := node.exprs[0]
|
||||
match expr0 {
|
||||
ast.None {
|
||||
is_none = true
|
||||
}
|
||||
ast.CallExpr {
|
||||
if it.name == 'error' {
|
||||
is_error = true // TODO check name 'error'
|
||||
}
|
||||
}
|
||||
else {}
|
||||
styp := g.base_type(g.fn_decl.return_type)
|
||||
g.write('/*:)$return_sym.name*/opt_ok(&($styp[]) { ')
|
||||
if !g.fn_decl.return_type.is_ptr() && node.types[0].is_ptr() {
|
||||
// Automatic Dereference for optional
|
||||
g.write('*')
|
||||
}
|
||||
if !is_none && !is_error {
|
||||
styp := g.base_type(g.fn_decl.return_type)
|
||||
g.write('/*:)$return_sym.name*/opt_ok(&($styp[]) { ')
|
||||
if !g.fn_decl.return_type.is_ptr() && node.types[0].is_ptr() {
|
||||
// Automatic Dereference for optional
|
||||
g.write('*')
|
||||
for i, expr in node.exprs {
|
||||
g.expr(expr)
|
||||
if i < node.exprs.len - 1 {
|
||||
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() {
|
||||
// Automatic Dereference
|
||||
|
@ -133,15 +133,3 @@ fn test_assigning_fns() {
|
||||
//
|
||||
// End assigning functions (IdentFn)
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -17,3 +17,58 @@ fn fn_mr_get_user() (string, int, []string, UserData) {
|
||||
data := UserData{test: 'Test 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
Block a user