generics: fix errors & simplify
parent
82d4a731f3
commit
11aaee685a
|
@ -16,6 +16,7 @@ struct CGen {
|
|||
is_user bool
|
||||
mut:
|
||||
lines []string
|
||||
lines_extra []string
|
||||
typedefs []string
|
||||
type_aliases []string
|
||||
includes []string
|
||||
|
@ -102,6 +103,7 @@ fn (g mut CGen) resetln(s string) {
|
|||
fn (g mut CGen) save() {
|
||||
s := g.lines.join('\n')
|
||||
g.out.writeln(s)
|
||||
g.out.writeln(g.lines_extra.join('\n'))
|
||||
g.out.close()
|
||||
}
|
||||
|
||||
|
|
|
@ -160,6 +160,12 @@ fn (p mut Parser) name_expr() string {
|
|||
}
|
||||
|
||||
mut name := p.lit
|
||||
|
||||
// generic type check
|
||||
if name in p.cur_fn.dispatch_of.inst.keys() {
|
||||
name = p.cur_fn.dispatch_of.inst[name]
|
||||
}
|
||||
|
||||
// Raw string (`s := r'hello \n ')
|
||||
if (name == 'r' || name == 'c') && p.peek() == .str && p.prev_tok != .dollar {
|
||||
p.string_expr()
|
||||
|
|
|
@ -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 == '' {
|
||||
|
@ -1016,7 +1030,7 @@ 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
|
||||
!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
|
||||
}
|
||||
|
|
|
@ -302,12 +302,8 @@ pub fn (v mut V) compile() {
|
|||
// free the string builder which held the generated methods
|
||||
v.vgen_buf.free()
|
||||
vgen_parser.is_vgen = true
|
||||
v.add_parser(vgen_parser)
|
||||
// run vgen / generic parsers
|
||||
for i, _ in v.parsers {
|
||||
if !v.parsers[i].is_vgen { continue }
|
||||
v.parsers[i].parse(.main)
|
||||
}
|
||||
// v.add_parser(vgen_parser)
|
||||
vgen_parser.parse(.main)
|
||||
// Generate .vh if we are building a module
|
||||
if v.pref.build_mode == .build_module {
|
||||
generate_vh(v.dir)
|
||||
|
@ -664,13 +660,6 @@ pub fn (v mut V) add_v_files_to_compile() {
|
|||
// resolve deps and add imports in correct order
|
||||
imported_mods := v.resolve_deps().imports()
|
||||
for mod in imported_mods {
|
||||
// TODO: work out bug and only add when needed in fn.v
|
||||
if !mod in v.gen_parser_idx {
|
||||
mut gp := v.new_parser_from_string('module '+mod.all_after('.')+'\n')
|
||||
gp.is_vgen = true
|
||||
gp.mod = mod
|
||||
v.gen_parser_idx[mod] = v.add_parser(gp)
|
||||
}
|
||||
if mod == 'builtin' || mod == 'main' {
|
||||
// builtin already added
|
||||
// main files will get added last
|
||||
|
|
|
@ -74,6 +74,7 @@ mut:
|
|||
sql_params []string // ("select * from users where id = $1", ***"100"***)
|
||||
sql_types []string // int, string and so on; see sql_params
|
||||
is_vh bool // parsing .vh file (for example `const (a int)` is allowed)
|
||||
generic_dispatch TypeInst
|
||||
pub:
|
||||
mod string
|
||||
}
|
||||
|
@ -94,6 +95,9 @@ struct ParserState {
|
|||
scanner_pos int
|
||||
scanner_line_ends []int
|
||||
scanner_nlines int
|
||||
cgen_lines []string
|
||||
cgen_cur_line string
|
||||
cgen_tmp_line string
|
||||
tokens []Token
|
||||
token_idx int
|
||||
tok TokenKind
|
||||
|
@ -285,6 +289,9 @@ pub fn (p mut Parser) save_state() ParserState {
|
|||
scanner_pos : p.scanner.pos
|
||||
scanner_line_ends : p.scanner.line_ends
|
||||
scanner_nlines : p.scanner.nlines
|
||||
cgen_lines : p.cgen.lines
|
||||
cgen_cur_line : p.cgen.cur_line
|
||||
cgen_tmp_line : p.cgen.tmp_line
|
||||
tokens : p.tokens
|
||||
token_idx : p.token_idx
|
||||
tok : p.tok
|
||||
|
@ -294,12 +301,19 @@ pub fn (p mut Parser) save_state() ParserState {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn (p mut Parser) restore_state(state ParserState) {
|
||||
p.scanner.line_nr = state.scanner_line_nr
|
||||
p.scanner.text = state.scanner_text
|
||||
p.scanner.pos = state.scanner_pos
|
||||
p.scanner.line_ends = state.scanner_line_ends
|
||||
p.scanner.nlines = state.scanner_nlines
|
||||
pub fn (p mut Parser) restore_state(state ParserState, scanner bool, cgen bool) {
|
||||
if scanner {
|
||||
p.scanner.line_nr = state.scanner_line_nr
|
||||
p.scanner.text = state.scanner_text
|
||||
p.scanner.pos = state.scanner_pos
|
||||
p.scanner.line_ends = state.scanner_line_ends
|
||||
p.scanner.nlines = state.scanner_nlines
|
||||
}
|
||||
if cgen {
|
||||
p.cgen.lines = state.cgen_lines
|
||||
p.cgen.cur_line = state.cgen_cur_line
|
||||
p.cgen.tmp_line = state.cgen_tmp_line
|
||||
}
|
||||
p.tokens = state.tokens
|
||||
p.token_idx = state.token_idx
|
||||
p.tok = state.tok
|
||||
|
@ -308,12 +322,19 @@ pub fn (p mut Parser) restore_state(state ParserState) {
|
|||
p.lit = state.lit
|
||||
}
|
||||
|
||||
fn (p mut Parser) clear_state() {
|
||||
p.scanner.line_nr = 0
|
||||
p.scanner.text = ''
|
||||
p.scanner.pos = 0
|
||||
p.scanner.line_ends = []
|
||||
p.scanner.nlines = 0
|
||||
fn (p mut Parser) clear_state(scanner bool, cgen bool) {
|
||||
if scanner {
|
||||
p.scanner.line_nr = 0
|
||||
p.scanner.text = ''
|
||||
p.scanner.pos = 0
|
||||
p.scanner.line_ends = []
|
||||
p.scanner.nlines = 0
|
||||
}
|
||||
if cgen {
|
||||
p.cgen.lines = []
|
||||
p.cgen.cur_line = ''
|
||||
p.cgen.tmp_line = ''
|
||||
}
|
||||
p.tokens = []
|
||||
p.token_idx = 0
|
||||
p.lit = ''
|
||||
|
@ -329,7 +350,7 @@ pub fn (p mut Parser) add_text(text string) {
|
|||
|
||||
fn (p mut Parser) statements_from_text(text string, rcbr bool) {
|
||||
saved_state := p.save_state()
|
||||
p.clear_state()
|
||||
p.clear_state(true, false)
|
||||
p.add_text(text)
|
||||
p.next()
|
||||
if rcbr {
|
||||
|
@ -337,7 +358,7 @@ fn (p mut Parser) statements_from_text(text string, rcbr bool) {
|
|||
} else {
|
||||
p.statements_no_rcbr()
|
||||
}
|
||||
p.restore_state(saved_state)
|
||||
p.restore_state(saved_state, true, false)
|
||||
}
|
||||
|
||||
fn (p mut Parser) parse(pass Pass) {
|
||||
|
@ -961,7 +982,13 @@ fn (p mut Parser) get_type() string {
|
|||
nr_muls++
|
||||
p.check(.amp)
|
||||
}
|
||||
typ += p.lit
|
||||
// generic type check
|
||||
ti := p.cur_fn.dispatch_of.inst
|
||||
if p.lit in ti.keys() {
|
||||
typ += ti[p.lit]
|
||||
} else {
|
||||
typ += p.lit
|
||||
}
|
||||
// C.Struct import
|
||||
if p.lit == 'C' && p.peek() == .dot {
|
||||
p.next()
|
||||
|
|
Loading…
Reference in New Issue