mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
rewrite interfaces
This commit is contained in:
@ -12,8 +12,7 @@ const (
|
||||
MaxLocalVars = 50
|
||||
)
|
||||
|
||||
pub
|
||||
struct Fn {
|
||||
pub struct Fn {
|
||||
// addr int
|
||||
pub:
|
||||
mut:
|
||||
@ -560,7 +559,7 @@ fn (p mut Parser) skip_fn_body() {
|
||||
}
|
||||
}
|
||||
|
||||
fn (p Parser) get_linkage_prefix() string {
|
||||
fn (p &Parser) get_linkage_prefix() string {
|
||||
return if p.pref.ccompiler == 'msvc' && p.attr == 'live' && p.pref.is_so {
|
||||
'__declspec(dllexport) '
|
||||
} else if p.attr == 'inline' {
|
||||
@ -718,6 +717,27 @@ fn (p mut Parser) fn_call(f mut Fn, method_ph int, receiver_var, receiver_type s
|
||||
// we need to preappend "method(receiver, ...)"
|
||||
if f.is_method {
|
||||
receiver := f.args.first()
|
||||
if receiver.typ.ends_with('er') {
|
||||
// I absolutely love this syntax
|
||||
// `s.speak()` =>
|
||||
// `((void (*)())(Speaker_name_table[s._interface_idx][1]))(s._object);
|
||||
// where `1` refers to the speak method, since it's the second method
|
||||
// of the Speaker interface
|
||||
t := p.table.find_type(receiver.typ)
|
||||
if t.cat == .interface_ {
|
||||
// Find the index of the method
|
||||
mut idx := 0
|
||||
for i, method in t.methods {
|
||||
if method.name == f.name {
|
||||
idx = i
|
||||
}
|
||||
}
|
||||
p.cgen.resetln('')
|
||||
var := p.expr_var.name
|
||||
iname := f.args[0].typ // Speaker
|
||||
p.gen('((void (*)())(${iname}_name_table[${var}._interface_idx][$idx]))(${var}._object)')
|
||||
}
|
||||
}
|
||||
//println('r=$receiver.typ RT=$receiver_type')
|
||||
if receiver.is_mut && !p.expr_var.is_mut {
|
||||
//println('$method_call recv=$receiver.name recv_mut=$receiver.is_mut')
|
||||
@ -747,7 +767,9 @@ fn (p mut Parser) fn_call(f mut Fn, method_ph int, receiver_var, receiver_type s
|
||||
// println('calling inst $f.name: $p.cgen.cur_line')
|
||||
}
|
||||
|
||||
p.gen(')')
|
||||
//if !is_interface {
|
||||
p.gen(')')
|
||||
//}
|
||||
p.calling_c = false
|
||||
if is_comptime_define {
|
||||
p.cgen.nogen = false
|
||||
@ -757,16 +779,16 @@ fn (p mut Parser) fn_call(f mut Fn, method_ph int, receiver_var, receiver_type s
|
||||
}
|
||||
|
||||
// for declaration
|
||||
// return an updated Fn object with args[] field set
|
||||
// update the Fn object's args[]
|
||||
fn (p mut Parser) fn_args(f mut Fn) {
|
||||
p.check(.lpar)
|
||||
defer { p.check(.rpar) }
|
||||
if f.is_interface {
|
||||
int_arg := Var {
|
||||
interface_arg := Var {
|
||||
typ: f.receiver_typ
|
||||
token_idx: p.cur_tok_index()
|
||||
}
|
||||
f.args << int_arg
|
||||
f.args << interface_arg
|
||||
}
|
||||
// `(int, string, int)`
|
||||
// Just register fn arg types
|
||||
@ -829,7 +851,7 @@ fn (p mut Parser) fn_args(f mut Fn) {
|
||||
p.check_and_register_used_imported_type(typ)
|
||||
if is_mut && is_primitive_type(typ) {
|
||||
p.error('mutable arguments are only allowed for arrays, maps, and structs.' +
|
||||
'\nreturn values instead: `foo(n mut int)` => `foo(n int) int`')
|
||||
'\nreturn values instead: `fn foo(n mut int) {` => `fn foo(n int) int {`')
|
||||
}
|
||||
for name in names {
|
||||
if is_mut {
|
||||
@ -916,8 +938,7 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
|
||||
ph := p.cgen.add_placeholder()
|
||||
// `)` here means that not enough args were provided
|
||||
if p.tok == .rpar {
|
||||
str_args := f.str_args(p.table)// TODO this is C args
|
||||
p.error('not enough arguments in call to `$f.name ($str_args)`')
|
||||
p.error('not enough arguments in call to `${f.str_for_error()}`')
|
||||
}
|
||||
// If `arg` is mutable, the caller needs to provide `mut`:
|
||||
// `mut numbers := [1,2,3]; reverse(mut numbers);`
|
||||
@ -951,6 +972,21 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
|
||||
p.gen('/*YY f=$f.name arg=$arg.name is_moved=$arg.is_moved*/string_clone(')
|
||||
}
|
||||
mut typ := p.bool_expression()
|
||||
// Register an interface type usage:
|
||||
// fn run(r Animal) { ... }
|
||||
// `run(dog)` adds `Dog` to the `Animal` interface.
|
||||
// This is needed to generate an interface table.
|
||||
if arg.typ.ends_with('er') {
|
||||
t := p.table.find_type(arg.typ)
|
||||
if t.cat == .interface_ {
|
||||
// perform((Speaker) { ._object = &dog,
|
||||
// _interface_idx = _Speaker_Dog_index })
|
||||
p.cgen.set_placeholder(ph, '($arg.typ) { ._object = &')
|
||||
p.gen(', ._interface_idx = _${arg.typ}_${typ}_index} /* i. arg*/')
|
||||
p.table.add_gen_type(arg.typ, typ)
|
||||
}
|
||||
}
|
||||
|
||||
if clone {
|
||||
p.gen(')')
|
||||
}
|
||||
@ -1077,19 +1113,19 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
|
||||
}
|
||||
else if is_interface {
|
||||
if !got_ptr {
|
||||
p.cgen.set_placeholder(ph, '&')
|
||||
//p.cgen.set_placeholder(ph, '&')
|
||||
}
|
||||
// Pass all interface methods
|
||||
interface_type := p.table.find_type(arg.typ)
|
||||
for method in interface_type.methods {
|
||||
p.gen(', ${typ}_${method.name} ')
|
||||
}
|
||||
//interface_type := p.table.find_type(arg.typ)
|
||||
//for method in interface_type.methods {
|
||||
//p.gen(', ${typ}_${method.name} ')
|
||||
//}
|
||||
}
|
||||
// Check for commas
|
||||
if i < f.args.len - 1 {
|
||||
// Handle 0 args passed to varargs
|
||||
if p.tok != .comma && !f.is_variadic {
|
||||
p.error('wrong number of arguments for $i,$arg.name fn `$f.name`: expected $f.args.len, but got less')
|
||||
p.error('wrong number of arguments in call to `${f.str_for_error()}`')
|
||||
}
|
||||
if p.tok == .comma && (!f.is_variadic || (f.is_variadic && i < f.args.len-2 )) {
|
||||
p.check(.comma)
|
||||
@ -1103,7 +1139,7 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
|
||||
saved_args << varg_type
|
||||
}
|
||||
if p.tok == .comma {
|
||||
p.error('wrong number of arguments for fn `$f.name`: expected $f.args.len, but got more')
|
||||
p.error('wrong number of arguments in call to `${f.str_for_error()}`')
|
||||
}
|
||||
p.check(.rpar)
|
||||
if f.is_generic {
|
||||
@ -1223,8 +1259,8 @@ fn (p mut Parser) replace_type_params(f &Fn, ti TypeInst) []string {
|
||||
fn (p mut Parser) register_vargs_stuct(typ string, len int) string {
|
||||
vargs_struct := 'varg_$typ'
|
||||
varg_type := Type{
|
||||
cat: .struct_,
|
||||
name: vargs_struct,
|
||||
cat: .struct_
|
||||
name: vargs_struct
|
||||
mod: p.mod
|
||||
}
|
||||
mut varg_len := len
|
||||
@ -1462,6 +1498,7 @@ fn (f &Fn) str_args(table &Table) string {
|
||||
// to all methods:
|
||||
// fn handle(r Runner) { =>
|
||||
// void handle(void *r, void (*Runner_run)(void*)) {
|
||||
/*
|
||||
if table.is_interface(arg.typ) {
|
||||
// First the object (same name as the interface argument)
|
||||
s += ' void* $arg.name'
|
||||
@ -1477,7 +1514,8 @@ fn (f &Fn) str_args(table &Table) string {
|
||||
s += ')'
|
||||
}
|
||||
}
|
||||
else if arg.typ.starts_with('varg_') {
|
||||
*/
|
||||
if arg.typ.starts_with('varg_') {
|
||||
s += '$arg.typ *$arg.name'
|
||||
}
|
||||
else {
|
||||
@ -1519,11 +1557,31 @@ fn (fns []Fn) contains(f Fn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
pub fn (f Fn) v_fn_module() string {
|
||||
pub fn (f &Fn) v_fn_module() string {
|
||||
return f.mod
|
||||
}
|
||||
|
||||
pub fn (f Fn) v_fn_name() string {
|
||||
pub fn (f &Fn) v_fn_name() string {
|
||||
return f.name.replace('${f.mod}__', '')
|
||||
}
|
||||
|
||||
pub fn (f &Fn) str_for_error() string {
|
||||
// Build the args for the error
|
||||
mut s := ''
|
||||
for i, a in f.args {
|
||||
if i == 0 {
|
||||
if f.is_method {
|
||||
s += a.typ + '.' + f.name + '('
|
||||
continue
|
||||
}
|
||||
s += f.name + '('
|
||||
}
|
||||
s += a.typ
|
||||
if i < f.args.len - 1 {
|
||||
s += ', '
|
||||
}
|
||||
}
|
||||
return s + ')'
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user