allow native functions to be bound as methods with a little work
This commit is contained in:
parent
7dfd853217
commit
430f20566e
8
object.c
8
object.c
@ -99,7 +99,10 @@ void krk_printObject(FILE * f, KrkValue value) {
|
||||
fprintf(f, "<instance of %s>", NAME(AS_INSTANCE(value)->_class));
|
||||
break;
|
||||
case OBJ_BOUND_METHOD:
|
||||
fprintf(f, "<bound <def %s>>", NAME(AS_BOUND_METHOD(value)->method->function));
|
||||
fprintf(f, "<bound <def %s>>", (AS_BOUND_METHOD(value)->method->type == OBJ_CLOSURE) ?
|
||||
NAME(((KrkClosure*)AS_BOUND_METHOD(value)->method)->function) : (
|
||||
(AS_BOUND_METHOD(value)->method->type == OBJ_NATIVE) ? "<native>" : "<unknown>"
|
||||
));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -116,6 +119,7 @@ KrkFunction * krk_newFunction() {
|
||||
KrkNative * krk_newNative(NativeFn function) {
|
||||
KrkNative * native = ALLOCATE_OBJECT(KrkNative, OBJ_NATIVE);
|
||||
native->function = function;
|
||||
native->isMethod = 0;
|
||||
return native;
|
||||
}
|
||||
|
||||
@ -154,7 +158,7 @@ KrkInstance * krk_newInstance(KrkClass * _class) {
|
||||
return instance;
|
||||
}
|
||||
|
||||
KrkBoundMethod * krk_newBoundMethod(KrkValue receiver, KrkClosure * method) {
|
||||
KrkBoundMethod * krk_newBoundMethod(KrkValue receiver, KrkObj * method) {
|
||||
KrkBoundMethod * bound = ALLOCATE_OBJECT(KrkBoundMethod, OBJ_BOUND_METHOD);
|
||||
bound->receiver = receiver;
|
||||
bound->method = method;
|
||||
|
5
object.h
5
object.h
@ -86,13 +86,14 @@ typedef struct {
|
||||
typedef struct {
|
||||
KrkObj obj;
|
||||
KrkValue receiver;
|
||||
KrkClosure * method;
|
||||
KrkObj * method;
|
||||
} KrkBoundMethod;
|
||||
|
||||
typedef KrkValue (*NativeFn)(int argCount, KrkValue* args);
|
||||
typedef struct {
|
||||
KrkObj obj;
|
||||
NativeFn function;
|
||||
int isMethod;
|
||||
} KrkNative;
|
||||
|
||||
static inline int isObjType(KrkValue value, ObjType type) {
|
||||
@ -108,4 +109,4 @@ extern KrkClosure * krk_newClosure(KrkFunction * function);
|
||||
extern KrkUpvalue * krk_newUpvalue(int slot);
|
||||
extern KrkClass * krk_newClass(KrkString * name);
|
||||
extern KrkInstance * krk_newInstance(KrkClass * _class);
|
||||
extern KrkBoundMethod * krk_newBoundMethod(KrkValue receiver, KrkClosure * method);
|
||||
extern KrkBoundMethod * krk_newBoundMethod(KrkValue receiver, KrkObj * method);
|
||||
|
31
vm.c
31
vm.c
@ -221,11 +221,12 @@ static KrkValue krk_expose_list_length(int argc, KrkValue argv[]) {
|
||||
return INTEGER_VAL(list->chunk.constants.count);
|
||||
}
|
||||
|
||||
void krk_runNext(void) {
|
||||
KrkValue krk_runNext(void) {
|
||||
size_t oldExit = vm.exitOnFrame;
|
||||
vm.exitOnFrame = vm.frameCount - 1;
|
||||
run();
|
||||
KrkValue result = run();
|
||||
vm.exitOnFrame = oldExit;
|
||||
return result;
|
||||
}
|
||||
|
||||
KrkInstance * krk_dictCreate(KrkValue * outClass) {
|
||||
@ -337,21 +338,22 @@ static int callValue(KrkValue callee, int argCount) {
|
||||
return call(AS_CLOSURE(callee), argCount);
|
||||
case OBJ_NATIVE: {
|
||||
NativeFn native = AS_NATIVE(callee);
|
||||
KrkValue result = native(argCount, vm.stackTop - argCount);
|
||||
int extraArgs = !!((KrkNative*)AS_OBJECT(callee))->isMethod;
|
||||
KrkValue result = native(argCount + extraArgs, vm.stackTop - argCount - extraArgs);
|
||||
if (vm.stackTop == vm.stack) {
|
||||
/* Runtime error returned from native method */
|
||||
return 0;
|
||||
}
|
||||
vm.stackTop -= argCount + 1;
|
||||
krk_push(result);
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
case OBJ_CLASS: {
|
||||
KrkClass * _class = AS_CLASS(callee);
|
||||
vm.stackTop[-argCount - 1] = OBJECT_VAL(krk_newInstance(_class));
|
||||
KrkValue initializer;
|
||||
if (krk_tableGet(&_class->methods, vm.specialMethodNames[METHOD_INIT], &initializer)) {
|
||||
return call(AS_CLOSURE(initializer), argCount);
|
||||
return callValue(initializer, argCount);
|
||||
} else if (argCount != 0) {
|
||||
krk_runtimeError("Class does not have an __init__ but arguments were passed to initializer: %d\n", argCount);
|
||||
return 0;
|
||||
@ -361,7 +363,7 @@ static int callValue(KrkValue callee, int argCount) {
|
||||
case OBJ_BOUND_METHOD: {
|
||||
KrkBoundMethod * bound = AS_BOUND_METHOD(callee);
|
||||
vm.stackTop[-argCount - 1] = bound->receiver;
|
||||
return call(bound->method, argCount);
|
||||
return callValue(OBJECT_VAL(bound->method), argCount);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
@ -374,7 +376,7 @@ static int callValue(KrkValue callee, int argCount) {
|
||||
static int bindMethod(KrkClass * _class, KrkString * name) {
|
||||
KrkValue method;
|
||||
if (!krk_tableGet(&_class->methods, OBJECT_VAL(name), &method)) return 0;
|
||||
KrkBoundMethod * bound = krk_newBoundMethod(krk_peek(0), AS_CLOSURE(method));
|
||||
KrkBoundMethod * bound = krk_newBoundMethod(krk_peek(0), AS_OBJECT(method));
|
||||
krk_pop();
|
||||
krk_push(OBJECT_VAL(bound));
|
||||
return 1;
|
||||
@ -421,7 +423,7 @@ static void defineMethod(KrkString * name) {
|
||||
void krk_attachNamedObject(KrkTable * table, const char name[], KrkObj * obj) {
|
||||
krk_push(OBJECT_VAL(krk_copyString(name,strlen(name))));
|
||||
krk_push(OBJECT_VAL(obj));
|
||||
krk_tableSet(&vm.globals, vm.stack[0], vm.stack[1]);
|
||||
krk_tableSet(table, vm.stack[0], vm.stack[1]);
|
||||
krk_pop();
|
||||
krk_pop();
|
||||
}
|
||||
@ -604,11 +606,12 @@ static void addObjects() {
|
||||
} else {
|
||||
/* Push the object for self reference */
|
||||
krk_push(_b);
|
||||
call(AS_CLOSURE(method), 0);
|
||||
int previousExitFrame = vm.exitOnFrame;
|
||||
vm.exitOnFrame = vm.frameCount - 1;
|
||||
KrkValue result = run();
|
||||
vm.exitOnFrame = previousExitFrame;
|
||||
KrkValue result;
|
||||
switch (callValue(method, 0)) {
|
||||
case 0: result = NONE_VAL(); break;
|
||||
case 1: result = krk_runNext(); break;
|
||||
case 2: result = krk_pop(); break;
|
||||
}
|
||||
if (!IS_STRING(result)) {
|
||||
krk_runtimeError("__str__ produced something that wasn't a string: %s", krk_typeName(result));
|
||||
return;
|
||||
@ -743,7 +746,7 @@ static KrkValue _int_to_char(int argc, KrkValue argv[]) {
|
||||
|
||||
static void bindSpecialMethod(NativeFn method, int arity) {
|
||||
KRK_PAUSE_GC();
|
||||
KrkBoundMethod * bound = krk_newBoundMethod(krk_peek(0), boundNative(method,arity));
|
||||
KrkBoundMethod * bound = krk_newBoundMethod(krk_peek(0), (KrkObj*)boundNative(method,arity));
|
||||
krk_pop(); /* The original object */
|
||||
krk_push(OBJECT_VAL(bound));
|
||||
KRK_RESUME_GC();
|
||||
|
2
vm.h
2
vm.h
@ -83,4 +83,4 @@ extern void krk_runtimeError(const char * fmt, ...);
|
||||
extern KrkValue krk_dictGet(KrkValue dictClass, KrkInstance * dict, KrkValue key);
|
||||
extern void krk_dictSet(KrkValue dictClass, KrkInstance * dict, KrkValue key, KrkValue value);
|
||||
extern KrkInstance * krk_dictCreate(KrkValue * outClass);
|
||||
extern void krk_runNext(void);
|
||||
extern KrkValue krk_runNext(void);
|
||||
|
Loading…
Reference in New Issue
Block a user