aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Tom Willemse2022-03-15 00:39:11 -0700
committerGravatar Tom Willemse2022-03-15 00:39:11 -0700
commit410f30ef93aebab85238e470253aefdd5f0348c1 (patch)
tree860c8024ff1028d13a8ef681c25578098a22fe15
parent44e47b89de9e7d9f7d86e1f7d532b70c952a8ab3 (diff)
downloadcrafting-interpreters-410f30ef93aebab85238e470253aefdd5f0348c1.tar.gz
crafting-interpreters-410f30ef93aebab85238e470253aefdd5f0348c1.zip
Chapter 24.5
-rw-r--r--clox/src/chunk.h1
-rw-r--r--clox/src/compiler.c27
-rw-r--r--clox/src/debug.c2
-rw-r--r--clox/src/vm.c78
4 files changed, 92 insertions, 16 deletions
diff --git a/clox/src/chunk.h b/clox/src/chunk.h
index 2ec7a8d..37f5d6e 100644
--- a/clox/src/chunk.h
+++ b/clox/src/chunk.h
@@ -28,6 +28,7 @@ typedef enum {
OP_JUMP,
OP_JUMP_IF_FALSE,
OP_LOOP,
+ OP_CALL,
OP_RETURN,
} OpCode;
diff --git a/clox/src/compiler.c b/clox/src/compiler.c
index bd835f2..ea40d7e 100644
--- a/clox/src/compiler.c
+++ b/clox/src/compiler.c
@@ -143,7 +143,10 @@ static int emitJump(uint8_t instruction) {
return currentChunk()->count - 2;
}
-static void emitReturn() { emitByte(OP_RETURN); }
+static void emitReturn() {
+ emitByte(OP_NIL);
+ emitByte(OP_RETURN);
+}
static uint8_t makeConstant(Value value) {
int constant = addConstant(currentChunk(), value);
@@ -269,6 +272,26 @@ static void binary(bool canAssign) {
}
}
+static uint8_t argumentList() {
+ uint8_t argCount = 0;
+ if (!check(TOKEN_RIGHT_PAREN)) {
+ do {
+ expression();
+ if (argCount == 255) {
+ error("Can't have more than 255 arguments.");
+ }
+ argCount++;
+ } while (match(TOKEN_COMMA));
+ }
+ consume(TOKEN_RIGHT_PAREN, "Expect ')' after arguments.");
+ return argCount;
+}
+
+static void call(bool canAssign) {
+ uint8_t argCount = argumentList();
+ emitBytes(OP_CALL, argCount);
+}
+
static void literal(bool canAssign) {
switch (parser.previous.type) {
case TOKEN_FALSE:
@@ -571,7 +594,7 @@ static void grouping(bool canAssign) {
}
ParseRule rules[] = {
- [TOKEN_LEFT_PAREN] = {grouping, NULL, PREC_NONE},
+ [TOKEN_LEFT_PAREN] = {grouping, call, PREC_CALL},
[TOKEN_RIGHT_PAREN] = {NULL, NULL, PREC_NONE},
[TOKEN_LEFT_BRACE] = {NULL, NULL, PREC_NONE},
[TOKEN_RIGHT_BRACE] = {NULL, NULL, PREC_NONE},
diff --git a/clox/src/debug.c b/clox/src/debug.c
index 3f3c289..7ba728d 100644
--- a/clox/src/debug.c
+++ b/clox/src/debug.c
@@ -94,6 +94,8 @@ int disassembleInstruction(Chunk *chunk, int offset) {
return jumpInstruction("OP_JUMP_IF_FALSE", 1, chunk, offset);
case OP_LOOP:
return jumpInstruction("OP_LOOP", -1, chunk, offset);
+ case OP_CALL:
+ return byteInstruction("OP_CALL", chunk, offset);
case OP_RETURN:
return simpleInstruction("OP_RETURN", offset);
default:
diff --git a/clox/src/vm.c b/clox/src/vm.c
index 7dd79a3..0d8d638 100644
--- a/clox/src/vm.c
+++ b/clox/src/vm.c
@@ -23,10 +23,18 @@ static void runtimeError(const char *format, ...) {
va_end(args);
fputs("\n", stderr);
- CallFrame *frame = &vm.frames[vm.frameCount - 1];
- size_t instruction = frame->ip - frame->function->chunk.code - 1;
- int line = frame->function->chunk.lines[instruction];
- fprintf(stderr, "[line %d] in script\n", line);
+ for (int i = vm.frameCount; i >= 0; i--) {
+ CallFrame *frame = &vm.frames[i];
+ ObjFunction *function = frame->function;
+ size_t instruction = frame->ip - function->chunk.code - 1;
+ fprintf(stderr, "[line %d] in ", function->chunk.lines[instruction]);
+ if (function->name == NULL) {
+ fprintf(stderr, "script\n");
+ } else {
+ fprintf(stderr, "%s()\n", function->name->chars);
+ }
+ }
+
resetStack();
}
@@ -56,6 +64,38 @@ Value pop() {
static Value peek(int distance) { return vm.stackTop[-1 - distance]; }
+static bool call(ObjFunction *function, int argCount) {
+ if (argCount != function->arity) {
+ runtimeError("Expected %d argumetns but got %d.", function->arity,
+ argCount);
+ return false;
+ }
+
+ if (vm.frameCount == FRAMES_MAX) {
+ runtimeError("Stack overflow.");
+ return false;
+ }
+
+ CallFrame *frame = &vm.frames[vm.frameCount++];
+ frame->function = function;
+ frame->ip = function->chunk.code;
+ frame->slots = vm.stackTop - argCount - 1;
+ return true;
+}
+
+static bool callValue(Value callee, int argCount) {
+ if (IS_OBJ(callee)) {
+ switch (OBJ_TYPE(callee)) {
+ case OBJ_FUNCTION:
+ return call(AS_FUNCTION(callee), argCount);
+ default:
+ break;
+ }
+ }
+ runtimeError("Can only call functions && classes.");
+ return false;
+}
+
static bool isFalsey(Value value) {
return IS_NIL(value) || (IS_BOOL(value) && !AS_BOOL(value));
}
@@ -226,13 +266,26 @@ static InterpretResult run() {
frame->ip -= offset;
break;
}
+ case OP_CALL: {
+ int argCount = READ_BYTE();
+ if (!callValue(peek(argCount), argCount)) {
+ return INTERPRET_RUNTIME_ERROR;
+ }
+ frame = &vm.frames[vm.frameCount - 1];
+ break;
+ }
case OP_RETURN: {
- /* The book said to remove this, but when I do I get an infinite loop and
- then a segfault because it keeps trying to add the constant 1 to the
- stack. */
- printValue(pop());
- printf("\n");
- return INTERPRET_OK;
+ Value result = pop();
+ vm.frameCount--;
+ if (vm.frameCount == 0) {
+ pop();
+ return INTERPRET_OK;
+ }
+
+ vm.stackTop = frame->slots;
+ push(result);
+ frame = &vm.frames[vm.frameCount - 1];
+ break;
}
}
}
@@ -250,10 +303,7 @@ InterpretResult interpret(const char *source) {
return INTERPRET_COMPILE_ERROR;
push(OBJ_VAL(function));
- CallFrame *frame = &vm.frames[vm.frameCount++];
- frame->function = function;
- frame->ip = function->chunk.code;
- frame->slots = vm.stack;
+ call(function, 0);
return run();
}