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() typ = p.get_type()
} }
// multiple returns // multiple returns
if typ.starts_with('MultiReturn_') { if typ.starts_with('_V_MulRet_') && p.first_pass() && !p.table.known_type(typ) {
if !p.first_pass() && !p.table.known_type(typ) { p.table.register_type2(Type{
p.table.register_type2(Type{ cat: TypeCategory.struct_,
cat: TypeCategory.struct_, name: typ,
name: typ, mod: p.mod
mod: p.mod })
}) for i, t in typ.replace('_V_MulRet_', '').replace('_PTR_', '*').split('_V_') {
for i, t in typ.replace('MultiReturn_', '').replace('_ZptrZ_', '*').split('_Z_') { p.table.add_field(typ, 'var_$i', t, false, '', .public)
p.table.add_field(typ, 'var_$i', t, false, '', .public)
}
p.cgen.typedefs << 'typedef struct $typ $typ;'
} }
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

View File

@ -276,6 +276,8 @@ fn (p mut Parser) parse(pass Pass) {
p.cgen.consts << g p.cgen.consts << g
case Token.eof: case Token.eof:
//p.log('end of parse()') //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 { // if p.is_script && !p.pref.is_test {
// p.set_current_fn( MainFn ) // p.set_current_fn( MainFn )
// p.check_unused_variables() // p.check_unused_variables()
@ -863,7 +865,7 @@ fn (p mut Parser) get_type() string {
} }
p.check(.rpar) p.check(.rpar)
// p.inside_tuple = false // p.inside_tuple = false
return 'MultiReturn_' + types.join('_Z_').replace('*', '_ZptrZ_') return '_V_MulRet_' + types.join('_V_').replace('*', '_PTR_')
} }
// fn type // fn type
if p.tok == .func { if p.tok == .func {
@ -1366,16 +1368,19 @@ fn (p mut Parser) var_decl() {
// t := p.bool_expression() // t := p.bool_expression()
p.var_decl_name = mr_var_name p.var_decl_name = mr_var_name
t := p.gen_var_decl(mr_var_name, is_static) t := p.gen_var_decl(mr_var_name, is_static)
mut types := [t] mut types := [t]
// multiple returns // multiple returns
if names.len > 1 { if names.len > 1 {
// should we register __ret var? // 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 { for i, name in names {
typ := types[i] typ := types[i]
if names.len > 1 { 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(';\n')
p.gen('$typ $name = ${mr_var_name}.var_$i') p.gen('$typ $name = ${mr_var_name}.var_$i')
} }
@ -3563,9 +3568,11 @@ fn (p mut Parser) return_st() {
p.check(.comma) p.check(.comma)
types << p.bool_expression() types << p.bool_expression()
} }
mut cur_fn_typ_chk := p.cur_fn.typ
// multiple returns // multiple returns
if types.len > 1 { 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) ret_vals := p.cgen.cur_line.right(ph)
mut ret_fields := '' mut ret_fields := ''
for ret_val_idx, ret_val in ret_vals.split(' ') { 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' 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 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
@ -3618,7 +3625,7 @@ fn (p mut Parser) return_st() {
p.genln('return $tmp;') p.genln('return $tmp;')
} }
} }
p.check_types(expr_type, p.cur_fn.typ) p.check_types(expr_type, cur_fn_typ_chk)
} }
} }
else { else {