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:
committed by
Alexander Medvednikov
parent
82d4a731f3
commit
11aaee685a
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user