1
0
forked from Mirror/wren

Start sketching out inheritance.

This commit is contained in:
Bob Nystrom
2013-11-13 11:05:03 -08:00
parent 509f62fdad
commit 27a652e565
5 changed files with 93 additions and 17 deletions

View File

@ -1201,8 +1201,17 @@ void definition(Compiler* compiler)
// Create a variable to store the class in.
int symbol = declareVariable(compiler);
// Create the empty class.
emit(compiler, CODE_CLASS);
// Load the superclass (if there is one).
if (match(compiler, TOKEN_IS))
{
parsePrecedence(compiler, 0, PREC_CALL);
emit(compiler, CODE_SUBCLASS);
}
else
{
// Create the empty class.
emit(compiler, CODE_CLASS);
}
// Store it in its name.
defineVariable(compiler, symbol);

View File

@ -228,6 +228,7 @@ DEF_PRIMITIVE(io_write)
}
static const char* CORE_LIB =
"class Object {}\n"
"class Bool {}\n"
"class Class {}\n"
"class Function {}\n"
@ -273,6 +274,8 @@ void loadCore(VM* vm)
PRIMITIVE(vm->numClass, "== ", num_eqeq);
PRIMITIVE(vm->numClass, "!= ", num_bangeq);
vm->objectClass = AS_CLASS(findGlobal(vm, "Object"));
vm->stringClass = AS_CLASS(findGlobal(vm, "String"));
PRIMITIVE(vm->stringClass, "contains ", string_contains);
PRIMITIVE(vm->stringClass, "count", string_count);
@ -284,7 +287,7 @@ void loadCore(VM* vm)
ObjClass* ioClass = AS_CLASS(findGlobal(vm, "IO"));
PRIMITIVE(ioClass, "write ", io_write);
ObjClass* unsupportedClass = newClass(vm);
ObjClass* unsupportedClass = newClass(vm, vm->objectClass);
// TODO(bob): Make this a distinct object type.
vm->unsupported = (Value)newInstance(vm, unsupportedClass);

View File

@ -265,11 +265,13 @@ Value newBool(VM* vm, int value)
return obj;
}
static ObjClass* newSingleClass(VM* vm)
static ObjClass* newSingleClass(VM* vm, ObjClass* metaclass,
ObjClass* superclass)
{
ObjClass* obj = allocate(vm, sizeof(ObjClass));
initObj(vm, &obj->obj, OBJ_CLASS);
obj->metaclass = NULL;
obj->metaclass = metaclass;
obj->superclass = superclass;
for (int i = 0; i < MAX_SYMBOLS; i++)
{
@ -279,18 +281,29 @@ static ObjClass* newSingleClass(VM* vm)
return obj;
}
ObjClass* newClass(VM* vm)
ObjClass* newClass(VM* vm, ObjClass* superclass)
{
ObjClass* classObj = newSingleClass(vm);
// Make the metaclass.
// TODO(bob): What is the metaclass's metaclass and superclass?
ObjClass* metaclass = newSingleClass(vm, NULL, NULL);
// Make sure this isn't collected when we allocate the metaclass.
pinObj(vm, (Value)classObj);
// Make sure it isn't collected when we allocate the metaclass.
pinObj(vm, (Value)metaclass);
// Make its metaclass.
// TODO(bob): What is the metaclass's metaclass?
classObj->metaclass = newSingleClass(vm);
ObjClass* classObj = newSingleClass(vm, metaclass, superclass);
unpinObj(vm, (Value)classObj);
unpinObj(vm, (Value)metaclass);
// Inherit methods from its superclass (unless it's Object, which has none).
// TODO(bob): If we want BETA-style inheritance, we'll need to do this after
// the subclass has defined its methods.
if (superclass != NULL)
{
for (int i = 0; i < MAX_SYMBOLS; i++)
{
classObj->methods[i] = superclass->methods[i];
}
}
return classObj;
}
@ -461,6 +474,10 @@ void dumpCode(VM* vm, ObjFn* fn)
case CODE_CLASS:
printf("CLASS\n");
break;
case CODE_SUBCLASS:
printf("SUBCLASS\n");
break;
case CODE_METACLASS:
printf("METACLASS\n");
@ -608,7 +625,8 @@ Value interpret(VM* vm, ObjFn* fn)
{
CallFrame* frame = &fiber->frames[fiber->numFrames - 1];
switch (frame->fn->bytecode[frame->ip++])
Code instruction = frame->fn->bytecode[frame->ip++];
switch (instruction)
{
case CODE_CONSTANT:
PUSH(frame->fn->constants[READ_ARG()]);
@ -619,8 +637,23 @@ Value interpret(VM* vm, ObjFn* fn)
case CODE_TRUE: PUSH(newBool(vm, 1)); break;
case CODE_CLASS:
case CODE_SUBCLASS:
{
ObjClass* classObj = newClass(vm);
int isSubclass = instruction == CODE_SUBCLASS;
ObjClass* superclass;
if (isSubclass)
{
// TODO(bob): Handle the superclass not being a class object!
superclass = AS_CLASS(POP());
}
else
{
// Implicit Object superclass.
superclass = vm->objectClass;
}
ObjClass* classObj = newClass(vm, superclass);
// Define a "new" method on the metaclass.
// TODO(bob): Can this be inherited?
@ -696,7 +729,7 @@ Value interpret(VM* vm, ObjFn* fn)
case CODE_CALL_10:
{
// Add one for the implicit receiver argument.
int numArgs = frame->fn->bytecode[frame->ip - 1] - CODE_CALL_0 + 1;
int numArgs = instruction - CODE_CALL_0 + 1;
int symbol = READ_ARG();
Value receiver = fiber->stack[fiber->stackSize - numArgs];

View File

@ -87,6 +87,7 @@ typedef struct sObjClass
{
Obj obj;
struct sObjClass* metaclass;
struct sObjClass* superclass;
// TODO(bob): Hack. Probably don't want to use this much space.
Method methods[MAX_SYMBOLS];
} ObjClass;
@ -127,6 +128,9 @@ typedef enum
// Define a new empty class and push it.
CODE_CLASS,
// Pop a superclass off the stack, then push a new class that extends it.
CODE_SUBCLASS,
// Push the metaclass of the class on the top of the stack. Does not discard
// the class.
CODE_METACLASS,
@ -196,6 +200,7 @@ struct sVM
ObjClass* fnClass;
ObjClass* nullClass;
ObjClass* numClass;
ObjClass* objectClass;
ObjClass* stringClass;
// The singleton values.
@ -264,7 +269,7 @@ Value newBool(VM* vm, int value);
ObjFn* newFunction(VM* vm);
// Creates a new class object.
ObjClass* newClass(VM* vm);
ObjClass* newClass(VM* vm, ObjClass* superclass);
// Creates a new instance of the given [classObj].
ObjInstance* newInstance(VM* vm, ObjClass* classObj);

View File

@ -0,0 +1,26 @@
class Foo {
methodOnFoo { io.write("foo") }
method(a) { io.write("foo") }
method(a, b, c) { io.write("foo") }
}
class Bar is Foo {
methodOnBar { io.write("bar") }
method(a, b) { io.write("bar") }
method(a, b, c, d) { io.write("bar") }
}
var bar = Bar.new
bar.methodOnFoo // expect: foo
bar.methodOnBar // expect: bar
// Methods with different arity do not shadow each other.
bar.method(1) // expect: foo
bar.method(1, 2) // expect: bar
bar.method(1, 2, 3) // expect: foo
bar.method(1, 2, 3, 4) // expect: bar
// TODO(bob): Overriding (or BETA-style refining?).
// TODO(bob): Private fields.
// TODO(bob): Super (or inner) calls.
// TODO(bob): Grammar for what expressions can follow "is".