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

generic functions

This commit is contained in:
Simon Heuser
2019-10-20 09:19:37 +02:00
committed by Alexander Medvednikov
parent f63e24e51d
commit 8a31ee4b53
10 changed files with 705 additions and 368 deletions

View File

@ -12,7 +12,6 @@ mut:
typesmap map[string]Type
consts []Var
fns map[string]Fn
generic_fns []GenTable //map[string]GenTable // generic_fns['listen_and_serve'] == ['Blog', 'Forum']
obf_ids map[string]int // obf_ids['myfunction'] == 23
modules []string // List of all modules registered by the application
imports []string // List of all imports
@ -40,12 +39,6 @@ enum NameCategory {
struct Name {
cat NameCategory
idx int // e.g. typ := types[name.idx]
}
struct GenTable {
fn_name string
mut:
types []string
}
// Holds import information scoped to the parsed file
@ -125,7 +118,7 @@ mut:
// This information is needed in the first pass.
is_placeholder bool
gen_str bool // needs `.str()` method generation
}
struct TypeNode {
@ -218,6 +211,7 @@ fn (t &Table) debug_fns() string {
const (
number_types = ['number', 'int', 'i8', 'i16', 'u16', 'u32', 'byte', 'i64', 'u64', 'f32', 'f64']
float_types = ['f32', 'f64']
reserved_type_param_names = ['R', 'S', 'T', 'U', 'W']
)
fn is_number_type(typ string) bool {
@ -254,8 +248,10 @@ fn new_table(obfuscate bool) &Table {
t.register_type('bool')
t.register_type('void')
t.register_type('voidptr')
t.register_type('T')
t.register_type('va_list')
for c in reserved_type_param_names {
t.register_type(c)
}
t.register_const('stdin', 'int', 'main')
t.register_const('stdout', 'int', 'main')
t.register_const('stderr', 'int', 'main')
@ -585,6 +581,13 @@ fn (p mut Parser) check_types2(got_, expected_ string, throw bool) bool {
if p.pref.translated {
return true
}
// generic return type
if expected == '_ANYTYPE_' {
p.cur_fn.typ = got
return true
}
// variadic
if expected.starts_with('...') {
expected = expected.right(3)
@ -665,7 +668,7 @@ fn (p mut Parser) check_types2(got_, expected_ string, throw bool) bool {
if got.starts_with('fn ') && (expected.ends_with('fn') ||
expected.ends_with('Fn')) {
return true
}
}
// Allow pointer arithmetic
if expected=='void*' && got=='int' {
return true
@ -676,7 +679,7 @@ fn (p mut Parser) check_types2(got_, expected_ string, throw bool) bool {
//}
if is_number_type(got) && is_number_type(expected) && p.is_const_literal {
return true
}
}
expected = expected.replace('*', '')
got = got.replace('*', '')
if got != expected {
@ -749,7 +752,7 @@ fn (t &Table) has_at_least_one_test_fn() bool {
for _, f in t.fns {
if f.name.starts_with('main__test_') {
return true
}
}
}
return false
}
@ -778,7 +781,7 @@ fn (table &Table) cgen_name_type_pair(name, typ string) string {
else if typ.starts_with('fn (') {
T := table.find_type(typ)
if T.name == '' {
println('this should never happen')
eprintln('function type `$typ` not found')
exit(1)
}
str_args := T.func.str_args(table)
@ -811,32 +814,6 @@ fn is_valid_int_const(val, typ string) bool {
return true
}
fn (t mut Table) register_generic_fn(fn_name string) {
t.generic_fns << GenTable{fn_name, []string}
}
fn (t &Table) fn_gen_types(fn_name string) []string {
for _, f in t.generic_fns {
if f.fn_name == fn_name {
return f.types
}
}
verror('function $fn_name not found')
return []string
}
// `foo<Bar>()`
// fn_name == 'foo'
// typ == 'Bar'
fn (t mut Table) register_generic_fn_type(fn_name, typ string) {
for i, f in t.generic_fns {
if f.fn_name == fn_name {
t.generic_fns[i].types << typ
return
}
}
}
fn (p mut Parser) typ_to_fmt(typ string, level int) string {
t := p.table.find_type(typ)
if t.cat == .enum_ {
@ -866,6 +843,11 @@ fn (p mut Parser) typ_to_fmt(typ string, level int) string {
return ''
}
fn type_to_safe_str(typ string) string {
r := typ.replace(' ','').replace('(','_').replace(')','_')
return r
}
fn is_compile_time_const(s_ string) bool {
s := s_.trim_space()
if s == '' {