aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Tom Willemse2022-08-14 19:56:32 -0700
committerGravatar Tom Willemse2022-08-14 19:56:32 -0700
commit62858b60e43803477e898c7993e109a94701ce70 (patch)
tree30d12b56bdf4e489372b68698252d4296fc5be4d
parente91006b59a143ad0083b3fb303a493f9d97e6c9b (diff)
downloadcrafting-interpreters-62858b60e43803477e898c7993e109a94701ce70.tar.gz
crafting-interpreters-62858b60e43803477e898c7993e109a94701ce70.zip
Chapter 28.5
-rw-r--r--clox/src/chunk.h1
-rw-r--r--clox/src/compiler.c4
-rw-r--r--clox/src/debug.c11
-rw-r--r--clox/src/vm.c36
4 files changed, 52 insertions, 0 deletions
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);