-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathboundmethod.cpp
More file actions
103 lines (93 loc) · 2.95 KB
/
Copy pathboundmethod.cpp
File metadata and controls
103 lines (93 loc) · 2.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include "boundmethod.h"
#include "../format.h"
#include "class.h"
#include "errors.h"
#include "file.h"
#include "function.h"
Value next_boundmethod_str(const Value *args, int numargs) {
(void)numargs;
EXPECT(boundmethod, "str(_)", 1, File);
File *f = args[1].toFile();
if(!f->stream->isWritable()) {
return FileError::sete("File is not writable!");
}
BoundMethod *b = args[0].toBoundMethod();
switch(b->type) {
case BoundMethod::CLASS_BOUND:
f->writableStream()->fmt("<class bound method {}.{}@{}>",
b->binder.toClass()->name, b->func->name,
b->func->arity);
return ValueTrue;
default:
f->writableStream()->fmt("<object bound method {}.{}@{}>",
b->binder.getClass()->name, b->func->name,
b->func->arity);
return ValueTrue;
}
}
Value next_boundmethod_fn(const Value *args, int numargs) {
(void)numargs;
return Value(args[0].toBoundMethod()->func);
}
Value next_boundmethod_binder(const Value *args, int numargs) {
(void)numargs;
return Value(args[0].toBoundMethod()->binder);
}
void BoundMethod::init(Class *BoundMethodClass) {
BoundMethodClass->add_builtin_fn("get_fn()", 0, next_boundmethod_fn);
BoundMethodClass->add_builtin_fn("get_binder()", 0,
next_boundmethod_binder);
BoundMethodClass->add_builtin_fn_nest("str(_)", 1, next_boundmethod_str);
}
BoundMethod::Status BoundMethod::verify(const Value *args, int arity) {
// for object bound functions, this is fine
int effective_arity = func->arity;
// if the function is class bound, the first argument
// must be an instance of the same class, unless the
// function is static
if(type == CLASS_BOUND)
effective_arity += 1 - func->isStatic();
// for a vararg function, at least arity number of arguments
// must be present.
if((func->isVarArg() && arity < effective_arity) ||
(!func->isVarArg() && arity != effective_arity)) {
RuntimeError::sete("Invalid arity given to the bound function!");
return MISMATCHED_ARITY;
}
// if the function is class bound, verify the first
// argument
if(type == CLASS_BOUND) {
Class *cls = binder.toClass();
if(args[0].getClass() != cls) {
Error::setTypeError(cls->name, func->name, cls->name, args[0], 1);
return INVALID_CLASS_INSTANCE;
}
}
return OK;
}
BoundMethod *BoundMethod::from(Function *f, Class *c) {
BoundMethod *b = Gc::alloc<BoundMethod>();
b->binder = Value(c);
b->func = f;
b->type = CLASS_BOUND;
return b;
}
BoundMethod *BoundMethod::from(Function *f, Object *o, Type t) {
BoundMethod *b = Gc::alloc<BoundMethod>();
b->binder = Value(o);
b->func = f;
b->type = t;
return b;
}
BoundMethod *BoundMethod::from(Function *f, Value v, Type t) {
BoundMethod *b = Gc::alloc<BoundMethod>();
b->binder = v;
b->func = f;
b->type = t;
return b;
}
#ifdef DEBUG_GC
const String *BoundMethod::gc_repr() {
return func->name;
}
#endif