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(); }