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