1
0
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:
joe-conigliaro 2019-11-23 00:09:53 +11:00 committed by GitHub
parent 956c605934
commit c11025f01f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

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