compiler: clean up multiple returns and verify number of returned values

pull/2096/head
joe-conigliaro 2019-09-24 20:14:04 +10:00 committed by Alexander Medvednikov
parent a44a03f9a5
commit 3317d7fd7c
2 changed files with 22 additions and 17 deletions

View File

@ -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

View File

@ -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 {