Add __base__, isinstance(), and track superclass in the VM and not just implicitly by super() calls.
This commit is contained in:
parent
90b8ba97dd
commit
764f9144f8
1
memory.c
1
memory.c
@ -131,6 +131,7 @@ static void blackenObject(KrkObj * object) {
|
||||
krk_markObject((KrkObj*)_class->name);
|
||||
krk_markObject((KrkObj*)_class->filename);
|
||||
krk_markObject((KrkObj*)_class->docstring);
|
||||
krk_markObject((KrkObj*)_class->base);
|
||||
krk_markTable(&_class->methods);
|
||||
break;
|
||||
}
|
||||
|
1
object.c
1
object.c
@ -150,6 +150,7 @@ KrkClass * krk_newClass(KrkString * name) {
|
||||
_class->name = name;
|
||||
_class->filename = NULL;
|
||||
_class->docstring = NULL;
|
||||
_class->base = NULL;
|
||||
krk_initTable(&_class->methods);
|
||||
return _class;
|
||||
}
|
||||
|
3
object.h
3
object.h
@ -72,11 +72,12 @@ typedef struct {
|
||||
size_t upvalueCount;
|
||||
} KrkClosure;
|
||||
|
||||
typedef struct {
|
||||
typedef struct KrkClass {
|
||||
KrkObj obj;
|
||||
KrkString * name;
|
||||
KrkString * filename;
|
||||
KrkString * docstring;
|
||||
struct KrkClass * base;
|
||||
KrkTable methods;
|
||||
} KrkClass;
|
||||
|
||||
|
2
rline.c
2
rline.c
@ -541,7 +541,7 @@ char * syn_krk_types[] = {
|
||||
"self", "super", /* implicit in a class method */
|
||||
"len", "str", "int", "float", "dir", /* global functions from __builtins__ */
|
||||
"list","dict","range", /* builtin classes */
|
||||
"object","exception",
|
||||
"object","exception","isinstance",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
37
vm.c
37
vm.c
@ -399,6 +399,33 @@ static KrkValue krk_dirObject(int argc, KrkValue argv[]) {
|
||||
return out;
|
||||
}
|
||||
|
||||
static KrkValue krk_isinstance(int argc, KrkValue argv[]) {
|
||||
if (argc != 2) {
|
||||
krk_runtimeError("isinstance expects 2 arguments, got %d", argc);
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
if (!IS_CLASS(argv[1])) {
|
||||
krk_runtimeError("isinstance() arg 2 must be class");
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
/* Things which are not instances are not instances of anything...
|
||||
* (for now, there should be fake classes for them later.) */
|
||||
if (!IS_INSTANCE(argv[0])) return BOOLEAN_VAL(0);
|
||||
|
||||
KrkInstance * obj = AS_INSTANCE(argv[0]);
|
||||
KrkClass * obj_class = obj->_class;
|
||||
KrkClass * _class = AS_CLASS(argv[1]);
|
||||
|
||||
while (obj_class) {
|
||||
if (obj_class == _class) return BOOLEAN_VAL(1);
|
||||
obj_class = obj_class->base;
|
||||
}
|
||||
|
||||
return BOOLEAN_VAL(0);
|
||||
}
|
||||
|
||||
static int call(KrkClosure * closure, int argCount) {
|
||||
int minArgs = closure->function->requiredArgs;
|
||||
int maxArgs = minArgs + closure->function->defaultArgs;
|
||||
@ -551,12 +578,15 @@ void krk_initVM(int flags) {
|
||||
vm.specialMethodNames[METHOD_FLOAT]= OBJECT_VAL(S("__float__"));
|
||||
vm.specialMethodNames[METHOD_LEN] = OBJECT_VAL(S("__len__"));
|
||||
vm.specialMethodNames[METHOD_DOC] = OBJECT_VAL(S("__doc__"));
|
||||
vm.specialMethodNames[METHOD_BASE] = OBJECT_VAL(S("__base__"));
|
||||
|
||||
/* Create built-in class `object` */
|
||||
vm.object_class = krk_newClass(S("object"));
|
||||
krk_attachNamedObject(&vm.globals, "object", (KrkObj*)vm.object_class);
|
||||
krk_defineNative(&vm.object_class->methods, ".__dir__", krk_dirObject);
|
||||
|
||||
/* Build classes for basic types with __init__ methods to generate them */
|
||||
|
||||
vm.builtins = krk_newInstance(vm.object_class);
|
||||
krk_attachNamedObject(&vm.globals, "__builtins__", (KrkObj*)vm.builtins);
|
||||
|
||||
@ -583,6 +613,7 @@ void krk_initVM(int flags) {
|
||||
|
||||
krk_defineNative(&vm.globals, "listOf", krk_list_of);
|
||||
krk_defineNative(&vm.globals, "dictOf", krk_dict_of);
|
||||
krk_defineNative(&vm.globals, "isinstance", krk_isinstance);
|
||||
|
||||
/* Now read the builtins module */
|
||||
KrkValue builtinsModule = krk_interpret(_builtins_src,1,"__builtins__","__builtins__");
|
||||
@ -1144,6 +1175,7 @@ static KrkValue run() {
|
||||
KrkClass * _class = krk_newClass(name);
|
||||
krk_push(OBJECT_VAL(_class));
|
||||
_class->filename = frame->closure->function->chunk.filename;
|
||||
_class->base = vm.object_class;
|
||||
krk_tableAddAll(&vm.object_class->methods, &_class->methods);
|
||||
break;
|
||||
}
|
||||
@ -1191,6 +1223,10 @@ static KrkValue run() {
|
||||
KrkValue out = _class->docstring ? OBJECT_VAL(_class->docstring) : NONE_VAL();
|
||||
krk_pop();
|
||||
krk_push(out);
|
||||
} else if (krk_valuesEqual(OBJECT_VAL(name), vm.specialMethodNames[METHOD_BASE])) {
|
||||
KrkValue out = _class->base ? OBJECT_VAL(_class->base) : NONE_VAL();
|
||||
krk_pop();
|
||||
krk_push(out);
|
||||
} else {
|
||||
goto _undefined;
|
||||
}
|
||||
@ -1300,6 +1336,7 @@ _undefined:
|
||||
return NONE_VAL();
|
||||
}
|
||||
KrkClass * subclass = AS_CLASS(krk_peek(0));
|
||||
subclass->base = AS_CLASS(superclass);
|
||||
krk_tableAddAll(&AS_CLASS(superclass)->methods, &subclass->methods);
|
||||
krk_pop();
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user