From 62858b60e43803477e898c7993e109a94701ce70 Mon Sep 17 00:00:00 2001 From: Tom Willemse Date: Sun, 14 Aug 2022 19:56:32 -0700 Subject: [PATCH] Chapter 28.5 --- clox/src/chunk.h | 1 + clox/src/compiler.c | 4 ++++ clox/src/debug.c | 11 +++++++++++ clox/src/vm.c | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+) diff --git a/clox/src/chunk.h b/clox/src/chunk.h index 9c75c1d..690fffd 100644 --- a/clox/src/chunk.h +++ b/clox/src/chunk.h @@ -33,6 +33,7 @@ typedef enum { OP_JUMP_IF_FALSE, OP_LOOP, OP_CALL, + OP_INVOKE, OP_CLOSURE, OP_CLOSE_UPVALUE, OP_RETURN, diff --git a/clox/src/compiler.c b/clox/src/compiler.c index 18ad4a7..bfa0a96 100644 --- a/clox/src/compiler.c +++ b/clox/src/compiler.c @@ -335,6 +335,10 @@ static void dot(bool canAssign) { if (canAssign && match(TOKEN_EQUAL)) { expression(); emitBytes(OP_SET_PROPERTY, name); + } else if (match(TOKEN_LEFT_PAREN)) { + uint8_t argCount = argumentList(); + emitBytes(OP_INVOKE, name); + emitByte(argCount); } else { emitBytes(OP_GET_PROPERTY, name); } diff --git a/clox/src/debug.c b/clox/src/debug.c index 74be178..079f0e9 100644 --- a/clox/src/debug.c +++ b/clox/src/debug.c @@ -20,6 +20,15 @@ static int constantInstruction(const char *name, Chunk *chunk, int offset) { return offset + 2; } +static int invokeInstruction(const char *name, Chunk *chunk, int offset) { + uint8_t constant = chunk->code[offset + 1]; + uint8_t argCount = chunk->code[offset + 2]; + printf("%-16s (%d args) %4d '", name, argCount, constant); + printValue(chunk->constants.values[constant]); + printf("'\n'"); + return offset + 3; +} + static int simpleInstruction(const char *name, int offset) { printf("%s\n", name); return offset + 1; @@ -105,6 +114,8 @@ int disassembleInstruction(Chunk *chunk, int offset) { return jumpInstruction("OP_LOOP", -1, chunk, offset); case OP_CALL: return byteInstruction("OP_CALL", chunk, offset); + case OP_INVOKE: + return invokeInstruction("OP_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 d248609..b5cb1cc 100644 --- a/clox/src/vm.c +++ b/clox/src/vm.c @@ -146,6 +146,33 @@ static bool callValue(Value callee, int argCount) { return false; } +static bool invokeFromClass(ObjClass *klass, ObjString *name, int argCount) { + Value method; + if (!tableGet(&klass->methods, name, &method)) { + runtimeError("Undefined property '%s'.", name->chars); + return false; + } + return call(AS_CLOSURE(method), argCount); +} + +static bool invoke(ObjString *name, int argCount) { + Value receiver = peek(argCount); + + if (!IS_INSTANCE(receiver)) { + runtimeError("Only instances have methods."); + return false; + } + + ObjInstance *instance = AS_INSTANCE(receiver); + + Value value; + if (tableGet(&instance->fields, name, &value)) { + vm.stackTop[-argCount - 1] = value; + return callValue(value, argCount); + } + return invokeFromClass(instance->klass, name, argCount); +} + static bool bindMethod(ObjClass *klass, ObjString *name) { Value method; if (!tableGet(&klass->methods, name, &method)) { @@ -424,6 +451,15 @@ static InterpretResult run() { frame = &vm.frames[vm.frameCount - 1]; break; } + case OP_INVOKE: { + ObjString *method = READ_STRING(); + int argCount = READ_BYTE(); + if (!invoke(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);