compiler: add variadic support for generic functions
parent
374133086d
commit
0cf3e2e677
|
@ -27,20 +27,21 @@ mut:
|
|||
// idx int
|
||||
scope_level int
|
||||
typ string // return type
|
||||
is_c bool
|
||||
receiver_typ string
|
||||
is_c bool
|
||||
is_public bool
|
||||
is_method bool
|
||||
returns_error bool
|
||||
is_decl bool // type myfn fn(int, int)
|
||||
is_unsafe bool
|
||||
is_unsafe bool
|
||||
is_deprecated bool
|
||||
is_variadic bool
|
||||
is_generic bool
|
||||
returns_error bool
|
||||
defer_text []string
|
||||
is_generic bool
|
||||
type_pars []string
|
||||
type_inst []TypeInst
|
||||
dispatch_of TypeInst // current type inst of this generic instance
|
||||
body_idx int // idx of the first body statement
|
||||
type_pars []string
|
||||
type_inst []TypeInst
|
||||
dispatch_of TypeInst // current type inst of this generic instance
|
||||
body_idx int // idx of the first body statement
|
||||
fn_name_token_idx int // used by error reporting
|
||||
}
|
||||
|
||||
|
@ -782,11 +783,11 @@ fn (p mut Parser) fn_args(f mut Fn) {
|
|||
if p.tok == .rpar {
|
||||
p.error('you must provide a type for vargs: eg `...string`. multiple types `...` are not supported yet.')
|
||||
}
|
||||
f.is_variadic = true
|
||||
t := p.get_type()
|
||||
// register varg struct, incase function is never called
|
||||
if p.first_pass() {
|
||||
vargs_struct := p.fn_register_vargs_stuct(f, t, []string)
|
||||
p.cgen.typedefs << 'typedef struct $vargs_struct $vargs_struct;\n'
|
||||
if p.first_pass() && !f.is_generic {
|
||||
p.fn_register_vargs_stuct(f, t, []string)
|
||||
}
|
||||
typ = '...$t'
|
||||
} else {
|
||||
|
@ -839,11 +840,6 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
|
|||
// println('fn_call_args() name=$f.name args.len=$f.args.len')
|
||||
// C func. # of args is not known
|
||||
p.check(.lpar)
|
||||
mut is_variadic := false
|
||||
if f.args.len > 0 {
|
||||
last_arg := f.args.last()
|
||||
is_variadic = last_arg.typ.starts_with('...')
|
||||
}
|
||||
if f.is_c {
|
||||
for p.tok != .rpar {
|
||||
//C.func(var1, var2.method())
|
||||
|
@ -926,7 +922,6 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
|
|||
p.gen('/*YY f=$f.name arg=$arg.name is_moved=$arg.is_moved*/string_clone(')
|
||||
}
|
||||
mut typ := p.bool_expression()
|
||||
if typ.starts_with('...') { typ = typ.right(3) }
|
||||
if clone {
|
||||
p.gen(')')
|
||||
}
|
||||
|
@ -1052,20 +1047,20 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
|
|||
// Check for commas
|
||||
if i < f.args.len - 1 {
|
||||
// Handle 0 args passed to varargs
|
||||
if p.tok != .comma && !is_variadic {
|
||||
if p.tok != .comma && !f.is_variadic {
|
||||
p.error('wrong number of arguments for $i,$arg.name fn `$f.name`: expected $f.args.len, but got less')
|
||||
}
|
||||
if p.tok == .comma && (!is_variadic || (is_variadic && i < f.args.len-2 )) {
|
||||
if p.tok == .comma && (!f.is_variadic || (f.is_variadic && i < f.args.len-2 )) {
|
||||
p.check(.comma)
|
||||
p.gen(',')
|
||||
}
|
||||
}
|
||||
}
|
||||
// varargs
|
||||
if !p.first_pass() && is_variadic {
|
||||
p.fn_gen_caller_vargs(mut f)
|
||||
varg_type, varg_values := p.fn_call_vargs(f)
|
||||
if f.is_variadic {
|
||||
saved_args << '...$varg_type'
|
||||
}
|
||||
|
||||
if p.tok == .comma {
|
||||
p.error('wrong number of arguments for fn `$f.name`: expected $f.args.len, but got more')
|
||||
}
|
||||
|
@ -1074,6 +1069,9 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
|
|||
type_map := p.extract_type_inst(f, saved_args)
|
||||
p.dispatch_generic_fn_instance(mut f, type_map)
|
||||
}
|
||||
if f.is_variadic {
|
||||
p.fn_gen_caller_vargs(f, varg_type, varg_values)
|
||||
}
|
||||
}
|
||||
|
||||
// From a given generic function and an argument list matching its signature,
|
||||
|
@ -1160,6 +1158,9 @@ fn (p mut Parser) replace_type_params(f &Fn, ti TypeInst) []string {
|
|||
fi = fi.right(6)
|
||||
fr += 'array_'
|
||||
}
|
||||
if fi.starts_with('...') {
|
||||
fi = fi.right(3)
|
||||
}
|
||||
if fi in ti.inst.keys() {
|
||||
fr += ti.inst[fi]
|
||||
// println("replaced $a => $fr")
|
||||
|
@ -1178,31 +1179,46 @@ fn (p mut Parser) fn_register_vargs_stuct(f &Fn, typ string, values []string) st
|
|||
name: vargs_struct,
|
||||
mod: p.mod
|
||||
}
|
||||
if values.len > 0 {
|
||||
p.table.rewrite_type(varg_type)
|
||||
} else {
|
||||
if !p.table.known_type(vargs_struct) {
|
||||
p.table.register_type2(varg_type)
|
||||
p.cgen.typedefs << 'typedef struct $vargs_struct $vargs_struct;\n'
|
||||
} else {
|
||||
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)
|
||||
return vargs_struct
|
||||
}
|
||||
|
||||
fn (p mut Parser) fn_gen_caller_vargs(f mut Fn) {
|
||||
fn (p mut Parser) fn_call_vargs(f Fn) (string, []string) {
|
||||
if !f.is_variadic {
|
||||
return '', []string
|
||||
}
|
||||
last_arg := f.args.last()
|
||||
varg_def_type := last_arg.typ.right(3)
|
||||
mut varg_def_type := last_arg.typ.right(3)
|
||||
mut types := []string
|
||||
mut values := []string
|
||||
for p.tok != .rpar {
|
||||
if p.tok == .comma {
|
||||
p.check(.comma)
|
||||
}
|
||||
p.cgen.start_tmp()
|
||||
varg_type := p.bool_expression()
|
||||
mut varg_type := p.bool_expression()
|
||||
varg_value := p.cgen.end_tmp()
|
||||
p.check_types(last_arg.typ, varg_type)
|
||||
if !f.is_generic {
|
||||
p.check_types(last_arg.typ, varg_type)
|
||||
} else {
|
||||
if types.len > 0 {
|
||||
for t in types {
|
||||
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('*') { '*' }
|
||||
else { '' }
|
||||
types << varg_type
|
||||
values << '$ref_deref$varg_value'
|
||||
}
|
||||
for va in p.table.varg_access {
|
||||
|
@ -1214,9 +1230,12 @@ fn (p mut Parser) fn_gen_caller_vargs(f mut Fn) {
|
|||
if f.args.len > 1 {
|
||||
p.cgen.gen(',')
|
||||
}
|
||||
vargs_struct := p.fn_register_vargs_stuct(f, varg_def_type, values)
|
||||
p.cgen.gen('&($vargs_struct){.len=$values.len,.args={'+values.join(',')+'}}')
|
||||
return varg_def_type, 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)
|
||||
p.cgen.gen('&($vargs_struct){.len=$values.len,.args={'+values.join(',')+'}}')
|
||||
}
|
||||
|
||||
fn (p mut Parser) register_multi_return_stuct(types []string) string {
|
||||
|
@ -1234,6 +1253,13 @@ fn (p mut Parser) register_multi_return_stuct(types []string) string {
|
|||
return typ
|
||||
}
|
||||
|
||||
fn (p mut Parser) rename_generic_fn_instance(f mut Fn, ti TypeInst) {
|
||||
f.name = f.name + '_T'
|
||||
for k in ti.inst.keys() {
|
||||
f.name = f.name + '_' + type_to_safe_str(ti.inst[k].replace('...', ''))
|
||||
}
|
||||
}
|
||||
|
||||
fn (p mut Parser) dispatch_generic_fn_instance(f mut Fn, ti TypeInst) {
|
||||
mut new_inst := true
|
||||
for e in f.type_inst {
|
||||
|
@ -1244,10 +1270,7 @@ fn (p mut Parser) dispatch_generic_fn_instance(f mut Fn, ti TypeInst) {
|
|||
}
|
||||
|
||||
if !new_inst {
|
||||
f.name = f.name + '_T'
|
||||
for k in ti.inst.keys() {
|
||||
f.name = f.name + '_' + type_to_safe_str(ti.inst[k])
|
||||
}
|
||||
p.rename_generic_fn_instance(mut f, ti)
|
||||
_f := p.table.find_fn(f.name) or {
|
||||
p.error('function instance `$f.name` not found')
|
||||
return
|
||||
|
@ -1276,10 +1299,7 @@ fn (p mut Parser) dispatch_generic_fn_instance(f mut Fn, ti TypeInst) {
|
|||
saved_tmp_line := p.cgen.tmp_line
|
||||
returns := p.returns // should be always false
|
||||
|
||||
f.name = f.name + '_T'
|
||||
for k in ti.inst.keys() {
|
||||
f.name = f.name + '_' + type_to_safe_str(ti.inst[k])
|
||||
}
|
||||
p.rename_generic_fn_instance(mut f, ti)
|
||||
f.is_generic = false // the instance is a normal function
|
||||
f.type_inst = []TypeInst
|
||||
f.scope_level = 0
|
||||
|
|
Loading…
Reference in New Issue