table: use optional in find_method()

pull/2035/head
Alexander Medvednikov 2019-09-18 15:37:34 +03:00
parent 059cb9cb74
commit 13e4c79f58
7 changed files with 49 additions and 38 deletions

View File

@ -224,30 +224,22 @@ fn (p mut Parser) comptime_method_call(typ Type) {
}
fn (p mut Parser) gen_array_str(typ Type) {
//println('gen array str "$typ.name"')
p.table.add_method(typ.name, Fn{
name: 'str',
p.add_method(typ.name, Fn{
name: 'str'
typ: 'string'
args: [Var{typ: typ.name, is_arg:true}]
is_method: true
is_public: true
receiver_typ: typ.name
})
/*
tt := p.table.find_type(typ.name)
for m in tt.methods {
println(m.name + ' ' + m.typ)
}
*/
t := typ.name
elm_type := t.right(6)
elm_type := typ.name.right(6)
elm_type2 := p.table.find_type(elm_type)
if p.typ_to_fmt(elm_type, 0) == '' &&
!p.table.type_has_method(elm_type2, 'str') {
p.error('cant print ${elm_type}[], unhandled print of ${elm_type}')
}
p.cgen.fns << '
string ${t}_str($t a) {
string ${typ.name}_str($typ.name a) {
strings__Builder sb = strings__new_builder(a.len * 3);
strings__Builder_write(&sb, tos2("[")) ;
for (int i = 0; i < a.len; i++) {

View File

@ -368,7 +368,7 @@ fn (p mut Parser) fn_decl() {
}
p.table.register_type2(receiver_t)
}
p.table.add_method(receiver_t.name, f)
p.add_method(receiver_t.name, f)
}
else {
// println('register_fn typ=$typ isg=$is_generic')

View File

@ -37,7 +37,7 @@ fn (p mut Parser) gen_var_decl(name string, is_static bool) string {
p.statements()
p.genln('$typ $name = *($typ*) $tmp . data;')
if !p.returns && p.prev_tok2 != .key_continue && p.prev_tok2 != .key_break {
p.error('`or` block must return/continue/break/panic')
p.error('`or` block must return/exit/continue/break/panic')
}
p.returns = false
return typ
@ -150,7 +150,7 @@ fn (table mut Table) fn_gen_name(f &Fn) string {
name = name.replace('-', 'minus')
}
// Avoid name conflicts (with things like abs(), print() etc).
// Generate b_abs(), b_print()
// Generate v_abs(), v_print()
// TODO duplicate functionality
if f.mod == 'builtin' && f.name in CReserved {
return 'v_$name'

View File

@ -626,7 +626,7 @@ fn (p mut Parser) struct_decl() {
if is_interface {
f := p.interface_method(field_name, name)
if p.first_pass() {
p.table.add_method(typ.name, f)
p.add_method(typ.name, f)
}
continue
}
@ -1771,7 +1771,7 @@ fn (p mut Parser) dot(str_typ string, method_ph int) string {
//println('ORM dot $str_typ')
//}
p.check(.dot)
typ := p.find_type(str_typ)
mut typ := p.find_type(str_typ)
if typ.name.len == 0 {
p.error('dot(): cannot find type `$str_typ`')
}
@ -1781,7 +1781,7 @@ fn (p mut Parser) dot(str_typ string, method_ph int) string {
}
field_name := p.lit
p.fgen(field_name)
p.log('dot() field_name=$field_name typ=$str_typ')
//p.log('dot() field_name=$field_name typ=$str_typ')
//if p.fileis('main.v') {
//println('dot() field_name=$field_name typ=$str_typ prev_tok=${prev_tok.str()}')
//}
@ -1795,7 +1795,7 @@ fn (p mut Parser) dot(str_typ string, method_ph int) string {
if !typ.is_c && !p.is_c_fn_call && !has_field && !has_method && !p.first_pass() {
if typ.name.starts_with('Option_') {
opt_type := typ.name.right(7)
p.error('unhandled option type: $opt_type?')
p.error('unhandled option type: `?$opt_type`')
}
//println('error in dot():')
//println('fields:')
@ -1850,7 +1850,10 @@ struct $f.parent_fn {
return field.typ
}
// method
method := p.table.find_method(typ, field_name)
method := p.table.find_method(typ, field_name) or {
p.error('could not find method `$field_name`') // should never happen
exit(1)
}
p.fn_call(method, method_ph, '', str_typ)
// Methods returning `array` should return `array_string`
if method.typ == 'array' && typ.name.starts_with('array_') {
@ -3543,7 +3546,7 @@ fn (p mut Parser) go_statement() {
p.next()
p.check(.dot)
typ := p.table.find_type(v.typ)
method := p.table.find_method(typ, p.lit)
method := p.table.find_method(typ, p.lit) or { panic('go method') }
p.async_fn_call(method, 0, var_name, v.typ)
}
// Normal function

View File

@ -438,29 +438,38 @@ fn (table &Table) find_field(typ &Type, name string) ?Var {
return none
}
fn (table mut Table) add_method(type_name string, f Fn) {
fn (p mut Parser) add_method(type_name string, f Fn) {
if !p.first_pass() && f.name != 'str' {
return
}
if type_name == '' {
print_backtrace()
cerror('add_method: empty type')
}
// TODO table.typesmap[type_name].methods << f
mut t := table.typesmap[type_name]
mut t := p.table.typesmap[type_name]
if type_name == 'str' {
println(t.methods.len)
}
t.methods << f
table.typesmap[type_name] = t
if type_name == 'str' {
println(t.methods.len)
}
p.table.typesmap[type_name] = t
}
fn (t &Type) has_method(name string) bool {
method := t.find_method(name)
return (method.name != '')
_ := t.find_method(name) or { return false }
return true
}
fn (table &Table) type_has_method(typ &Type, name string) bool {
method := table.find_method(typ, name)
return (method.name != '')
_ := table.find_method(typ, name) or { return false }
return true
}
// TODO use `?Fn`
fn (table &Table) find_method(typ &Type, name string) Fn {
fn (table &Table) find_method(typ &Type, name string) ?Fn {
t := table.typesmap[typ.name]
for method in t.methods {
if method.name == name {
@ -469,12 +478,17 @@ fn (table &Table) find_method(typ &Type, name string) Fn {
}
if typ.parent != '' {
parent := table.find_type(typ.parent)
return parent.find_method(name)
for method in parent.methods {
if method.name == name {
return method
}
}
return none
}
return Fn{}
return none
}
fn (t &Type) find_method(name string) Fn {
fn (t &Type) find_method(name string) ?Fn {
// println('$t.name find_method($name) methods.len=$t.methods.len')
for method in t.methods {
// println('method=$method.name')
@ -482,9 +496,7 @@ fn (t &Type) find_method(name string) Fn {
return method
}
}
//println('ret Fn{}')
return Fn{}
//return none
return none
}
/*
@ -512,6 +524,7 @@ fn (t &Table) find_type(name_ string) Type {
name = name.left(name.len - 1)
}
if !(name in t.typesmap) {
//println('ret Type')
return Type{}
}
return t.typesmap[name]
@ -520,7 +533,7 @@ fn (t &Table) find_type(name_ string) Type {
fn (p mut Parser) _check_types(got_, expected_ string, throw bool) bool {
mut got := got_
mut expected := expected_
p.log('check types got="$got" exp="$expected" ')
//p.log('check types got="$got" exp="$expected" ')
if p.pref.translated {
return true
}

View File

@ -7,7 +7,7 @@ fn test_array_str() {
println(f)
//s := f.str()
//println(s)
n := [i64(1), 2, 3]
n := [1, 2, 3]
assert n.str() == '[1, 2, 3]'
println(n) // make sure the array is printable
n2 := [4,5,6]

View File

@ -9,6 +9,7 @@
+ fix non-ascii rendering in gg (ä, å, etc)
- cache all tokens once
- enable vfmt
- bring back vdoc and regenerate all module docs
- optimize the parser (reduce map lookups)
- cache vlib (right now it's re-compiled every time)
- fix openssl on older linux distros
@ -31,4 +32,6 @@
+ o(log n) type lookup
- prebuilt binaries for all platforms
- fix interfaces
- `none` keyword for optionals
- table: migrate all find*** functions to optionals