compiler: clean up multiple returns and verify number of returned values
parent
a44a03f9a5
commit
3317d7fd7c
|
@ -275,18 +275,16 @@ fn (p mut Parser) fn_decl() {
|
|||
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('_ZptrZ_', '*').split('_Z_') {
|
||||
p.table.add_field(typ, 'var_$i', t, false, '', .public)
|
||||
}
|
||||
p.cgen.typedefs << 'typedef struct $typ $typ;'
|
||||
if typ.starts_with('_V_MulRet_') && 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('_V_MulRet_', '').replace('_PTR_', '*').split('_V_') {
|
||||
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
|
||||
|
|
|
@ -276,6 +276,8 @@ fn (p mut Parser) parse(pass Pass) {
|
|||
p.cgen.consts << g
|
||||
case Token.eof:
|
||||
//p.log('end of parse()')
|
||||
// TODO: check why this was added? everything seems to work
|
||||
// without it, and it's already happening in fn_decl
|
||||
// if p.is_script && !p.pref.is_test {
|
||||
// p.set_current_fn( MainFn )
|
||||
// p.check_unused_variables()
|
||||
|
@ -863,7 +865,7 @@ fn (p mut Parser) get_type() string {
|
|||
}
|
||||
p.check(.rpar)
|
||||
// p.inside_tuple = false
|
||||
return 'MultiReturn_' + types.join('_Z_').replace('*', '_ZptrZ_')
|
||||
return '_V_MulRet_' + types.join('_V_').replace('*', '_PTR_')
|
||||
}
|
||||
// fn type
|
||||
if p.tok == .func {
|
||||
|
@ -1366,16 +1368,19 @@ fn (p mut Parser) var_decl() {
|
|||
// 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('_ZptrZ_', '*').split('_Z_')
|
||||
types = t.replace('_V_MulRet_', '').replace('_PTR_', '*').split('_V_')
|
||||
}
|
||||
for i, name in names {
|
||||
typ := types[i]
|
||||
if names.len > 1 {
|
||||
if names.len != types.len {
|
||||
mr_fn := p.cgen.cur_line.find_between('=', '(').trim_space()
|
||||
p.error('assignment mismatch: ${names.len} variables but `$mr_fn` returns $types.len values.')
|
||||
}
|
||||
p.gen(';\n')
|
||||
p.gen('$typ $name = ${mr_var_name}.var_$i')
|
||||
}
|
||||
|
@ -3563,9 +3568,11 @@ fn (p mut Parser) return_st() {
|
|||
p.check(.comma)
|
||||
types << p.bool_expression()
|
||||
}
|
||||
mut cur_fn_typ_chk := p.cur_fn.typ
|
||||
// multiple returns
|
||||
if types.len > 1 {
|
||||
expr_type = 'MultiReturn_' + types.join('_Z_').replace('*', '_ZptrZ_')
|
||||
expr_type = types.join(',')
|
||||
cur_fn_typ_chk = cur_fn_typ_chk.replace('_V_MulRet_', '').replace('_PTR_', '*').replace('_V_', ',')
|
||||
ret_vals := p.cgen.cur_line.right(ph)
|
||||
mut ret_fields := ''
|
||||
for ret_val_idx, ret_val in ret_vals.split(' ') {
|
||||
|
@ -3574,7 +3581,7 @@ fn (p mut Parser) return_st() {
|
|||
}
|
||||
ret_fields += '.var_$ret_val_idx=$ret_val'
|
||||
}
|
||||
p.cgen.resetln('($expr_type){$ret_fields}')
|
||||
p.cgen.resetln('($p.cur_fn.typ){$ret_fields}')
|
||||
}
|
||||
p.inside_return_expr = false
|
||||
// Automatically wrap an object inside an option if the function
|
||||
|
@ -3618,7 +3625,7 @@ fn (p mut Parser) return_st() {
|
|||
p.genln('return $tmp;')
|
||||
}
|
||||
}
|
||||
p.check_types(expr_type, p.cur_fn.typ)
|
||||
p.check_types(expr_type, cur_fn_typ_chk)
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
Loading…
Reference in New Issue