aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Tom Willemse2022-08-14 23:44:26 -0700
committerGravatar Tom Willemse2022-08-14 23:44:26 -0700
commit69a9a95483ca23ee1a42554a9675a30a9d94cc30 (patch)
tree50ae1504f3371f6a6df17338dd5658b4d1aa579a
parent1bba129074b812a354eccfdd9cc69b233789dc6c (diff)
downloadcrafting-interpreters-69a9a95483ca23ee1a42554a9675a30a9d94cc30.tar.gz
crafting-interpreters-69a9a95483ca23ee1a42554a9675a30a9d94cc30.zip
Chapter 29.3
-rw-r--r--clox/src/chunk.h2
-rw-r--r--clox/src/compiler.c25
-rw-r--r--clox/src/debug.c4
-rw-r--r--clox/src/vm.c19
4 files changed, 49 insertions, 1 deletions
diff --git a/clox/src/chunk.h b/clox/src/chunk.h
index 4810f38..1748adc 100644
--- a/clox/src/chunk.h
+++ b/clox/src/chunk.h
@@ -19,6 +19,7 @@ typedef enum {
OP_SET_UPVALUE,
OP_GET_PROPERTY,
OP_SET_PROPERTY,
+ OP_GET_SUPER,
OP_EQUAL,
OP_GREATER,
OP_LESS,
@@ -34,6 +35,7 @@ typedef enum {
OP_LOOP,
OP_CALL,
OP_INVOKE,
+ OP_SUPER_INVOKE,
OP_CLOSURE,
OP_CLOSE_UPVALUE,
OP_RETURN,
diff --git a/clox/src/compiler.c b/clox/src/compiler.c
index 599ad1b..fd435d5 100644
--- a/clox/src/compiler.c
+++ b/clox/src/compiler.c
@@ -486,6 +486,29 @@ static Token syntheticToken(const char *text) {
return token;
}
+static void super_(bool canAssign) {
+ if (currentClass == NULL) {
+ error("Can't use 'super' outside of a class.");
+ } else if (!currentClass->hasSuperclass) {
+ error("Can't use 'super' in a class with no superclass.");
+ }
+
+ consume(TOKEN_DOT, "Expect '.' after 'super'.");
+ consume(TOKEN_IDENTIFIER, "Expect superclass method name.");
+ uint8_t name = identifierConstant(&parser.previous);
+
+ namedVariable(syntheticToken("this"), false);
+ if (match(TOKEN_LEFT_PAREN)) {
+ uint8_t argCount = argumentList();
+ namedVariable(syntheticToken("super"), false);
+ emitBytes(OP_SUPER_INVOKE, name);
+ emitByte(argCount);
+ } else {
+ namedVariable(syntheticToken("super"), false);
+ emitBytes(OP_GET_SUPER, name);
+ }
+}
+
static void classDeclaration() {
consume(TOKEN_IDENTIFIER, "Expect class name");
Token className = parser.previous;
@@ -823,7 +846,7 @@ ParseRule rules[] = {
[TOKEN_OR] = {NULL, or_, PREC_OR},
[TOKEN_PRINT] = {NULL, NULL, PREC_NONE},
[TOKEN_RETURN] = {NULL, NULL, PREC_NONE},
- [TOKEN_SUPER] = {NULL, NULL, PREC_NONE},
+ [TOKEN_SUPER] = {super_, NULL, PREC_NONE},
[TOKEN_THIS] = {this_, NULL, PREC_NONE},
[TOKEN_TRUE] = {literal, NULL, PREC_NONE},
[TOKEN_VAR] = {NULL, NULL, PREC_NONE},
diff --git a/clox/src/debug.c b/clox/src/debug.c
index 4a39811..b8e4a48 100644
--- a/clox/src/debug.c
+++ b/clox/src/debug.c
@@ -86,6 +86,8 @@ int disassembleInstruction(Chunk *chunk, int offset) {
return constantInstruction("OP_GET_PROPERTY", chunk, offset);
case OP_SET_PROPERTY:
return constantInstruction("OP_SET_PROPERTY", chunk, offset);
+ case OP_GET_SUPER:
+ return constantInstruction("OP_GET_SUPER", chunk, offset);
case OP_EQUAL:
return simpleInstruction("OP_EQUAL", offset);
case OP_GREATER:
@@ -116,6 +118,8 @@ int disassembleInstruction(Chunk *chunk, int offset) {
return byteInstruction("OP_CALL", chunk, offset);
case OP_INVOKE:
return invokeInstruction("OP_INVOKE", chunk, offset);
+ case OP_SUPER_INVOKE:
+ return invokeInstruction("OP_SUPER_INVOKE", chunk, offset);
case OP_CLOSURE: {
offset++;
uint8_t constant = chunk->code[offset++];
diff --git a/clox/src/vm.c b/clox/src/vm.c
index 8a6847e..47c9f29 100644
--- a/clox/src/vm.c
+++ b/clox/src/vm.c
@@ -379,6 +379,15 @@ static InterpretResult run() {
push(value);
break;
}
+ case OP_GET_SUPER: {
+ ObjString *name = READ_STRING();
+ ObjClass *superclass = AS_CLASS(pop());
+
+ if (!bindMethod(superclass, name)) {
+ return INTERPRET_RUNTIME_ERROR;
+ }
+ break;
+ }
case OP_EQUAL: {
Value b = pop();
Value a = pop();
@@ -460,6 +469,16 @@ static InterpretResult run() {
frame = &vm.frames[vm.frameCount - 1];
break;
}
+ case OP_SUPER_INVOKE: {
+ ObjString *method = READ_STRING();
+ int argCount = READ_BYTE();
+ ObjClass *superclass = AS_CLASS(pop());
+ if (!invokeFromClass(superclass, method, argCount)) {
+ return INTERPRET_RUNTIME_ERROR;
+ }
+ frame = &vm.frames[vm.frameCount - 1];
+ break;
+ }
case OP_CLOSURE: {
ObjFunction *function = AS_FUNCTION(READ_CONSTANT());
ObjClosure *closure = newClosure(function);