compiler: functions with multiple returns

pull/1949/head^2
joe-conigliaro 2019-09-23 12:45:19 +10:00 committed by Alexander Medvednikov
parent a0c5113611
commit 60d932e57d
3 changed files with 106 additions and 25 deletions

View File

@ -279,12 +279,26 @@ fn (p mut Parser) fn_decl() {
// Returns a type?
mut typ := 'void'
if p.tok == .name || p.tok == .mul || p.tok == .amp || p.tok == .lsbr ||
p.tok == .question {
p.tok == .question || p.tok == .lpar {
p.fgen(' ')
// TODO In
// if p.tok in [ .name, .mul, .amp, .lsbr ] {
typ = p.get_type()
}
// multiple returns
if typ.starts_with('MultiReturn_') {
if !p.first_pass() && !p.table.known_type(typ) {
p.table.register_type2(Type{
cat: TypeCategory.struct_,
name: typ,
mod: p.mod
})
for i, t in typ.replace('MultiReturn_', '').replace('0ptr0', '*').split('_') {
p.table.add_field(typ, 'var_$i', t, false, '', .public)
}
p.cgen.typedefs << 'typedef struct $typ $typ;'
}
}
// Translated C code can have empty functions (just definitions)
is_fn_header := !is_c && !is_sig && (p.pref.translated || p.pref.is_test) && p.tok != .lcbr
if is_fn_header {

View File

@ -833,6 +833,25 @@ fn (p mut Parser) get_type() string {
mut mul := false
mut nr_muls := 0
mut typ := ''
// multiple returns
if p.tok == .lpar {
// if p.inside_tuple {
// p.error('unexpected (')
// }
// p.inside_tuple = true
p.check(.lpar)
mut types := []string
for {
types << p.get_type()
if p.tok != .comma {
break
}
p.check(.comma)
}
p.check(.rpar)
// p.inside_tuple = false
return 'MultiReturn_' + types.join('_').replace('*', '0ptr0')
}
// fn type
if p.tok == .func {
mut f := Fn{name: '_', mod: p.mod}
@ -1163,7 +1182,8 @@ fn (p mut Parser) statement(add_semi bool) string {
return ''
}
// `a := 777`
else if p.peek() == .decl_assign {
else if p.peek() == .decl_assign || p.peek() == .comma {
p.log('var decl')
p.var_decl()
}
else {
@ -1324,21 +1344,46 @@ fn (p mut Parser) var_decl() {
p.check(.key_static)
p.fspace()
}
mut names := []string
names << p.check_name()
for p.tok == .comma {
p.check(.comma)
names << p.check_name()
}
mr_var_name := if names.len > 1 { '__ret_'+names.join('_') } else { names[0] }
p.check_space(.decl_assign) // :=
// t := p.bool_expression()
p.var_decl_name = mr_var_name
t := p.gen_var_decl(mr_var_name, is_static)
mut types := [t]
// multiple returns
if names.len > 1 {
// should we register __ret var?
types = t.replace('MultiReturn_', '').replace('0ptr0', '*').split('_')
}
for i, name in names {
typ := types[i]
if names.len > 1 {
p.gen(';\n')
p.gen('$typ $name = ${mr_var_name}.var_$i')
}
// println('var decl tok=${p.strtok()} ismut=$is_mut')
var_scanner_pos := p.scanner.get_scanner_pos()
name := p.check_name()
p.var_decl_name = name
// name := p.check_name()
// p.var_decl_name = name
// Don't allow declaring a variable with the same name. Even in a child scope
// (shadowing is not allowed)
if !p.builtin_mod && p.cur_fn.known_var(name) {
v := p.cur_fn.find_var(name)
// v := p.cur_fn.find_var(name)
p.error('redefinition of `$name`')
}
if name.len > 1 && contains_capital(name) {
p.error('variable names cannot contain uppercase letters, use snake_case instead')
}
p.check_space(.decl_assign) // :=
typ := p.gen_var_decl(name, is_static)
// p.check_space(.decl_assign) // :=
// typ := p.gen_var_decl(name, is_static)
p.register_var(Var {
name: name
typ: typ
@ -1347,6 +1392,7 @@ fn (p mut Parser) var_decl() {
scanner_pos: var_scanner_pos
line_nr: var_scanner_pos.line_nr
})
}
//if p.is_alloc { println('REG VAR IS ALLOC $name') }
p.var_decl_name = ''
p.is_empty_c_struct_init = false
@ -3532,7 +3578,27 @@ fn (p mut Parser) return_st() {
p.inside_return_expr = true
is_none := p.tok == .key_none
p.expected_type = p.cur_fn.typ
expr_type := p.bool_expression()
// expr_type := p.bool_expression()
mut expr_type := p.bool_expression()
mut types := []string
types << expr_type
for p.tok == .comma {
p.check(.comma)
types << p.bool_expression()
}
// multiple returns
if types.len > 1 {
expr_type = 'MultiReturn_' + types.join('_').replace('*', '0ptr0')
ret_vals := p.cgen.cur_line.right(ph)
mut ret_fields := ''
for ret_val_idx, ret_val in ret_vals.split(' ') {
if ret_val_idx > 0 {
ret_fields += ','
}
ret_fields += '.var_$ret_val_idx=$ret_val'
}
p.cgen.resetln('($expr_type){$ret_fields}')
}
p.inside_return_expr = false
// Automatically wrap an object inside an option if the function
// returns an option

1
vc 160000

@ -0,0 +1 @@
Subproject commit c2c26419198a271ca00cb8d77119d17c5622569e