From 1ae50814d3c7fc75fe02f7ce53497cb17f8114ff Mon Sep 17 00:00:00 2001 From: Tom Willemse Date: Wed, 23 Mar 2022 17:00:22 -0700 Subject: [PATCH] Chapter 25.1 --- clox/src/chunk.h | 1 + clox/src/compiler.c | 2 +- clox/src/debug.c | 8 ++++++++ clox/src/memory.c | 4 ++++ clox/src/object.c | 9 +++++++++ clox/src/object.h | 9 +++++++++ clox/src/vm.c | 35 +++++++++++++++++++++++------------ clox/src/vm.h | 2 +- 8 files changed, 56 insertions(+), 14 deletions(-) diff --git a/clox/src/chunk.h b/clox/src/chunk.h index 37f5d6e..be3c1cb 100644 --- a/clox/src/chunk.h +++ b/clox/src/chunk.h @@ -29,6 +29,7 @@ typedef enum { OP_JUMP_IF_FALSE, OP_LOOP, OP_CALL, + OP_CLOSURE, OP_RETURN, } OpCode; diff --git a/clox/src/compiler.c b/clox/src/compiler.c index b1e4811..7500005 100644 --- a/clox/src/compiler.c +++ b/clox/src/compiler.c @@ -339,7 +339,7 @@ static void function(FunctionType type) { block(); ObjFunction *function = endCompiler(); - emitBytes(OP_CONSTANT, makeConstant(OBJ_VAL(function))); + emitBytes(OP_CLOSURE, makeConstant(OBJ_VAL(function))); } static void markInitialized() { diff --git a/clox/src/debug.c b/clox/src/debug.c index 7ba728d..b564aac 100644 --- a/clox/src/debug.c +++ b/clox/src/debug.c @@ -96,6 +96,14 @@ int disassembleInstruction(Chunk *chunk, int offset) { return jumpInstruction("OP_LOOP", -1, chunk, offset); case OP_CALL: return byteInstruction("OP_CALL", chunk, offset); + case OP_CLOSURE: { + offset++; + uint8_t constant = chunk->code[offset++]; + printf("%-16s %4d", "OP_CLOSURE", constant); + printValue(chunk->constants.values[constant]); + printf("\n"); + return offset; + } case OP_RETURN: return simpleInstruction("OP_RETURN", offset); default: diff --git a/clox/src/memory.c b/clox/src/memory.c index e88b91f..3124bb6 100644 --- a/clox/src/memory.c +++ b/clox/src/memory.c @@ -17,6 +17,10 @@ void *reallocate(void *pointer, size_t oldSize, size_t newSize) { static void freeObject(Obj *object) { switch (object->type) { + case OBJ_CLOSURE: { + FREE(ObjClosure, object); + break; + } case OBJ_FUNCTION: { ObjFunction *function = (ObjFunction *)object; freeChunk(&function->chunk); diff --git a/clox/src/object.c b/clox/src/object.c index d4afccc..c12fb82 100644 --- a/clox/src/object.c +++ b/clox/src/object.c @@ -19,6 +19,12 @@ static Obj *allocateObject(size_t size, ObjType type) { return object; } +ObjClosure *newClosure(ObjFunction *function) { + ObjClosure *closure = ALLOCATE_OBJ(ObjClosure, OBJ_CLOSURE); + closure->function = function; + return closure; +} + ObjFunction *newFunction() { ObjFunction *function = ALLOCATE_OBJ(ObjFunction, OBJ_FUNCTION); function->arity = 0; @@ -84,6 +90,9 @@ static void printFunction(ObjFunction *function) { void printObject(Value value) { switch (OBJ_TYPE(value)) { + case OBJ_CLOSURE: + printFunction(AS_CLOSURE(value)->function); + break; case OBJ_FUNCTION: printFunction(AS_FUNCTION(value)); break; diff --git a/clox/src/object.h b/clox/src/object.h index b5942d6..54faf5b 100644 --- a/clox/src/object.h +++ b/clox/src/object.h @@ -7,16 +7,19 @@ #define OBJ_TYPE(value) (AS_OBJ(value)->type) +#define IS_CLOSURE(value) isObjType(value, OBJ_CLOSURE) #define IS_FUNCTION(value) isObjType(value, OBJ_FUNCTION) #define IS_NATIVE(value) isObjType(value, OBJ_NATIVE) #define IS_STRING(value) isObjType(value, OBJ_STRING) +#define AS_CLOSURE(value) ((ObjClosure *)AS_OBJ(value)) #define AS_FUNCTION(value) ((ObjFunction *)AS_OBJ(value)) #define AS_NATIVE(value) (((ObjNative *)AS_OBJ(value))->function) #define AS_STRING(value) ((ObjString *)AS_OBJ(value)) #define AS_CSTRING(value) (((ObjString *)AS_OBJ(value))->chars) typedef enum { + OBJ_CLOSURE, OBJ_FUNCTION, OBJ_NATIVE, OBJ_STRING, @@ -48,6 +51,12 @@ struct ObjString { uint32_t hash; }; +typedef struct { + Obj obj; + ObjFunction *function; +} ObjClosure; + +ObjClosure *newClosure(ObjFunction *function); ObjFunction *newFunction(); ObjNative *newNative(NativeFn function); ObjString *takeString(char *chars, int length); diff --git a/clox/src/vm.c b/clox/src/vm.c index bf7078c..0ed46b4 100644 --- a/clox/src/vm.c +++ b/clox/src/vm.c @@ -30,7 +30,7 @@ static void runtimeError(const char *format, ...) { for (int i = vm.frameCount; i >= 0; i--) { CallFrame *frame = &vm.frames[i]; - ObjFunction *function = frame->function; + ObjFunction *function = frame->closure->function; size_t instruction = frame->ip - function->chunk.code - 1; fprintf(stderr, "[line %d] in ", function->chunk.lines[instruction]); if (function->name == NULL) { @@ -79,9 +79,9 @@ 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, +static bool call(ObjClosure *closure, int argCount) { + if (argCount != closure->function->arity) { + runtimeError("Expected %d arguments but got %d.", closure->function->arity, argCount); return false; } @@ -92,8 +92,8 @@ static bool call(ObjFunction *function, int argCount) { } CallFrame *frame = &vm.frames[vm.frameCount++]; - frame->function = function; - frame->ip = function->chunk.code; + frame->closure = closure; + frame->ip = closure->function->chunk.code; frame->slots = vm.stackTop - argCount - 1; return true; } @@ -101,8 +101,8 @@ static bool call(ObjFunction *function, int argCount) { static bool callValue(Value callee, int argCount) { if (IS_OBJ(callee)) { switch (OBJ_TYPE(callee)) { - case OBJ_FUNCTION: - return call(AS_FUNCTION(callee), argCount); + case OBJ_CLOSURE: + return call(AS_CLOSURE(callee), argCount); case OBJ_NATIVE: { NativeFn native = AS_NATIVE(callee); Value result = native(argCount, vm.stackTop - argCount); @@ -144,7 +144,8 @@ static InterpretResult run() { #define READ_SHORT() \ (frame->ip += 2, (uint16_t)((frame->ip[-2] << 8) | frame->ip[-1])) -#define READ_CONSTANT() (frame->function->chunk.constants.values[READ_BYTE()]) +#define READ_CONSTANT() \ + (frame->closure->function->chunk.constants.values[READ_BYTE()]) #define READ_STRING() AS_STRING(READ_CONSTANT()) #define BINARY_OP(valueType, op) \ do { \ @@ -165,8 +166,9 @@ static InterpretResult run() { printf(" ]"); } printf("\n"); - disassembleInstruction(&frame->function->chunk, - (int)(frame->ip - frame->function->chunk.code)); + disassembleInstruction( + &frame->closure->function->chunk, + (int)(frame->ip - frame->closure->function->chunk.code)); #endif uint8_t instruction; @@ -296,6 +298,12 @@ static InterpretResult run() { frame = &vm.frames[vm.frameCount - 1]; break; } + case OP_CLOSURE: { + ObjFunction *function = AS_FUNCTION(READ_CONSTANT()); + ObjClosure *closure = newClosure(function); + push(OBJ_VAL(closure)); + break; + } case OP_RETURN: { Value result = pop(); vm.frameCount--; @@ -325,7 +333,10 @@ InterpretResult interpret(const char *source) { return INTERPRET_COMPILE_ERROR; push(OBJ_VAL(function)); - call(function, 0); + ObjClosure *closure = newClosure(function); + pop(); + push(OBJ_VAL(closure)); + call(closure, 0); return run(); } diff --git a/clox/src/vm.h b/clox/src/vm.h index 170166b..ce14d0c 100644 --- a/clox/src/vm.h +++ b/clox/src/vm.h @@ -10,7 +10,7 @@ #define STACK_MAX (FRAMES_MAX * UINT8_COUNT) typedef struct { - ObjFunction *function; + ObjClosure *closure; uint8_t *ip; Value *slots; } CallFrame;