Chapter 29.3

This commit is contained in:
Tom Willemse 2022-08-14 23:44:26 -07:00
parent 1bba129074
commit 69a9a95483
4 changed files with 49 additions and 1 deletions

View file

@ -19,6 +19,7 @@ typedef enum {
OP_SET_UPVALUE, OP_SET_UPVALUE,
OP_GET_PROPERTY, OP_GET_PROPERTY,
OP_SET_PROPERTY, OP_SET_PROPERTY,
OP_GET_SUPER,
OP_EQUAL, OP_EQUAL,
OP_GREATER, OP_GREATER,
OP_LESS, OP_LESS,
@ -34,6 +35,7 @@ typedef enum {
OP_LOOP, OP_LOOP,
OP_CALL, OP_CALL,
OP_INVOKE, OP_INVOKE,
OP_SUPER_INVOKE,
OP_CLOSURE, OP_CLOSURE,
OP_CLOSE_UPVALUE, OP_CLOSE_UPVALUE,
OP_RETURN, OP_RETURN,

View file

@ -486,6 +486,29 @@ static Token syntheticToken(const char *text) {
return token; 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() { static void classDeclaration() {
consume(TOKEN_IDENTIFIER, "Expect class name"); consume(TOKEN_IDENTIFIER, "Expect class name");
Token className = parser.previous; Token className = parser.previous;
@ -823,7 +846,7 @@ ParseRule rules[] = {
[TOKEN_OR] = {NULL, or_, PREC_OR}, [TOKEN_OR] = {NULL, or_, PREC_OR},
[TOKEN_PRINT] = {NULL, NULL, PREC_NONE}, [TOKEN_PRINT] = {NULL, NULL, PREC_NONE},
[TOKEN_RETURN] = {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_THIS] = {this_, NULL, PREC_NONE},
[TOKEN_TRUE] = {literal, NULL, PREC_NONE}, [TOKEN_TRUE] = {literal, NULL, PREC_NONE},
[TOKEN_VAR] = {NULL, NULL, PREC_NONE}, [TOKEN_VAR] = {NULL, NULL, PREC_NONE},

View file

@ -86,6 +86,8 @@ int disassembleInstruction(Chunk *chunk, int offset) {
return constantInstruction("OP_GET_PROPERTY", chunk, offset); return constantInstruction("OP_GET_PROPERTY", chunk, offset);
case OP_SET_PROPERTY: case OP_SET_PROPERTY:
return constantInstruction("OP_SET_PROPERTY", chunk, offset); return constantInstruction("OP_SET_PROPERTY", chunk, offset);
case OP_GET_SUPER:
return constantInstruction("OP_GET_SUPER", chunk, offset);
case OP_EQUAL: case OP_EQUAL:
return simpleInstruction("OP_EQUAL", offset); return simpleInstruction("OP_EQUAL", offset);
case OP_GREATER: case OP_GREATER:
@ -116,6 +118,8 @@ int disassembleInstruction(Chunk *chunk, int offset) {
return byteInstruction("OP_CALL", chunk, offset); return byteInstruction("OP_CALL", chunk, offset);
case OP_INVOKE: case OP_INVOKE:
return invokeInstruction("OP_INVOKE", chunk, offset); return invokeInstruction("OP_INVOKE", chunk, offset);
case OP_SUPER_INVOKE:
return invokeInstruction("OP_SUPER_INVOKE", chunk, offset);
case OP_CLOSURE: { case OP_CLOSURE: {
offset++; offset++;
uint8_t constant = chunk->code[offset++]; uint8_t constant = chunk->code[offset++];

View file

@ -379,6 +379,15 @@ static InterpretResult run() {
push(value); push(value);
break; 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: { case OP_EQUAL: {
Value b = pop(); Value b = pop();
Value a = pop(); Value a = pop();
@ -460,6 +469,16 @@ static InterpretResult run() {
frame = &vm.frames[vm.frameCount - 1]; frame = &vm.frames[vm.frameCount - 1];
break; 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: { case OP_CLOSURE: {
ObjFunction *function = AS_FUNCTION(READ_CONSTANT()); ObjFunction *function = AS_FUNCTION(READ_CONSTANT());
ObjClosure *closure = newClosure(function); ObjClosure *closure = newClosure(function);