From 3c0fca9258ccb5a15afc1b025e0f7d513a3bc7e1 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 8 Jan 2020 10:19:12 +0100 Subject: [PATCH] register methods (wip) --- vlib/builtin/array.v | 48 ++++---- vlib/builtin/array_test.v | 8 -- vlib/compiler/cheaders.v | 1 + vlib/compiler/expression.v | 12 ++ vlib/v/parser/fn.v | 12 +- vlib/v/parser/parser.v | 20 ++-- vlib/v/table/table.v | 232 ++++++++++++++++++++++++++++++++++++- vlib/v/table/type.v | 178 ---------------------------- vlib/v/types/types.v | 12 +- 9 files changed, 294 insertions(+), 229 deletions(-) delete mode 100644 vlib/v/table/type.v diff --git a/vlib/builtin/array.v b/vlib/builtin/array.v index f419093d65..e7fa70b934 100644 --- a/vlib/builtin/array.v +++ b/vlib/builtin/array.v @@ -166,6 +166,7 @@ pub fn (a array) last() voidptr { return a.data + (a.len - 1) * a.element_size } +/* // array.left returns a new array using the same buffer as the given array // with the first `n` elements of the given array. fn (a array) left(n int) array { @@ -191,12 +192,7 @@ fn (a array) right(n int) array { } return a.slice(n, a.len) } - -// used internally for [2..4] -fn (a array) slice2(start, _end int, end_max bool) array { - end := if end_max { a.len } else { _end } - return a.slice(start, end) -} +*/ // array.slice returns an array using the same buffer as original array // but starting from the `start` element and ending with the element before @@ -223,6 +219,29 @@ fn (a array) slice(start, _end int) array { return res } +// used internally for [2..4] +fn (a array) slice2(start, _end int, end_max bool) array { + end := if end_max { a.len } else { _end } + return a.slice(start, end) +} + +// array.clone returns an independent copy of a given array +pub fn (a array) clone() array { + mut size := a.cap * a.element_size + if size == 0 { + size++ + } + arr := array{ + len: a.len + cap: a.cap + element_size: a.element_size + data: calloc(size) + } + C.memcpy(arr.data, a.data, a.cap * a.element_size) + return arr +} + + fn (a array) slice_clone(start, _end int) array { mut end := _end if start > end { @@ -282,21 +301,6 @@ pub fn (a array) reverse() array { return arr } -// array.clone returns an independent copy of a given array -pub fn (a array) clone() array { - mut size := a.cap * a.element_size - if size == 0 { - size++ - } - arr := array{ - len: a.len - cap: a.cap - element_size: a.element_size - data: calloc(size) - } - C.memcpy(arr.data, a.data, a.cap * a.element_size) - return arr -} // pub fn (a []int) free() { [unsafe_fn] @@ -364,7 +368,7 @@ pub fn (b []byte) hex() string { pub fn copy(dst, src []byte) int { if dst.len > 0 && src.len > 0 { min := if dst.len < src.len { dst.len } else { src.len } - C.memcpy(dst.data, src.left(min).data, dst.element_size * min) + C.memcpy(dst.data, src[min..].data, dst.element_size * min) return min } return 0 diff --git a/vlib/builtin/array_test.v b/vlib/builtin/array_test.v index 7f94c36a75..109b56d00b 100644 --- a/vlib/builtin/array_test.v +++ b/vlib/builtin/array_test.v @@ -222,11 +222,8 @@ fn test_repeat() { fn test_right() { a := [1, 2, 3, 4] - b := a.right(1) c := a[1..a.len] d := a[1..] - assert b[0] == 2 - assert b[1] == 3 assert c[0] == 2 assert c[1] == 3 assert d[0] == 2 @@ -252,18 +249,13 @@ fn test_right_with_n_bigger_than_array_size() { fn test_left() { a := [1, 2, 3] - b := a.left(2) c := a[0..2] d := a[..2] - e := a.left(4) - assert b[0] == 1 - assert b[1] == 2 assert c[0] == 1 assert c[1] == 2 assert d[0] == 1 assert d[1] == 2 assert e[0] == 1 - assert e[2] == 3 assert e.len == 3 } diff --git a/vlib/compiler/cheaders.v b/vlib/compiler/cheaders.v index ba13d0eb6f..4d6a95c915 100644 --- a/vlib/compiler/cheaders.v +++ b/vlib/compiler/cheaders.v @@ -149,6 +149,7 @@ $c_common_macros byte g_str_buf[1024]; int load_so(byteptr); void reload_so(); + ' js_headers = ' diff --git a/vlib/compiler/expression.v b/vlib/compiler/expression.v index 3f8cfed862..a081cc29ce 100644 --- a/vlib/compiler/expression.v +++ b/vlib/compiler/expression.v @@ -77,6 +77,18 @@ fn (p mut Parser) bool_expression() string { } p.cgen.set_placeholder(start_ph, '*($cast_typ*)') p.gen('.obj') + // Make sure the sum type can be cast, otherwise throw a runtime error + /* + sum_type:= p.cgen.cur_line.all_after('*) (').replace('.obj', '.typ') + + n := cast_typ.all_after('__') + p.cgen.insert_before('if (($sum_type != SumType_$n) { +puts("runtime error: $p.file_name:$p.scanner.line_nr cannot cast sum type `$typ` to `$n`"); +exit(1); +} +') +*/ + } else { p.cgen.set_placeholder(start_ph, '($cast_typ)(') p.gen(')') diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index a3775958b2..5f899c471f 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -137,7 +137,17 @@ fn (p mut Parser) fn_decl() ast.FnDecl { ti = p.parse_ti() p.return_ti = ti } - if !is_method { + if is_method { + ok := p.table.register_method(rec_ti, table.Fn{ + name: name + args: args + return_ti: ti + }) + if !ok { + p.error('expected Struct') + } + } + else { p.table.register_fn(table.Fn{ name: name args: args diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index a97821ef27..e1b7dde0a9 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -423,19 +423,12 @@ fn (p mut Parser) index_expr(left ast.Expr) (ast.Expr,types.TypeIdent) { fn (p mut Parser) dot_expr(left ast.Expr, ti types.TypeIdent) (ast.Expr,types.TypeIdent) { p.next() field_name := p.check_name() - typ := p.table.types[ti.idx] as types.Struct - mut ok := false - for field in typ.fields { - if field.name == field_name { - ok = true - break - } - } - if !ok { - p.error('type `$typ.name` has no field or method `$field_name`') - } + struc := p.table.types[ti.idx] as types.Struct // Method call if p.tok.kind == .lpar { + if !p.table.struct_has_method(struc, field_name) { + p.error('type `$struc.name` has no method `$field_name`') + } p.next() args := p.call_args() println('method call $field_name') @@ -447,6 +440,9 @@ fn (p mut Parser) dot_expr(left ast.Expr, ti types.TypeIdent) (ast.Expr,types.Ty } return node,types.int_ti } + if !p.table.struct_has_field(struc, field_name) { + p.error('type `$struc.name` has no field `$field_name`') + } /* // p.next() field := p.check_name() @@ -660,7 +656,7 @@ fn (p mut Parser) array_init() (ast.Expr,types.TypeIdent) { p.check(.comma) } } - type_idx, type_name := p.table.find_or_register_array(val_ti, 1) + type_idx,type_name := p.table.find_or_register_array(val_ti, 1) array_ti := types.new_ti(.array, type_name, type_idx, 0) mut node := ast.Expr{} node = ast.ArrayInit{ diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index 27cd171576..8f634178bf 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -28,9 +28,9 @@ pub: pub struct Fn { pub: - name string - args []Var - return_ti types.TypeIdent + name string + args []Var + return_ti types.TypeIdent } pub fn new_table() &Table { @@ -116,8 +116,234 @@ pub fn (t mut Table) register_fn(new_fn Fn) { t.fns[new_fn.name] = new_fn } +pub fn (t mut Table) register_method(ti types.TypeIdent, new_fn Fn) bool { + println('register method `$new_fn.name` tiname=$ti.name ') + match t.types[ti.idx] { + types.Struct { + println('got struct') + } + else { + return false + } + } + mut struc := t.types[ti.idx] as types.Struct + if struc.methods.len == 0 { + struc.methods = make(0, 0, sizeof(types.Field)) + } + println('register method `$new_fn.name` struct=$struc.name ') + struc.methods << types.Field{ + name: new_fn.name + } + t.types[ti.idx] = struc + return true +} pub fn (t mut Table) new_tmp_var() string { t.tmp_cnt++ return 'tmp$t.tmp_cnt' } + +pub fn (t &Table) struct_has_field(s &types.Struct, name string) bool { + println('struct_has_field($s.name, $name) s.idx=$s.idx types.len=$t.types.len s.parent_idx=$s.parent_idx') + // for typ in t.types { + // println('$typ.idx $typ.name') + // } + for field in s.fields { + if field.name == name { + return true + } + } + if s.parent_idx != 0 { + parent := t.types[s.parent_idx] as types.Struct + println('got parent $parent.name') + for field in parent.fields { + if field.name == name { + return true + } + } + } + return false +} + +pub fn (t &Table) struct_has_method(s &types.Struct, name string) bool { + for field in s.methods { + if field.name == name { + return true + } + } + return false +} + +[inline] +pub fn (t &Table) find_type_idx(name string) int { + return t.type_idxs[name] +} + +[inline] +pub fn (t &Table) find_type(name string) ?types.Type { + idx := t.type_idxs[name] + if idx > 0 { + return t.types[idx] + } + return none +} + +pub fn (t mut Table) register_struct(typ types.Struct) int { + println('register_struct($typ.name)') + // existing + existing_idx := t.type_idxs[typ.name] + if existing_idx > 0 { + ex_type := t.types[existing_idx] + match ex_type { + types.Placeholder { + // override placeholder + println('overriding type placeholder `$it.name` with struct') + mut struct_type := types.Type{} + struct_type = { + typ | + idx:existing_idx + } + t.types[existing_idx] = struct_type + return existing_idx + } + types.Struct { + return existing_idx + } + else { + panic('cannot register type `$typ.name`, another type with this name exists') + } + } + } + // register + println('registering: $typ.name') + idx := t.types.len + t.type_idxs[typ.name] = idx + mut struct_type := types.Type{} + struct_type = { + typ | + idx:idx, + parent_idx:0, + } + t.types << struct_type + return idx +} + +pub fn (t mut Table) find_or_register_map(key_ti &types.TypeIdent, value_ti &types.TypeIdent) (int,string) { + name := 'map_${key_ti.name}_${value_ti.name}' + // existing + existing_idx := t.type_idxs[name] + if existing_idx > 0 { + return existing_idx,name + } + // register + idx := t.types.len + mut map_type := types.Type{} + map_type = types.Map{ + name: name + key_type_idx: key_ti.idx + value_type_idx: value_ti.idx + } + t.type_idxs[name] = idx + t.types << map_type + return idx,name +} + +pub fn (t mut Table) find_or_register_array(elem_ti &types.TypeIdent, nr_dims int) (int,string) { + name := 'array_${elem_ti.name}' + if nr_dims > 1 { '_${nr_dims}d' } else { '' } + // existing + existing_idx := t.type_idxs[name] + if existing_idx > 0 { + return existing_idx,name + } + // register + idx := t.types.len + mut array_type := types.Type{} + array_type = types.Array{ + idx: idx + name: name + elem_type_idx: elem_ti.idx + elem_is_ptr: elem_ti.is_ptr() + nr_dims: nr_dims + } + t.type_idxs[name] = idx + t.types << array_type + return idx,name +} + +pub fn (t mut Table) find_or_register_array_fixed(elem_ti &types.TypeIdent, size int, nr_dims int) (int,string) { + name := 'array_fixed_${elem_ti.name}_${size}' + if nr_dims > 1 { '_${nr_dims}d' } else { '' } + // existing + existing_idx := t.type_idxs[name] + if existing_idx > 0 { + return existing_idx,name + } + // register + idx := t.types.len + mut array_fixed_type := types.Type{} + array_fixed_type = types.ArrayFixed{ + idx: idx + name: name + elem_type_idx: elem_ti.idx + elem_is_ptr: elem_ti.is_ptr() + size: size + nr_dims: nr_dims + } + t.type_idxs[name] = idx + t.types << array_fixed_type + return idx,name +} + +pub fn (t mut Table) find_or_register_multi_return(mr_tis []types.TypeIdent) (int,string) { + mut name := 'multi_return' + for mr_ti in mr_tis { + name += '_$mr_ti.name' + } + // existing + existing_idx := t.type_idxs[name] + if existing_idx > 0 { + return existing_idx,name + } + // register + idx := t.types.len + mut mr_type := types.Type{} + mr_type = types.MultiReturn{ + idx: idx + name: name + tis: mr_tis + } + t.type_idxs[name] = idx + t.types << mr_type + return idx,name +} + +pub fn (t mut Table) find_or_register_variadic(variadic_ti &types.TypeIdent) (int,string) { + name := 'variadic_$variadic_ti.name' + // existing + existing_idx := t.type_idxs[name] + if existing_idx > 0 { + return existing_idx,name + } + // register + idx := t.types.len + mut variadic_type := types.Type{} + variadic_type = types.Variadic{ + idx: idx + ti: variadic_ti + } + t.type_idxs[name] = idx + t.types << variadic_type + return idx,name +} + +pub fn (t mut Table) add_placeholder_type(name string) int { + idx := t.types.len + t.type_idxs[name] = t.types.len + mut pt := types.Type{} + pt = types.Placeholder{ + idx: idx + name: name + } + println('added placeholder: $name - $idx ') + t.types << pt + return idx +} diff --git a/vlib/v/table/type.v b/vlib/v/table/type.v deleted file mode 100644 index 8a0fea9d5a..0000000000 --- a/vlib/v/table/type.v +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. -// Use of this source code is governed by an MIT license -// that can be found in the LICENSE file. -module table - -import v.types - -[inline] -pub fn (t &Table) find_type_idx(name string) int { - return t.type_idxs[name] -} - -[inline] -pub fn (t &Table) find_type(name string) ?types.Type { - idx := t.type_idxs[name] - if idx > 0 { - return t.types[idx] - } - return none -} - -pub fn (t mut Table) register_struct(typ types.Struct) int { - // existing - existing_idx := t.type_idxs[typ.name] - if existing_idx > 0 { - ex_type := t.types[existing_idx] - match ex_type { - types.Placeholder { - // override placeholder - println('overriding type placeholder `$it.name` with struct') - mut struct_type := types.Type{} - struct_type = { - typ | - idx:existing_idx - } - t.types[existing_idx] = struct_type - return existing_idx - } - types.Struct { - return existing_idx - } - else { - panic('cannot register type `$typ.name`, another type with this name exists') - } - } - } - // register - println('registering: $typ.name') - idx := t.types.len - t.type_idxs[typ.name] = idx - mut struct_type := types.Type{} - struct_type = { - typ | - idx:idx - } - t.types << struct_type - return idx -} - -pub fn (t mut Table) find_or_register_map(key_ti &types.TypeIdent, value_ti &types.TypeIdent) (int,string) { - name := 'map_${key_ti.name}_${value_ti.name}' - // existing - existing_idx := t.type_idxs[name] - if existing_idx > 0 { - return existing_idx,name - } - // register - idx := t.types.len - mut map_type := types.Type{} - map_type = types.Map{ - name: name - key_type_idx: key_ti.idx - value_type_idx: value_ti.idx - } - t.type_idxs[name] = idx - t.types << map_type - return idx,name -} - -pub fn (t mut Table) find_or_register_array(elem_ti &types.TypeIdent, nr_dims int) (int,string) { - name := 'array_${elem_ti.name}' + if nr_dims > 1 { '_${nr_dims}d' } else { '' } - // existing - existing_idx := t.type_idxs[name] - if existing_idx > 0 { - return existing_idx,name - } - // register - idx := t.types.len - mut array_type := types.Type{} - array_type = types.Array{ - idx: idx - name: name - elem_type_idx: elem_ti.idx - elem_is_ptr: elem_ti.is_ptr() - nr_dims: nr_dims - } - t.type_idxs[name] = idx - t.types << array_type - return idx,name -} - -pub fn (t mut Table) find_or_register_array_fixed(elem_ti &types.TypeIdent, size int, nr_dims int) (int,string) { - name := 'array_fixed_${elem_ti.name}_${size}' + if nr_dims > 1 { '_${nr_dims}d' } else { '' } - // existing - existing_idx := t.type_idxs[name] - if existing_idx > 0 { - return existing_idx,name - } - // register - idx := t.types.len - mut array_fixed_type := types.Type{} - array_fixed_type = types.ArrayFixed{ - idx: idx - name: name - elem_type_idx: elem_ti.idx - elem_is_ptr: elem_ti.is_ptr() - size: size - nr_dims: nr_dims - } - t.type_idxs[name] = idx - t.types << array_fixed_type - return idx,name -} - -pub fn (t mut Table) find_or_register_multi_return(mr_tis []types.TypeIdent) (int,string) { - mut name := 'multi_return' - for mr_ti in mr_tis { - name += '_$mr_ti.name' - } - // existing - existing_idx := t.type_idxs[name] - if existing_idx > 0 { - return existing_idx,name - } - // register - idx := t.types.len - mut mr_type := types.Type{} - mr_type = types.MultiReturn{ - idx: idx - name: name - tis: mr_tis - } - t.type_idxs[name] = idx - t.types << mr_type - return idx,name -} - -pub fn (t mut Table) find_or_register_variadic(variadic_ti &types.TypeIdent) (int,string) { - name := 'variadic_$variadic_ti.name' - // existing - existing_idx := t.type_idxs[name] - if existing_idx > 0 { - return existing_idx,name - } - // register - idx := t.types.len - mut variadic_type := types.Type{} - variadic_type = types.Variadic{ - idx: idx - ti: variadic_ti - } - t.type_idxs[name] = idx - t.types << variadic_type - return idx,name -} - -pub fn (t mut Table) add_placeholder_type(name string) int { - idx := t.types.len - t.type_idxs[name] = t.types.len - mut pt := types.Type{} - pt = types.Placeholder{ - idx: idx - name: name - } - println('added placeholder: $name - $idx ') - t.types << pt - return idx -} diff --git a/vlib/v/types/types.v b/vlib/v/types/types.v index 189b77e63b..f193c8cdc5 100644 --- a/vlib/v/types/types.v +++ b/vlib/v/types/types.v @@ -56,7 +56,7 @@ pub fn new_ti(kind Kind, name string, idx int, nr_muls int) TypeIdent { [inline] pub fn new_builtin_ti(kind Kind, nr_muls int) TypeIdent { return TypeIdent{ - idx: -int(kind)-1 + idx: -int(kind) - 1 kind: kind name: kind.str() nr_muls: nr_muls @@ -224,10 +224,12 @@ pub: pub struct Struct { pub: - idx int - name string - fields []Field - // methods + idx int + parent_idx int + name string +pub mut: + fields []Field + methods []Field // TODO Method } pub struct Field {