Chapter 24.5
This commit is contained in:
parent
44e47b89de
commit
410f30ef93
4 changed files with 92 additions and 16 deletions
|
@ -28,6 +28,7 @@ typedef enum {
|
|||
OP_JUMP,
|
||||
OP_JUMP_IF_FALSE,
|
||||
OP_LOOP,
|
||||
OP_CALL,
|
||||
OP_RETURN,
|
||||
} OpCode;
|
||||
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue