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 defer_text []string
type_pars []string type_pars []string
type_inst []TypeInst type_inst []TypeInst
// dispatch_of TypeInst // current type inst of this generic instance
generic_tmpl []Token generic_tmpl []Token
fn_name_token_idx int // used by error reporting fn_name_token_idx int // used by error reporting
comptime_define string comptime_define string
@ -1190,7 +1189,7 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
p.check(.rpar) p.check(.rpar)
if f.is_generic { if f.is_generic {
type_map := p.extract_type_inst(f, saved_args) 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 { if f.is_variadic {
p.fn_gen_caller_vargs(f, varg_type, varg_values) 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 return r
} }
// Replace function type and type of params for a given generic function using a TypeInst // replace a generic type using TypeInst
fn (p mut Parser) replace_type_params(f mut Fn, ti TypeInst) { fn replace_generic_type(gen_type string, ti &TypeInst) string {
mut args2 := []Var mut typ := gen_type.replace('map_', '')
mut args := f.args .replace('varg_', '').trim_right('*')
for i, _ in args { for typ.starts_with('array_') { typ = typ[6..] }
mut arg := args[i] if typ in ti.inst {
for k, v in ti.inst { typ = gen_type.replace(typ, ti.inst[typ])
for arg.typ.contains(k) { return typ
arg.typ = arg.typ.replace(k, v) }
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 { f.args = args
for f.typ.contains(k) { f.typ = replace_generic_type(f.typ, ti)
f.typ = f.typ.replace(k, v)
}
}
f.args = args2
} }
fn (p mut Parser) register_vargs_stuct(typ string, len int) string { 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 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) { fn (p mut Parser) save_generic_tmpl(f mut Fn, pos int) {
mut cbr_depth := 1 mut cbr_depth := 1
mut tokens := []Token mut tokens := []Token
@ -1377,7 +1395,8 @@ fn (p mut Parser) save_generic_tmpl(f mut Fn, pos int) {
f.generic_tmpl = tokens 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 := '' mut fn_body := ''
for tok in f.generic_tmpl { for tok in f.generic_tmpl {
mut tok_str := tok.str() mut tok_str := tok.str()
@ -1389,7 +1408,7 @@ fn (f &Fn) generic_tmpl_to_inst(ti TypeInst) string {
return fn_body 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 { if f.is_method {
f.name = f.receiver_typ + '_' + f.name 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 mut new_inst := true
for e in f.type_inst { for e in f.type_inst {
if e.inst.str() == ti.inst.str() { 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 { 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 { _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 return
} }
// println('using existing inst ${p.fn_signature_v(f)}') // println('using existing inst ${p.fn_signature_v(f)}')
return return
} }
f.type_inst << ti f.type_inst << *ti
p.table.register_fn(f) p.table.register_fn(f)
// 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)
p.rename_generic_fn_instance(mut f, ti) // TODO: Handle case where type not defined yet, see above
p.replace_type_params(mut f, ti)
// TODO: Handle
// if f.typ in f.type_pars { f.typ = '_ANYTYPE_' } // if f.typ in f.type_pars { f.typ = '_ANYTYPE_' }
// if f.typ in ti.inst { // if f.typ in ti.inst {
// f.typ = ti.inst[f.typ] // f.typ = ti.inst[f.typ]
// } // }
f.is_generic = false
if f.is_method { if f.is_method {
p.add_method(f.args[0].name, f) p.add_method(f.args[0].name, f)
} else { } else {
@ -1508,6 +1528,7 @@ fn (f &Fn) str_args_v(table &Table) string {
for i, arg in f.args { for i, arg in f.args {
if f.is_method && i == 0 { continue } if f.is_method && i == 0 { continue }
mut arg_typ := arg.typ.replace('array_', '[]').replace('map_', 'map[string]') 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('*') } if arg.is_mut { arg_typ = 'mut '+arg_typ.trim('*') }
else if arg_typ.ends_with('*') || arg.ptr { arg_typ = '&'+arg_typ.trim_right('*') } else if arg_typ.ends_with('*') || arg.ptr { arg_typ = '&'+arg_typ.trim_right('*') }
str_args += '$arg.name $arg_typ' 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) ' method = '($receiver_arg.name $rcv_typ) '
} }
vis := if f.is_public { 'pub ' } else { '' } 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' return '${vis}fn $method$f_name(${f.str_args_v(p.table)}) $f_type'
} }