compiler: functions with multiple returns
parent
a0c5113611
commit
60d932e57d
|
@ -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 {
|
||||
|
|
|
@ -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}
|
||||
|
@ -1162,8 +1181,9 @@ fn (p mut Parser) statement(add_semi bool) string {
|
|||
p.check(.colon)
|
||||
return ''
|
||||
}
|
||||
// `a := 777`
|
||||
else if p.peek() == .decl_assign {
|
||||
// `a := 777`
|
||||
else if p.peek() == .decl_assign || p.peek() == .comma {
|
||||
p.log('var decl')
|
||||
p.var_decl()
|
||||
}
|
||||
else {
|
||||
|
@ -1324,29 +1344,55 @@ fn (p mut Parser) var_decl() {
|
|||
p.check(.key_static)
|
||||
p.fspace()
|
||||
}
|
||||
// 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
|
||||
// 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)
|
||||
p.error('redefinition of `$name`')
|
||||
}
|
||||
if name.len > 1 && contains_capital(name) {
|
||||
p.error('variable names cannot contain uppercase letters, use snake_case instead')
|
||||
|
||||
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) // :=
|
||||
typ := p.gen_var_decl(name, is_static)
|
||||
p.register_var(Var {
|
||||
name: name
|
||||
typ: typ
|
||||
is_mut: is_mut
|
||||
is_alloc: p.is_alloc || typ.starts_with('array_')
|
||||
scanner_pos: var_scanner_pos
|
||||
line_nr: var_scanner_pos.line_nr
|
||||
})
|
||||
// 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
|
||||
// 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)
|
||||
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.register_var(Var {
|
||||
name: name
|
||||
typ: typ
|
||||
is_mut: is_mut
|
||||
is_alloc: p.is_alloc || typ.starts_with('array_')
|
||||
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
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit c2c26419198a271ca00cb8d77119d17c5622569e
|
Loading…
Reference in New Issue