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,
|
||||||
OP_JUMP_IF_FALSE,
|
OP_JUMP_IF_FALSE,
|
||||||
OP_LOOP,
|
OP_LOOP,
|
||||||
|
OP_CALL,
|
||||||
OP_RETURN,
|
OP_RETURN,
|
||||||
} OpCode;
|
} OpCode;
|
||||||
|
|
||||||
|
|
|
@ -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},
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue