mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
compiler: clean up & optimize generics. add comments & support all param types (#2845)
This commit is contained in:
parent
956c605934
commit
c11025f01f
@ -39,7 +39,6 @@ mut:
|
||||
defer_text []string
|
||||
type_pars []string
|
||||
type_inst []TypeInst
|
||||
// dispatch_of TypeInst // current type inst of this generic instance
|
||||
generic_tmpl []Token
|
||||
fn_name_token_idx int // used by error reporting
|
||||
comptime_define string
|
||||
@ -1190,7 +1189,7 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
|
||||
p.check(.rpar)
|
||||
if f.is_generic {
|
||||
type_map := p.extract_type_inst(f, saved_args)
|
||||
p.dispatch_generic_fn_instance(mut f, type_map)
|
||||
p.dispatch_generic_fn_instance(mut f, &type_map)
|
||||
}
|
||||
if f.is_variadic {
|
||||
p.fn_gen_caller_vargs(f, varg_type, varg_values)
|
||||
@ -1248,25 +1247,42 @@ fn (p mut Parser) extract_type_inst(f &Fn, args_ []string) TypeInst {
|
||||
return r
|
||||
}
|
||||
|
||||
// Replace function type and type of params for a given generic function using a TypeInst
|
||||
fn (p mut Parser) replace_type_params(f mut Fn, ti TypeInst) {
|
||||
mut args2 := []Var
|
||||
mut args := f.args
|
||||
for i, _ in args {
|
||||
mut arg := args[i]
|
||||
for k, v in ti.inst {
|
||||
for arg.typ.contains(k) {
|
||||
arg.typ = arg.typ.replace(k, v)
|
||||
// replace a generic type using TypeInst
|
||||
fn replace_generic_type(gen_type string, ti &TypeInst) string {
|
||||
mut typ := gen_type.replace('map_', '')
|
||||
.replace('varg_', '').trim_right('*')
|
||||
for typ.starts_with('array_') { typ = typ[6..] }
|
||||
if typ in ti.inst {
|
||||
typ = gen_type.replace(typ, ti.inst[typ])
|
||||
return typ
|
||||
}
|
||||
typ = gen_type
|
||||
if typ.starts_with('fn (') {
|
||||
args := typ[4..].all_before_last(')').split(',')
|
||||
ret_t := typ.all_after(')').trim_space()
|
||||
mut args_r := []string
|
||||
for arg in args {
|
||||
args_r << replace_generic_type(arg, ti)
|
||||
}
|
||||
mut t := 'fn (' + args_r.join(',') + ')'
|
||||
if ret_t.len > 0 {
|
||||
t += ' ' + replace_generic_type(ret_t, ti)
|
||||
}
|
||||
typ = t
|
||||
}
|
||||
args2 << arg
|
||||
return typ
|
||||
}
|
||||
|
||||
// replace return type & param types for a given generic function using TypeInst
|
||||
fn replace_generic_type_params(f mut Fn, ti &TypeInst) {
|
||||
mut args := []Var
|
||||
for i, _ in f.args {
|
||||
mut arg := f.args[i]
|
||||
arg.typ = replace_generic_type(arg.typ, ti)
|
||||
args << arg
|
||||
}
|
||||
for k, v in ti.inst {
|
||||
for f.typ.contains(k) {
|
||||
f.typ = f.typ.replace(k, v)
|
||||
}
|
||||
}
|
||||
f.args = args2
|
||||
f.args = args
|
||||
f.typ = replace_generic_type(f.typ, ti)
|
||||
}
|
||||
|
||||
fn (p mut Parser) register_vargs_stuct(typ string, len int) string {
|
||||
@ -1362,6 +1378,8 @@ fn (p mut Parser) register_multi_return_stuct(types []string) string {
|
||||
return typ
|
||||
}
|
||||
|
||||
// save the tokens for the generic funciton body (between `{}`)
|
||||
// the function signature isn't saved, it is reconstructed from Fn
|
||||
fn (p mut Parser) save_generic_tmpl(f mut Fn, pos int) {
|
||||
mut cbr_depth := 1
|
||||
mut tokens := []Token
|
||||
@ -1377,7 +1395,8 @@ fn (p mut Parser) save_generic_tmpl(f mut Fn, pos int) {
|
||||
f.generic_tmpl = tokens
|
||||
}
|
||||
|
||||
fn (f &Fn) generic_tmpl_to_inst(ti TypeInst) string {
|
||||
// replace generic types in function body template with types from TypeInst
|
||||
fn (f &Fn) generic_tmpl_to_inst(ti &TypeInst) string {
|
||||
mut fn_body := ''
|
||||
for tok in f.generic_tmpl {
|
||||
mut tok_str := tok.str()
|
||||
@ -1389,7 +1408,7 @@ fn (f &Fn) generic_tmpl_to_inst(ti TypeInst) string {
|
||||
return fn_body
|
||||
}
|
||||
|
||||
fn (p mut Parser) rename_generic_fn_instance(f mut Fn, ti TypeInst) {
|
||||
fn rename_generic_fn_instance(f mut Fn, ti &TypeInst) {
|
||||
if f.is_method {
|
||||
f.name = f.receiver_typ + '_' + f.name
|
||||
}
|
||||
@ -1399,7 +1418,7 @@ fn (p mut Parser) rename_generic_fn_instance(f mut Fn, ti TypeInst) {
|
||||
}
|
||||
}
|
||||
|
||||
fn (p mut Parser) dispatch_generic_fn_instance(f mut Fn, ti TypeInst) {
|
||||
fn (p mut Parser) dispatch_generic_fn_instance(f mut Fn, ti &TypeInst) {
|
||||
mut new_inst := true
|
||||
for e in f.type_inst {
|
||||
if e.inst.str() == ti.inst.str() {
|
||||
@ -1408,26 +1427,27 @@ fn (p mut Parser) dispatch_generic_fn_instance(f mut Fn, ti TypeInst) {
|
||||
}
|
||||
}
|
||||
if !new_inst {
|
||||
p.rename_generic_fn_instance(mut f, ti)
|
||||
rename_generic_fn_instance(mut f, ti)
|
||||
_f := p.table.find_fn(f.name) or {
|
||||
// p.error('function instance `$f.name` not found')
|
||||
p.error('function instance `$f.name` not found')
|
||||
return
|
||||
}
|
||||
// println('using existing inst ${p.fn_signature_v(f)}')
|
||||
return
|
||||
}
|
||||
f.type_inst << ti
|
||||
f.type_inst << *ti
|
||||
p.table.register_fn(f)
|
||||
|
||||
p.rename_generic_fn_instance(mut f, ti)
|
||||
p.replace_type_params(mut f, ti)
|
||||
// NOTE: f.dispatch_of was removed because of how the parsing is done now. if we need
|
||||
// function dispatch info we will need to store it somewhere other than function
|
||||
// or reattach it to the function instance in fn_decl when the generic instance is parsed
|
||||
rename_generic_fn_instance(mut f, ti)
|
||||
replace_generic_type_params(mut f, ti)
|
||||
|
||||
// TODO: Handle
|
||||
// TODO: Handle case where type not defined yet, see above
|
||||
// if f.typ in f.type_pars { f.typ = '_ANYTYPE_' }
|
||||
// if f.typ in ti.inst {
|
||||
// f.typ = ti.inst[f.typ]
|
||||
// }
|
||||
f.is_generic = false
|
||||
if f.is_method {
|
||||
p.add_method(f.args[0].name, f)
|
||||
} else {
|
||||
@ -1508,6 +1528,7 @@ fn (f &Fn) str_args_v(table &Table) string {
|
||||
for i, arg in f.args {
|
||||
if f.is_method && i == 0 { continue }
|
||||
mut arg_typ := arg.typ.replace('array_', '[]').replace('map_', 'map[string]')
|
||||
if arg_typ == 'void*' { arg_typ = 'voidptr' }
|
||||
if arg.is_mut { arg_typ = 'mut '+arg_typ.trim('*') }
|
||||
else if arg_typ.ends_with('*') || arg.ptr { arg_typ = '&'+arg_typ.trim_right('*') }
|
||||
str_args += '$arg.name $arg_typ'
|
||||
@ -1560,7 +1581,7 @@ fn (p &Parser) fn_signature_v(f &Fn) string {
|
||||
method = '($receiver_arg.name $rcv_typ) '
|
||||
}
|
||||
vis := if f.is_public { 'pub ' } else { '' }
|
||||
f_type := if f.typ == 'void' { '' } else { f.typ }
|
||||
f_type := if f.typ == 'void' { '' } else if f.typ == 'void*' { 'voidptr' } else { f.typ }
|
||||
return '${vis}fn $method$f_name(${f.str_args_v(p.table)}) $f_type'
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user