parser: fix forwarding vargs & multiple call varg len fix

pull/2619/head
joe-conigliaro 2019-11-02 03:14:16 +11:00 committed by Alexander Medvednikov
parent de8297c983
commit fe9d884d90
2 changed files with 40 additions and 10 deletions

View File

@ -813,8 +813,8 @@ fn (p mut Parser) fn_args(f mut Fn) {
f.is_variadic = true
t := p.get_type()
// register varg struct, incase function is never called
if p.first_pass() && !f.is_generic {
p.fn_register_vargs_stuct(f, t, []string)
if p.first_pass() && !f.is_generic && !f.is_c{
p.register_vargs_stuct(t, 0)
}
typ = '...$t'
} else {
@ -1205,21 +1205,25 @@ fn (p mut Parser) replace_type_params(f &Fn, ti TypeInst) []string {
return r
}
fn (p mut Parser) fn_register_vargs_stuct(f &Fn, typ string, values []string) string {
vargs_struct := '_V_FnVargs_$f.name'
fn (p mut Parser) register_vargs_stuct(typ string, len int) string {
vargs_struct := '_V_FnVargs_$typ'
varg_type := Type{
cat: TypeCategory.struct_,
name: vargs_struct,
mod: p.mod
}
mut varg_len := len
if !p.table.known_type(vargs_struct) {
p.table.register_type2(varg_type)
p.cgen.typedefs << 'typedef struct $vargs_struct $vargs_struct;\n'
} else {
ex_typ := p.table.find_type(vargs_struct)
ex_len := ex_typ.fields[1].name[5..ex_typ.fields[1].name.len-1].int()
if ex_len > varg_len { varg_len = ex_len }
p.table.rewrite_type(varg_type)
}
p.table.add_field(vargs_struct, 'len', 'int', false, '', .public)
p.table.add_field(vargs_struct, 'args[$values.len]', typ, false, '', .public)
p.table.add_field(vargs_struct, 'args[$varg_len]', typ, false, '', .public)
return vargs_struct
}
@ -1238,6 +1242,10 @@ fn (p mut Parser) fn_call_vargs(f Fn) (string, []string) {
p.cgen.start_tmp()
mut varg_type := p.bool_expression()
varg_value := p.cgen.end_tmp()
if varg_type.starts_with('...') &&
(values.len > 0 || p.tok == .comma) {
p.error('You cannot pass additional vargs when forwarding vargs to another function/method')
}
if !f.is_generic {
p.check_types(last_arg.typ, varg_type)
} else {
@ -1246,7 +1254,6 @@ fn (p mut Parser) fn_call_vargs(f Fn) (string, []string) {
p.check_types(varg_type, t)
}
}
varg_def_type = varg_type
}
ref_deref := if last_arg.typ.ends_with('*') && !varg_type.ends_with('*') { '&' }
else if !last_arg.typ.ends_with('*') && varg_type.ends_with('*') { '*' }
@ -1263,13 +1270,18 @@ fn (p mut Parser) fn_call_vargs(f Fn) (string, []string) {
if !f.is_method && f.args.len > 1 {
p.cgen.gen(',')
}
return varg_def_type, values
return types[0], values
}
fn (p mut Parser) fn_gen_caller_vargs(f &Fn, varg_type string, values []string) {
vargs_struct := p.fn_register_vargs_stuct(f, varg_type, values)
is_varg := varg_type.starts_with('...')
if is_varg { // forwarding varg
p.cgen.gen('${values[0]}')
} else {
vargs_struct := p.register_vargs_stuct(varg_type, values.len)
p.cgen.gen('&($vargs_struct){.len=$values.len,.args={'+values.join(',')+'}}')
}
}
fn (p mut Parser) register_multi_return_stuct(types []string) string {
typ := '_V_MulRet_' + types.join('_V_').replace('*', '_PTR_')
@ -1450,7 +1462,7 @@ fn (f &Fn) str_args(table &Table) string {
}
}
else if arg.typ.starts_with('...') {
s += '_V_FnVargs_$f.name *$arg.name'
s += '_V_FnVargs_${arg.typ[3..]} *$arg.name'
}
else {
// s += '$arg.typ $arg.name'

View File

@ -2,6 +2,7 @@ struct VaTestGroup {
name string
}
// basic
fn variadic_test(name string, groups ...VaTestGroup) {
assert groups.len == 2
assert groups[0].name == 'users'
@ -14,6 +15,7 @@ fn test_fn_variadic() {
variadic_test('joe', group1, group2)
}
// generic
fn variadic_test_generic<T>(a int, b ...T) T {
b1 := b[0]
b2 := b[1]
@ -23,3 +25,19 @@ fn variadic_test_generic<T>(a int, b ...T) T {
fn test_fn_variadic_generic() {
assert variadic_test_generic(111, 'hello', 'v') == '111 hello v'
}
// forwarding
fn variadic_forward_a(a ...string) string {
return variadic_forward_b(a)
}
fn variadic_forward_b(a ...string) string {
a0 := a[0]
a1 := a[1]
a2 := a[2]
return '$a0$a1$a2'
}
fn test_fn_variadic_forward() {
assert variadic_forward_a('a', 'b', 'c') == 'abc'
}