1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

generics: fix errors & simplify

This commit is contained in:
joe-conigliaro
2019-11-30 00:46:43 +11:00
committed by Alexander Medvednikov
parent 82d4a731f3
commit 11aaee685a
5 changed files with 84 additions and 110 deletions

View File

@@ -40,7 +40,8 @@ mut:
type_pars []string
type_inst []TypeInst
dispatch_of TypeInst // current type inst of this generic instance
generic_tmpl []Token
generic_fn_idx int
parser_idx int
fn_name_token_idx int // used by error reporting
comptime_define string
is_used bool // so that we can skip unused fns in resulting C code
@@ -195,6 +196,7 @@ fn (p mut Parser) clear_vars() {
fn (p mut Parser) fn_decl() {
p.clear_vars() // clear local vars every time a new fn is started
defer { p.fgenln('\n') }
fn_start_idx := p.cur_tok_index()
// If we are in the first pass, create a new function.
// In the second pass fetch the one we created.
/*
@@ -343,7 +345,13 @@ fn (p mut Parser) fn_decl() {
}
// Generic?
if p.tok == .lt {
f.is_generic = true
// instance (dispatch)
if p.generic_dispatch.inst.size > 0 {
f.dispatch_of = p.generic_dispatch
rename_generic_fn_instance(mut f, f.dispatch_of)
} else {
f.is_generic = true
}
p.next()
for {
type_par := p.check_name()
@@ -357,8 +365,8 @@ fn (p mut Parser) fn_decl() {
if p.tok == .gt { break }
p.check(.comma)
}
p.set_current_fn(f)
p.check(.gt)
p.set_current_fn(f)
}
// Args (...)
p.fn_args(mut f)
@@ -419,7 +427,13 @@ fn (p mut Parser) fn_decl() {
// Generic functions are inserted as needed from the call site
if f.is_generic {
if p.first_pass() {
p.save_generic_tmpl(mut f, p.cur_tok_index())
if !p.scanner.is_vh {
gpidx := p.v.get_file_parser_index(p.file_path) or {
panic('error finding parser for: $p.file_path')
}
f.parser_idx = gpidx
}
f.generic_fn_idx = fn_start_idx
if f.is_method {
rcv := p.table.find_type(receiver_typ)
if p.first_pass() && rcv.name == '' {
@@ -1015,8 +1029,8 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
}
}
p.expected_type = arg.typ
clone := p.pref.autofree && p.mod != 'string' && arg.typ == 'string' &&
!p.builtin_mod //&& arg.is_moved
clone := p.pref.autofree && p.mod != 'string' && arg.typ == 'string' &&
!p.builtin_mod //&& arg.is_moved
if clone {
p.gen('/*YY f=$f.name arg=$arg.name is_moved=$arg.is_moved*/string_clone(')
}
@@ -1410,38 +1424,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
for i in pos..p.tokens.len-1 {
tok := p.tokens[i]
if tok.tok == .lcbr { cbr_depth++ }
if tok.tok == .rcbr {
cbr_depth--
if cbr_depth == 0 { break }
}
tokens << tok
}
f.generic_tmpl = tokens
}
// 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()
if tok.tok == .name && tok_str in ti.inst {
tok_str = ti.inst[tok_str]
}
fn_body += ' $tok_str'
}
return fn_body
}
fn rename_generic_fn_instance(f mut Fn, ti &TypeInst) {
if f.is_method {
if f.is_method && f.dispatch_of.inst.size == 0 {
f.name = f.receiver_typ + '_' + f.name
}
f.name = f.name + '_T'
@@ -1469,7 +1453,6 @@ fn (p mut Parser) dispatch_generic_fn_instance(f mut Fn, ti &TypeInst) {
}
f.type_inst << *ti
p.table.register_fn(f)
rename_generic_fn_instance(mut f, ti)
replace_generic_type_params(mut f, ti)
// TODO: save dispatch info when update to incremental parsing
@@ -1485,18 +1468,17 @@ fn (p mut Parser) dispatch_generic_fn_instance(f mut Fn, ti &TypeInst) {
} else {
p.table.register_fn(f)
}
mut fn_code := '${p.fn_signature_v(f)} {\n${f.generic_tmpl_to_inst(ti)}\n}'
// TODO: parse incrementally as needed & set typeinst
if f.mod in p.v.gen_parser_idx {
pidx := p.v.gen_parser_idx[f.mod]
p.v.parsers[pidx].add_text(fn_code)
for mod in p.table.imports {
if p.v.parsers[pidx].import_table.known_import(mod) { continue }
p.v.parsers[pidx].register_import(mod, 0)
}
} else {
// TODO: add here after I work out bug
}
mut gp := p.v.parsers[f.parser_idx]
gp.is_vgen = true
gp.generic_dispatch = *ti
saved_state := p.save_state()
p.clear_state(false, true)
gp.token_idx = f.generic_fn_idx
gp.next()
gp.fn_decl()
p.cgen.lines_extra << p.cgen.lines
p.restore_state(saved_state, false, true)
p.cgen.fns << '${p.fn_signature(f)};'
}
@@ -1556,20 +1538,6 @@ fn (f &Fn) str_args(table &Table) string {
return s
}
fn (f &Fn) str_args_v(table &Table) string {
mut str_args := ''
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' } else if arg_typ == 'byte*' { arg_typ = 'byteptr' }
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'
if i < f.args.len-1 { str_args += ','}
}
return str_args
}
// find local function variable with closest name to `name`
fn (p &Parser) find_misspelled_local_var(name string, min_match f32) string {
mut closest := f32(0)
@@ -1601,24 +1569,6 @@ fn (p &Parser) fn_signature(f &Fn) string {
return '$f.typ $f.name(${f.str_args(p.table)})'
}
fn (p &Parser) fn_signature_v(f &Fn) string {
mut method := ''
mut f_name := f.name.all_after('__')
if f.is_method {
receiver_arg := f.args[0]
receiver_type := receiver_arg.typ.trim('*')
f_name = f_name.all_after('${receiver_type}_')
mut rcv_typ := receiver_arg.typ.replace('array_', '[]').replace('map_', 'map[string]')
if receiver_arg.is_mut { rcv_typ = 'mut '+rcv_typ.trim('*') }
else if rcv_typ.ends_with('*') || receiver_arg.ptr { rcv_typ = '&'+rcv_typ.trim_right('&*') }
method = '($receiver_arg.name $rcv_typ) '
}
vis := if f.is_public { 'pub ' } else { '' }
f_type := if f.typ == 'void' { '' } else if f.typ == 'void*' { 'voidptr' }
else if f.typ == 'byte*' { 'byteptr' } else { f.typ }
return '${vis}fn $method$f_name(${f.str_args_v(p.table)}) $f_type'
}
pub fn (f &Fn) v_fn_module() string {
return f.mod
}