Chapter 24.5

This commit is contained in:
Tom Willemse 2022-03-15 00:39:11 -07:00
parent 44e47b89de
commit 410f30ef93
4 changed files with 92 additions and 16 deletions

View file

@ -28,6 +28,7 @@ typedef enum {
OP_JUMP, OP_JUMP,
OP_JUMP_IF_FALSE, OP_JUMP_IF_FALSE,
OP_LOOP, OP_LOOP,
OP_CALL,
OP_RETURN, OP_RETURN,
} OpCode; } OpCode;

View file

@ -143,7 +143,10 @@ static int emitJump(uint8_t instruction) {
return currentChunk()->count - 2; 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) { static uint8_t makeConstant(Value value) {
int constant = addConstant(currentChunk(), 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) { static void literal(bool canAssign) {
switch (parser.previous.type) { switch (parser.previous.type) {
case TOKEN_FALSE: case TOKEN_FALSE:
@ -571,7 +594,7 @@ static void grouping(bool canAssign) {
} }
ParseRule rules[] = { ParseRule rules[] = {
[TOKEN_LEFT_PAREN] = {grouping, NULL, PREC_NONE}, [TOKEN_LEFT_PAREN] = {grouping, call, PREC_CALL},
[TOKEN_RIGHT_PAREN] = {NULL, NULL, PREC_NONE}, [TOKEN_RIGHT_PAREN] = {NULL, NULL, PREC_NONE},
[TOKEN_LEFT_BRACE] = {NULL, NULL, PREC_NONE}, [TOKEN_LEFT_BRACE] = {NULL, NULL, PREC_NONE},
[TOKEN_RIGHT_BRACE] = {NULL, NULL, PREC_NONE}, [TOKEN_RIGHT_BRACE] = {NULL, NULL, PREC_NONE},

View file

@ -94,6 +94,8 @@ int disassembleInstruction(Chunk *chunk, int offset) {
return jumpInstruction("OP_JUMP_IF_FALSE", 1, chunk, offset); return jumpInstruction("OP_JUMP_IF_FALSE", 1, chunk, offset);
case OP_LOOP: case OP_LOOP:
return jumpInstruction("OP_LOOP", -1, chunk, offset); return jumpInstruction("OP_LOOP", -1, chunk, offset);
case OP_CALL:
return byteInstruction("OP_CALL", chunk, offset);
case OP_RETURN: case OP_RETURN:
return simpleInstruction("OP_RETURN", offset); return simpleInstruction("OP_RETURN", offset);
default: default:

View file

@ -23,10 +23,18 @@ static void runtimeError(const char *format, ...) {
va_end(args); va_end(args);
fputs("\n", stderr); fputs("\n", stderr);
CallFrame *frame = &vm.frames[vm.frameCount - 1]; for (int i = vm.frameCount; i >= 0; i--) {
size_t instruction = frame->ip - frame->function->chunk.code - 1; CallFrame *frame = &vm.frames[i];
int line = frame->function->chunk.lines[instruction]; ObjFunction *function = frame->function;
fprintf(stderr, "[line %d] in script\n", line); 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(); resetStack();
} }
@ -56,6 +64,38 @@ Value pop() {
static Value peek(int distance) { return vm.stackTop[-1 - distance]; } 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) { static bool isFalsey(Value value) {
return IS_NIL(value) || (IS_BOOL(value) && !AS_BOOL(value)); return IS_NIL(value) || (IS_BOOL(value) && !AS_BOOL(value));
} }
@ -226,14 +266,27 @@ static InterpretResult run() {
frame->ip -= offset; frame->ip -= offset;
break; 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: { case OP_RETURN: {
/* The book said to remove this, but when I do I get an infinite loop and Value result = pop();
then a segfault because it keeps trying to add the constant 1 to the vm.frameCount--;
stack. */ if (vm.frameCount == 0) {
printValue(pop()); pop();
printf("\n");
return INTERPRET_OK; 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; return INTERPRET_COMPILE_ERROR;
push(OBJ_VAL(function)); push(OBJ_VAL(function));
CallFrame *frame = &vm.frames[vm.frameCount++]; call(function, 0);
frame->function = function;
frame->ip = function->chunk.code;
frame->slots = vm.stack;
return run(); return run();
} }