compiler: functions with multiple returns
parent
a0c5113611
commit
60d932e57d
|
@ -279,12 +279,26 @@ fn (p mut Parser) fn_decl() {
|
||||||
// Returns a type?
|
// Returns a type?
|
||||||
mut typ := 'void'
|
mut typ := 'void'
|
||||||
if p.tok == .name || p.tok == .mul || p.tok == .amp || p.tok == .lsbr ||
|
if p.tok == .name || p.tok == .mul || p.tok == .amp || p.tok == .lsbr ||
|
||||||
p.tok == .question {
|
p.tok == .question || p.tok == .lpar {
|
||||||
p.fgen(' ')
|
p.fgen(' ')
|
||||||
// TODO In
|
// TODO In
|
||||||
// if p.tok in [ .name, .mul, .amp, .lsbr ] {
|
// if p.tok in [ .name, .mul, .amp, .lsbr ] {
|
||||||
typ = p.get_type()
|
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)
|
// 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
|
is_fn_header := !is_c && !is_sig && (p.pref.translated || p.pref.is_test) && p.tok != .lcbr
|
||||||
if is_fn_header {
|
if is_fn_header {
|
||||||
|
|
|
@ -833,6 +833,25 @@ fn (p mut Parser) get_type() string {
|
||||||
mut mul := false
|
mut mul := false
|
||||||
mut nr_muls := 0
|
mut nr_muls := 0
|
||||||
mut typ := ''
|
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
|
// fn type
|
||||||
if p.tok == .func {
|
if p.tok == .func {
|
||||||
mut f := Fn{name: '_', mod: p.mod}
|
mut f := Fn{name: '_', mod: p.mod}
|
||||||
|
@ -1163,7 +1182,8 @@ fn (p mut Parser) statement(add_semi bool) string {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
// `a := 777`
|
// `a := 777`
|
||||||
else if p.peek() == .decl_assign {
|
else if p.peek() == .decl_assign || p.peek() == .comma {
|
||||||
|
p.log('var decl')
|
||||||
p.var_decl()
|
p.var_decl()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1324,21 +1344,46 @@ fn (p mut Parser) var_decl() {
|
||||||
p.check(.key_static)
|
p.check(.key_static)
|
||||||
p.fspace()
|
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')
|
// println('var decl tok=${p.strtok()} ismut=$is_mut')
|
||||||
var_scanner_pos := p.scanner.get_scanner_pos()
|
var_scanner_pos := p.scanner.get_scanner_pos()
|
||||||
name := p.check_name()
|
// name := p.check_name()
|
||||||
p.var_decl_name = name
|
// p.var_decl_name = name
|
||||||
// Don't allow declaring a variable with the same name. Even in a child scope
|
// Don't allow declaring a variable with the same name. Even in a child scope
|
||||||
// (shadowing is not allowed)
|
// (shadowing is not allowed)
|
||||||
if !p.builtin_mod && p.cur_fn.known_var(name) {
|
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`')
|
p.error('redefinition of `$name`')
|
||||||
}
|
}
|
||||||
if name.len > 1 && contains_capital(name) {
|
if name.len > 1 && contains_capital(name) {
|
||||||
p.error('variable names cannot contain uppercase letters, use snake_case instead')
|
p.error('variable names cannot contain uppercase letters, use snake_case instead')
|
||||||
}
|
}
|
||||||
p.check_space(.decl_assign) // :=
|
// p.check_space(.decl_assign) // :=
|
||||||
typ := p.gen_var_decl(name, is_static)
|
// typ := p.gen_var_decl(name, is_static)
|
||||||
p.register_var(Var {
|
p.register_var(Var {
|
||||||
name: name
|
name: name
|
||||||
typ: typ
|
typ: typ
|
||||||
|
@ -1347,6 +1392,7 @@ fn (p mut Parser) var_decl() {
|
||||||
scanner_pos: var_scanner_pos
|
scanner_pos: var_scanner_pos
|
||||||
line_nr: var_scanner_pos.line_nr
|
line_nr: var_scanner_pos.line_nr
|
||||||
})
|
})
|
||||||
|
}
|
||||||
//if p.is_alloc { println('REG VAR IS ALLOC $name') }
|
//if p.is_alloc { println('REG VAR IS ALLOC $name') }
|
||||||
p.var_decl_name = ''
|
p.var_decl_name = ''
|
||||||
p.is_empty_c_struct_init = false
|
p.is_empty_c_struct_init = false
|
||||||
|
@ -3532,7 +3578,27 @@ fn (p mut Parser) return_st() {
|
||||||
p.inside_return_expr = true
|
p.inside_return_expr = true
|
||||||
is_none := p.tok == .key_none
|
is_none := p.tok == .key_none
|
||||||
p.expected_type = p.cur_fn.typ
|
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
|
p.inside_return_expr = false
|
||||||
// Automatically wrap an object inside an option if the function
|
// Automatically wrap an object inside an option if the function
|
||||||
// returns an option
|
// returns an option
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit c2c26419198a271ca00cb8d77119d17c5622569e
|
Loading…
Reference in New Issue