interface: support arguments in methods and simplify
parent
71a92eb87b
commit
4b3ce79e84
|
@ -103,14 +103,6 @@ const (
|
|||
)
|
||||
|
||||
pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string {
|
||||
if true { // if
|
||||
x := 10 // line
|
||||
// sep
|
||||
y := 20
|
||||
_ = x
|
||||
_ = y
|
||||
} else {
|
||||
}
|
||||
// println('start cgen2')
|
||||
mut g := Gen{
|
||||
out: strings.new_builder(1000)
|
||||
|
@ -291,8 +283,8 @@ pub fn (mut g Gen) write_typeof_functions() {
|
|||
}
|
||||
|
||||
// V type to C type
|
||||
pub fn (mut g Gen) typ(t table.Type) string {
|
||||
mut styp := g.base_typ(t)
|
||||
fn (mut g Gen) typ(t table.Type) string {
|
||||
mut styp := g.base_type(t)
|
||||
if t.flag_is(.optional) {
|
||||
// Register an optional
|
||||
styp = 'Option_' + styp
|
||||
|
@ -309,13 +301,20 @@ pub fn (mut g Gen) typ(t table.Type) string {
|
|||
return styp
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) base_typ(t table.Type) string {
|
||||
fn (g &Gen) base_type(t table.Type) string {
|
||||
mut styp := g.cc_type(t)
|
||||
nr_muls := t.nr_muls()
|
||||
sym := g.table.get_type_symbol(t)
|
||||
mut styp := sym.name.replace('.', '__')
|
||||
if nr_muls > 0 {
|
||||
styp += strings.repeat(`*`, nr_muls)
|
||||
}
|
||||
return styp
|
||||
}
|
||||
|
||||
// cc_type returns the Cleaned Concrete Type name, *without ptr*,
|
||||
// i.e. it's always just Cat, not Cat_ptr:
|
||||
fn (g &Gen) cc_type(t table.Type) string {
|
||||
sym := g.table.get_type_symbol(t)
|
||||
mut styp := sym.name.replace('.', '__')
|
||||
if styp.starts_with('C__') {
|
||||
styp = styp[3..]
|
||||
if sym.kind == .struct_ {
|
||||
|
@ -330,6 +329,12 @@ pub fn (mut g Gen) base_typ(t table.Type) string {
|
|||
|
||||
//
|
||||
pub fn (mut g Gen) write_typedef_types() {
|
||||
g.typedefs.writeln('
|
||||
typedef struct {
|
||||
void* _object;
|
||||
int _interface_idx;
|
||||
} _Interface;
|
||||
')
|
||||
for typ in g.table.types {
|
||||
match typ.kind {
|
||||
.alias {
|
||||
|
@ -342,6 +347,9 @@ pub fn (mut g Gen) write_typedef_types() {
|
|||
styp := typ.name.replace('.', '__')
|
||||
g.definitions.writeln('typedef array $styp;')
|
||||
}
|
||||
.interface_ {
|
||||
g.definitions.writeln('typedef _Interface ${c_name(typ.name)};')
|
||||
}
|
||||
.map {
|
||||
styp := typ.name.replace('.', '__')
|
||||
g.definitions.writeln('typedef map $styp;')
|
||||
|
@ -842,7 +850,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
}
|
||||
g.expr(ident)
|
||||
if is_optional {
|
||||
mr_base_styp := g.base_typ(return_type)
|
||||
mr_base_styp := g.base_type(return_type)
|
||||
g.writeln(' = (*(${mr_base_styp}*)${mr_var_name}.data).arg$i;')
|
||||
} else {
|
||||
g.writeln(' = ${mr_var_name}.arg$i;')
|
||||
|
@ -1185,7 +1193,6 @@ fn (mut g Gen) expr(node ast.Expr) {
|
|||
}
|
||||
ast.SelectorExpr {
|
||||
g.expr(it.expr)
|
||||
// if it.expr_type.nr_muls() > 0 {
|
||||
if it.expr_type.is_ptr() {
|
||||
g.write('->')
|
||||
} else {
|
||||
|
@ -1650,7 +1657,7 @@ fn (mut g Gen) ident(node ast.Ident) {
|
|||
// `println(x)` => `println(*(int*)x.data)`
|
||||
if ident_var.is_optional && !(g.is_assign_lhs && g.right_is_opt) {
|
||||
g.write('/*opt*/')
|
||||
styp := g.base_typ(ident_var.typ)
|
||||
styp := g.base_type(ident_var.typ)
|
||||
g.write('(*($styp*)${name}.data)')
|
||||
return
|
||||
}
|
||||
|
@ -1908,7 +1915,7 @@ fn (mut g Gen) return_statement(node ast.Return) {
|
|||
// mr_info := typ_sym.info as table.MultiReturn
|
||||
mut styp := ''
|
||||
if fn_return_is_optional { // && !node.types[0].flag_is(.optional) && node.types[0] !=
|
||||
styp = g.base_typ(g.fn_decl.return_type)
|
||||
styp = g.base_type(g.fn_decl.return_type)
|
||||
g.write('opt_ok(&($styp/*X*/[]) { ')
|
||||
} else {
|
||||
styp = g.typ(g.fn_decl.return_type)
|
||||
|
@ -1947,7 +1954,7 @@ fn (mut g Gen) return_statement(node ast.Return) {
|
|||
else {}
|
||||
}
|
||||
if !is_none && !is_error {
|
||||
styp := g.base_typ(g.fn_decl.return_type)
|
||||
styp := g.base_type(g.fn_decl.return_type)
|
||||
g.write('/*:)$return_sym.name*/opt_ok(&($styp[]) { ')
|
||||
if !g.fn_decl.return_type.is_ptr() && node.types[0].is_ptr() {
|
||||
// Automatic Dereference for optional
|
||||
|
@ -2277,13 +2284,6 @@ fn (mut g Gen) write_types(types []table.TypeSymbol) {
|
|||
g.definitions.writeln('typedef $fixed $styp [$len];')
|
||||
// }
|
||||
}
|
||||
table.Interface {
|
||||
g.definitions.writeln('//interface')
|
||||
g.definitions.writeln('typedef struct {')
|
||||
g.definitions.writeln('\tvoid* _object;')
|
||||
g.definitions.writeln('\tint _interface_idx;')
|
||||
g.definitions.writeln('} $name;')
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
|
@ -2608,7 +2608,7 @@ fn (mut g Gen) insert_before(s string) {
|
|||
// to access its fields (`.ok`, `.error` etc)
|
||||
// `os.cp(...)` => `Option bool tmp = os__cp(...); if (!tmp.ok) { ... }`
|
||||
fn (mut g Gen) or_block(var_name string, stmts []ast.Stmt, return_type table.Type) {
|
||||
mr_styp := g.base_typ(return_type)
|
||||
mr_styp := g.base_type(return_type)
|
||||
g.writeln(';') // or')
|
||||
g.writeln('if (!${var_name}.ok) {')
|
||||
g.writeln('\tstring err = ${var_name}.v_error;')
|
||||
|
@ -3375,59 +3375,100 @@ fn (g Gen) type_to_fmt(typ table.Type) string {
|
|||
}
|
||||
|
||||
// Generates interface table and interface indexes
|
||||
// TODO remove all `replace()`
|
||||
fn (v &Gen) interface_table() string {
|
||||
fn (g &Gen) interface_table() string {
|
||||
mut sb := strings.new_builder(100)
|
||||
for _, t in v.table.types {
|
||||
if t.kind != .interface_ {
|
||||
for ityp in g.table.types {
|
||||
if ityp.kind != .interface_ {
|
||||
continue
|
||||
}
|
||||
info := t.info as table.Interface
|
||||
inter_info := ityp.info as table.Interface
|
||||
if inter_info.types.len == 0 {
|
||||
continue
|
||||
}
|
||||
sb.writeln('// NR interfaced types= $inter_info.types.len')
|
||||
// interface_name is for example Speaker
|
||||
interface_name := t.name.replace('.', '__')
|
||||
mut methods := ''
|
||||
mut generated_casting_functions := ''
|
||||
sb.writeln('// NR gen_types= $info.gen_types.len')
|
||||
for i, gen_type in info.gen_types {
|
||||
// ptr_ctype can be for example Cat OR Cat_ptr:
|
||||
ptr_ctype := gen_type.replace('*', '_ptr').replace('.', '__')
|
||||
interface_name := c_name(ityp.name)
|
||||
// generate a struct that references interface methods
|
||||
methods_struct_name := 'struct _${interface_name}_interface_methods'
|
||||
mut methods_typ_def := strings.new_builder(100)
|
||||
mut methods_struct_def := strings.new_builder(100)
|
||||
methods_struct_def.writeln('$methods_struct_name {')
|
||||
for method in ityp.methods {
|
||||
typ_name := '_${interface_name}_${method.name}_fn'
|
||||
ret_styp := g.typ(method.return_type)
|
||||
methods_typ_def.write('typedef $ret_styp (*$typ_name)(void* _')
|
||||
// the first param is the receiver, it's handled by `void*` above
|
||||
for i in 1 .. method.args.len {
|
||||
arg := method.args[i]
|
||||
methods_typ_def.write(', ${g.typ(arg.typ)} $arg.name')
|
||||
}
|
||||
// TODO g.fn_args(method.args[1..], method.is_variadic)
|
||||
methods_typ_def.writeln(');')
|
||||
methods_struct_def.writeln('\t$typ_name ${c_name(method.name)};')
|
||||
}
|
||||
methods_struct_def.writeln('};')
|
||||
// generate an array of the interface methods for the structs using the interface
|
||||
// as well as case functions from the struct to the interface
|
||||
mut methods_struct := strings.new_builder(100)
|
||||
methods_struct.writeln('$methods_struct_name ${interface_name}_name_table[$inter_info.types.len] = {')
|
||||
mut cast_functions := strings.new_builder(100)
|
||||
cast_functions.write('// Casting functions for interface "${interface_name}"')
|
||||
mut methods_wrapper := strings.new_builder(100)
|
||||
methods_wrapper.writeln('// Methods wrapper for interface "${interface_name}"')
|
||||
for i, st in inter_info.types {
|
||||
// cctype is the Cleaned Concrete Type name, *without ptr*,
|
||||
// i.e. cctype is always just Cat, not Cat_ptr:
|
||||
cctype := gen_type.replace('*', '').replace('.', '__')
|
||||
cctype := g.cc_type(st)
|
||||
// Speaker_Cat_index = 0
|
||||
interface_index_name := '_${interface_name}_${ptr_ctype}_index'
|
||||
generated_casting_functions += '
|
||||
${interface_name} I_${cctype}_to_${interface_name}(${cctype}* x) {
|
||||
return (${interface_name}){
|
||||
._object = (void*) memdup(x, sizeof(${cctype})),
|
||||
._interface_idx = ${interface_index_name} };
|
||||
}
|
||||
'
|
||||
methods += '{\n'
|
||||
for j, method in t.methods {
|
||||
// Cat_speak
|
||||
methods += ' (void*) ${cctype}_${method.name}'
|
||||
if j < t.methods.len - 1 {
|
||||
methods += ', \n'
|
||||
interface_index_name := '_${interface_name}_${cctype}_index'
|
||||
cast_functions.writeln('
|
||||
_Interface I_${cctype}_to_Interface(${cctype}* x) {
|
||||
return (_Interface) {
|
||||
._object = (void*) memdup(x, sizeof(${cctype})),
|
||||
._interface_idx = ${interface_index_name}
|
||||
};
|
||||
}')
|
||||
methods_struct.writeln('\t{')
|
||||
for method in ityp.methods {
|
||||
// .speak = Cat_speak
|
||||
mut method_call := '${cctype}_${method.name}'
|
||||
if !method.args[0].typ.is_ptr() {
|
||||
// inline void Cat_speak_method_wrapper(Cat c) { return Cat_speak(*c); }
|
||||
methods_wrapper.write('static inline ${g.typ(method.return_type)}')
|
||||
methods_wrapper.write(' ${method_call}_method_wrapper(')
|
||||
methods_wrapper.write('${cctype}* ${method.args[0].name}')
|
||||
// TODO g.fn_args
|
||||
for j in 1 .. method.args.len {
|
||||
arg := method.args[j]
|
||||
methods_wrapper.write(', ${g.typ(arg.typ)} $arg.name')
|
||||
}
|
||||
methods_wrapper.writeln(') {')
|
||||
methods_wrapper.write('\t')
|
||||
if method.return_type != table.void_type {
|
||||
methods_wrapper.write('return ')
|
||||
}
|
||||
methods_wrapper.write('${method_call}(*${method.args[0].name}')
|
||||
for j in 1 .. method.args.len {
|
||||
methods_wrapper.write(', ${method.args[j].name}')
|
||||
}
|
||||
methods_wrapper.writeln(');')
|
||||
methods_wrapper.writeln('}')
|
||||
// .speak = Cat_speak_method_wrapper
|
||||
method_call += '_method_wrapper'
|
||||
}
|
||||
methods_struct.writeln('\t\t.${c_name(method.name)} = $method_call,')
|
||||
}
|
||||
methods += '\n},\n\n'
|
||||
methods_struct.writeln('\t},')
|
||||
sb.writeln('int ${interface_index_name} = $i;')
|
||||
}
|
||||
if info.gen_types.len > 0 {
|
||||
// methods = '{TCCSKIP(0)}'
|
||||
// }
|
||||
sb.writeln('void* (* ${interface_name}_name_table[][$t.methods.len]) = ' + '{ \n $methods \n }; ')
|
||||
} else {
|
||||
// The line below is needed so that C compilation succeeds,
|
||||
// even if no interface methods are called.
|
||||
// See https://github.com/zenith391/vgtk3/issues/7
|
||||
sb.writeln('void* (* ${interface_name}_name_table[][1]) = ' + '{ {NULL} }; ')
|
||||
}
|
||||
if generated_casting_functions.len > 0 {
|
||||
sb.writeln('// Casting functions for interface "${interface_name}" :')
|
||||
sb.writeln(generated_casting_functions)
|
||||
}
|
||||
methods_struct.writeln('};')
|
||||
// add line return after interface index declarations
|
||||
sb.writeln('')
|
||||
sb.writeln(methods_wrapper.str())
|
||||
sb.writeln(methods_typ_def.str())
|
||||
sb.writeln(methods_struct_def.str())
|
||||
sb.writeln(methods_struct.str())
|
||||
sb.writeln(cast_functions.str())
|
||||
}
|
||||
return sb.str()
|
||||
}
|
||||
|
@ -3471,11 +3512,6 @@ fn (mut g Gen) array_init(it ast.ArrayInit) {
|
|||
if it.is_interface {
|
||||
// sym := g.table.get_type_symbol(it.interface_types[i])
|
||||
// isym := g.table.get_type_symbol(it.interface_type)
|
||||
/*
|
||||
interface_styp := g.typ(it.interface_type)
|
||||
styp := g.typ(it.interface_types[i])
|
||||
g.write('I_${styp}_to_${interface_styp}(')
|
||||
*/
|
||||
g.interface_call(it.interface_types[i], it.interface_type)
|
||||
}
|
||||
g.expr(expr)
|
||||
|
@ -3490,9 +3526,9 @@ fn (mut g Gen) array_init(it ast.ArrayInit) {
|
|||
// `ui.foo(button)` =>
|
||||
// `ui__foo(I_ui__Button_to_ui__Widget(` ...
|
||||
fn (g &Gen) interface_call(typ, interface_type table.Type) {
|
||||
interface_styp := g.typ(interface_type).replace('*', '')
|
||||
styp := g.typ(typ).replace('*', '')
|
||||
g.write('I_${styp}_to_${interface_styp}(')
|
||||
interface_styp := g.cc_type(interface_type)
|
||||
styp := g.cc_type(typ)
|
||||
g.write('/* $interface_styp */ I_${styp}_to_Interface(')
|
||||
if !typ.is_ptr() {
|
||||
g.write('&')
|
||||
}
|
||||
|
|
|
@ -50,8 +50,7 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
|
|||
}
|
||||
} else {
|
||||
mut name := it.name
|
||||
c := name[0]
|
||||
if c in [`+`, `-`, `*`, `/`, `%`] {
|
||||
if name[0] in [`+`, `-`, `*`, `/`, `%`] {
|
||||
name = util.replace_op(name)
|
||||
}
|
||||
if it.is_method {
|
||||
|
@ -279,28 +278,20 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
|||
if node.left_type == 0 {
|
||||
verror('method receiver type is 0, this means there are some uchecked exprs')
|
||||
}
|
||||
mut receiver_type_name := g.cc_type(node.receiver_type)
|
||||
typ_sym := g.table.get_type_symbol(node.receiver_type)
|
||||
// mut receiver_type_name := g.typ(node.receiver_type)
|
||||
mut receiver_type_name := typ_sym.name.replace('.', '__') // TODO g.typ() ?
|
||||
if typ_sym.kind == .interface_ {
|
||||
// Find the index of the method
|
||||
mut idx := -1
|
||||
for i, method in typ_sym.methods {
|
||||
if method.name == node.name {
|
||||
idx = i
|
||||
}
|
||||
}
|
||||
if idx == -1 {
|
||||
verror('method_call: cannot find interface method index')
|
||||
}
|
||||
sret_type := g.typ(node.return_type)
|
||||
g.writeln('// interface method call')
|
||||
// `((void (*)())(Speaker_name_table[s._interface_idx][1]))(s._object);`
|
||||
g.write('(($sret_type (*)())(${receiver_type_name}_name_table[')
|
||||
// Speaker_name_table[s._interface_idx].speak(s._object)
|
||||
g.write('${c_name(receiver_type_name)}_name_table[')
|
||||
g.expr(node.left)
|
||||
g.write('._interface_idx][$idx]))(')
|
||||
g.write('._interface_idx].${node.name}(')
|
||||
g.expr(node.left)
|
||||
g.write('._object)')
|
||||
g.write('._object')
|
||||
if node.args.len > 0 {
|
||||
g.write(', ')
|
||||
g.call_args(node.args, node.expected_arg_types)
|
||||
}
|
||||
g.write(')')
|
||||
return
|
||||
}
|
||||
if typ_sym.kind == .array && node.name == 'map' {
|
||||
|
@ -509,9 +500,8 @@ fn (mut g Gen) call_args(args []ast.CallArg, expected_types []table.Type) {
|
|||
is_variadic := expected_types.len > 0 && expected_types[expected_types.len - 1].flag_is(.variadic)
|
||||
is_forwarding_varg := args.len > 0 && args[args.len - 1].typ.flag_is(.variadic)
|
||||
gen_vargs := is_variadic && !is_forwarding_varg
|
||||
mut arg_no := 0
|
||||
for arg in args {
|
||||
if gen_vargs && arg_no == expected_types.len - 1 {
|
||||
for i, arg in args {
|
||||
if gen_vargs && i == expected_types.len - 1 {
|
||||
break
|
||||
}
|
||||
// if arg.typ.name.starts_with('I') {
|
||||
|
@ -519,42 +509,42 @@ fn (mut g Gen) call_args(args []ast.CallArg, expected_types []table.Type) {
|
|||
mut is_interface := false
|
||||
// some c fn definitions dont have args (cfns.v) or are not updated in checker
|
||||
// when these are fixed we wont need this check
|
||||
if arg_no < expected_types.len {
|
||||
if expected_types[arg_no] != 0 {
|
||||
if i < expected_types.len {
|
||||
if expected_types[i] != 0 {
|
||||
// Cast a type to interface
|
||||
// `foo(dog)` => `foo(I_Dog_to_Animal(dog))`
|
||||
exp_sym := g.table.get_type_symbol(expected_types[arg_no])
|
||||
exp_sym := g.table.get_type_symbol(expected_types[i])
|
||||
// exp_styp := g.typ(expected_types[arg_no]) // g.table.get_type_symbol(expected_types[arg_no])
|
||||
// styp := g.typ(arg.typ) // g.table.get_type_symbol(arg.typ)
|
||||
if exp_sym.kind == .interface_ {
|
||||
g.interface_call(arg.typ, expected_types[arg_no])
|
||||
g.interface_call(arg.typ, expected_types[i])
|
||||
// g.write('/*Z*/I_${styp}_to_${exp_styp}(')
|
||||
is_interface = true
|
||||
}
|
||||
}
|
||||
g.ref_or_deref_arg(arg, expected_types[arg_no])
|
||||
g.ref_or_deref_arg(arg, expected_types[i])
|
||||
} else {
|
||||
g.expr(arg.expr)
|
||||
}
|
||||
if is_interface {
|
||||
g.write(')')
|
||||
}
|
||||
if arg_no < args.len - 1 || gen_vargs {
|
||||
if i < args.len - 1 || gen_vargs {
|
||||
g.write(', ')
|
||||
}
|
||||
arg_no++
|
||||
}
|
||||
arg_nr := expected_types.len - 1
|
||||
if gen_vargs {
|
||||
varg_type := expected_types[expected_types.len - 1]
|
||||
struct_name := 'varg_' + g.typ(varg_type).replace('*', '_ptr')
|
||||
variadic_count := args.len - arg_no
|
||||
variadic_count := args.len - arg_nr
|
||||
varg_type_str := int(varg_type).str()
|
||||
if variadic_count > g.variadic_args[varg_type_str] {
|
||||
g.variadic_args[varg_type_str] = variadic_count
|
||||
}
|
||||
g.write('($struct_name){.len=$variadic_count,.args={')
|
||||
if variadic_count > 0 {
|
||||
for j in arg_no .. args.len {
|
||||
for j in arg_nr .. args.len {
|
||||
g.ref_or_deref_arg(args[j], varg_type)
|
||||
if j < args.len - 1 {
|
||||
g.write(', ')
|
||||
|
|
|
@ -135,7 +135,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
|
|||
fields << table.Field{
|
||||
name: field_name
|
||||
typ: typ
|
||||
default_expr: ast.ex2fe( default_expr )
|
||||
default_expr: ast.ex2fe(default_expr)
|
||||
has_default_expr: has_default_expr
|
||||
is_pub: is_field_pub
|
||||
is_mut: is_field_mut
|
||||
|
@ -265,8 +265,7 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
|
|||
kind: .interface_
|
||||
name: interface_name
|
||||
info: table.Interface{
|
||||
gen_types: []
|
||||
foo: 'foo'
|
||||
types: []
|
||||
}
|
||||
}
|
||||
typ := table.new_type(p.table.register_type_symbol(t))
|
||||
|
|
|
@ -180,23 +180,23 @@ pub const (
|
|||
)
|
||||
|
||||
pub const (
|
||||
integer_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx,
|
||||
integer_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx,
|
||||
u16_type_idx,
|
||||
u32_type_idx,
|
||||
u64_type_idx
|
||||
]
|
||||
signed_integer_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx]
|
||||
signed_integer_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx]
|
||||
unsigned_integer_type_idxs = [byte_type_idx, u16_type_idx, u32_type_idx, u64_type_idx]
|
||||
float_type_idxs = [f32_type_idx, f64_type_idx]
|
||||
number_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx,
|
||||
float_type_idxs = [f32_type_idx, f64_type_idx]
|
||||
number_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx,
|
||||
u16_type_idx,
|
||||
u32_type_idx,
|
||||
u64_type_idx,
|
||||
f32_type_idx,
|
||||
f64_type_idx
|
||||
]
|
||||
pointer_type_idxs = [voidptr_type_idx, byteptr_type_idx, charptr_type_idx]
|
||||
string_type_idxs = [string_type_idx, ustring_type_idx]
|
||||
pointer_type_idxs = [voidptr_type_idx, byteptr_type_idx, charptr_type_idx]
|
||||
string_type_idxs = [string_type_idx, ustring_type_idx]
|
||||
)
|
||||
|
||||
pub const (
|
||||
|
@ -530,8 +530,7 @@ pub mut:
|
|||
|
||||
pub struct Interface {
|
||||
mut:
|
||||
gen_types []string
|
||||
foo string
|
||||
types []Type
|
||||
}
|
||||
|
||||
pub struct Enum {
|
||||
|
@ -547,7 +546,7 @@ pub:
|
|||
// NB: FExpr here is a actually an ast.Expr .
|
||||
// It should always be used by casting to ast.Expr, using ast.fe2ex()/ast.ex2fe()
|
||||
// That hack is needed to break an import cycle between v.ast and v.table .
|
||||
type FExpr = voidptr | byteptr
|
||||
type FExpr = byteptr | voidptr
|
||||
|
||||
pub struct Field {
|
||||
pub:
|
||||
|
@ -634,6 +633,22 @@ pub fn (table &Table) type_to_str(t Type) string {
|
|||
return res
|
||||
}
|
||||
|
||||
pub fn (t &TypeSymbol) has_method(name string) bool {
|
||||
t.find_method(name) or {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
pub fn (t &TypeSymbol) find_method(name string) ?Fn {
|
||||
for method in t.methods {
|
||||
if method.name == name {
|
||||
return method
|
||||
}
|
||||
}
|
||||
return none
|
||||
}
|
||||
|
||||
pub fn (s Struct) find_field(name string) ?Field {
|
||||
for field in s.fields {
|
||||
if field.name == name {
|
||||
|
|
|
@ -96,41 +96,6 @@ pub fn (mut t TypeSymbol) register_method(new_fn Fn) {
|
|||
t.methods << new_fn
|
||||
}
|
||||
|
||||
pub fn (t &TypeSymbol) has_method(name string) bool {
|
||||
t.find_method(name) or {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
pub fn (t &TypeSymbol) find_method(name string) ?Fn {
|
||||
for method in t.methods {
|
||||
if method.name == name {
|
||||
return method
|
||||
}
|
||||
}
|
||||
return none
|
||||
}
|
||||
|
||||
pub fn (s &TypeSymbol) has_field(name string) bool {
|
||||
s.find_field(name) or {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
pub fn (s &TypeSymbol) find_field(name string) ?Field {
|
||||
match s.info {
|
||||
Struct { for field in it.fields {
|
||||
if field.name == name {
|
||||
return field
|
||||
}
|
||||
} }
|
||||
else {}
|
||||
}
|
||||
return none
|
||||
}
|
||||
|
||||
pub fn (t &Table) type_has_method(s &TypeSymbol, name string) bool {
|
||||
// println('type_has_method($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx')
|
||||
if _ := t.type_find_method(s, name) {
|
||||
|
@ -168,8 +133,11 @@ pub fn (t &Table) struct_find_field(s &TypeSymbol, name string) ?Field {
|
|||
// println('struct_find_field($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx')
|
||||
mut ts := s
|
||||
for {
|
||||
if field := ts.find_field(name) {
|
||||
return field
|
||||
if ts.info is Struct {
|
||||
struct_info := ts.info as Struct
|
||||
if field := struct_info.find_field(name) {
|
||||
return field
|
||||
}
|
||||
}
|
||||
if ts.parent_idx == 0 {
|
||||
break
|
||||
|
@ -179,6 +147,15 @@ pub fn (t &Table) struct_find_field(s &TypeSymbol, name string) ?Field {
|
|||
return none
|
||||
}
|
||||
|
||||
pub fn (t &Table) interface_add_type(inter mut Interface, typ Type) bool {
|
||||
// TODO Verify `typ` implements `inter`
|
||||
typ_sym := t.get_type_symbol(typ)
|
||||
if typ !in inter.types && typ_sym.kind != .interface_ {
|
||||
inter.types << typ
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (t &Table) find_type_idx(name string) int {
|
||||
return t.type_idxs[name]
|
||||
|
@ -491,15 +468,7 @@ pub fn (t &Table) check(got, expected Type) bool {
|
|||
// Handle expected interface
|
||||
if exp_type_sym.kind == .interface_ {
|
||||
mut info := exp_type_sym.info as Interface
|
||||
// println('gen_types before')
|
||||
// println(info.gen_types)
|
||||
if got_type_sym.name !in info.gen_types && got_type_sym.kind != .interface_ {
|
||||
// TODO `got` should never be an interface?
|
||||
info.gen_types << got_type_sym.name
|
||||
}
|
||||
// println('adding gen_type $got_type_sym.name')
|
||||
// println(info.gen_types)
|
||||
return true
|
||||
return t.interface_add_type(info, got)
|
||||
}
|
||||
// Handle expected interface array
|
||||
/*
|
||||
|
|
|
@ -11,15 +11,18 @@ fn (d Cat) name() string {
|
|||
return 'Cat'
|
||||
}
|
||||
|
||||
fn (d Cat) speak() {
|
||||
fn (d Cat) speak(s string) {
|
||||
assert s == 'Hi !'
|
||||
println('meow')
|
||||
}
|
||||
|
||||
fn (d Dog) speak() {
|
||||
fn (d Dog) speak(s string) {
|
||||
assert s == 'Hi !'
|
||||
println('woof')
|
||||
}
|
||||
|
||||
fn (d Dog) name() string {
|
||||
assert d.breed == 'Labrador Retriever'
|
||||
return 'Dog'
|
||||
}
|
||||
|
||||
|
@ -31,7 +34,7 @@ fn test_todo() {
|
|||
|
||||
|
||||
fn perform_speak(s Speaker) {
|
||||
s.speak()
|
||||
s.speak('Hi !')
|
||||
assert true
|
||||
name := s.name()
|
||||
assert name == 'Dog' || name == 'Cat'
|
||||
|
@ -42,7 +45,7 @@ fn perform_speak(s Speaker) {
|
|||
}
|
||||
|
||||
fn test_perform_speak() {
|
||||
dog := Dog{}
|
||||
dog := Dog{breed: 'Labrador Retriever'}
|
||||
perform_speak(dog)
|
||||
cat := Cat{}
|
||||
perform_speak(cat)
|
||||
|
@ -88,7 +91,7 @@ struct Foo {
|
|||
|
||||
interface Speaker {
|
||||
name() string
|
||||
speak()
|
||||
speak(s string)
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue