diff --git a/clox/src/chunk.h b/clox/src/chunk.h index fe585de..e992c04 100644 --- a/clox/src/chunk.h +++ b/clox/src/chunk.h @@ -32,6 +32,7 @@ typedef enum { OP_LOOP, OP_CALL, OP_CLOSURE, + OP_CLOSE_UPVALUE, OP_RETURN, } OpCode; diff --git a/clox/src/compiler.c b/clox/src/compiler.c index 6e98b5e..75ed697 100644 --- a/clox/src/compiler.c +++ b/clox/src/compiler.c @@ -42,6 +42,7 @@ typedef struct { typedef struct { Token name; int depth; + bool isCaptured; } Local; typedef struct { @@ -197,6 +198,7 @@ static void initCompiler(Compiler *compiler, FunctionType type) { Local *local = ¤t->locals[current->localCount++]; local->depth = 0; + local->isCaptured = false; local->name.start = ""; local->name.length = 0; } @@ -224,7 +226,11 @@ static void endScope() { while (current->localCount > 0 && current->locals[current->localCount - 1].depth > current->scopeDepth) { - emitByte(OP_POP); + if (current->locals[current->localCount - 1].isCaptured) { + emitByte(OP_CLOSE_UPVALUE); + } else { + emitByte(OP_POP); + } current->localCount--; } } @@ -740,6 +746,7 @@ static int resolveUpvalue(Compiler *compiler, Token *name) { int local = resolveLocal(compiler->enclosing, name); if (local != -1) { + compiler->enclosing->locals[local].isCaptured = true; return addUpvalue(compiler, (uint8_t)local, true); } @@ -760,6 +767,7 @@ static void addLocal(Token name) { Local *local = ¤t->locals[current->localCount++]; local->name = name; local->depth = -1; + local->isCaptured = false; } static void declareVariable() { diff --git a/clox/src/debug.c b/clox/src/debug.c index f175030..750fdb9 100644 --- a/clox/src/debug.c +++ b/clox/src/debug.c @@ -118,6 +118,8 @@ int disassembleInstruction(Chunk *chunk, int offset) { return offset; } + case OP_CLOSE_UPVALUE: + return simpleInstruction("OP_CLOSE_UPVALUE", offset); case OP_RETURN: return simpleInstruction("OP_RETURN", offset); default: diff --git a/clox/src/memory.c b/clox/src/memory.c index 3124bb6..1db1c61 100644 --- a/clox/src/memory.c +++ b/clox/src/memory.c @@ -18,6 +18,8 @@ void *reallocate(void *pointer, size_t oldSize, size_t newSize) { static void freeObject(Obj *object) { switch (object->type) { case OBJ_CLOSURE: { + ObjClosure *closure = (ObjClosure *)object; + FREE_ARRAY(ObjUpvalue *, closure->upvalues, closure->upvalueCount); FREE(ObjClosure, object); break; } @@ -36,6 +38,9 @@ static void freeObject(Obj *object) { FREE(ObjString, object); break; } + case OBJ_UPVALUE: + FREE(ObjUpvalue, object); + break; } } diff --git a/clox/src/object.c b/clox/src/object.c index 8d26d8b..31550ae 100644 --- a/clox/src/object.c +++ b/clox/src/object.c @@ -20,8 +20,15 @@ static Obj *allocateObject(size_t size, ObjType type) { } ObjClosure *newClosure(ObjFunction *function) { + ObjUpvalue **upvalues = ALLOCATE(ObjUpvalue *, function->upvalueCount); + for (int i = 0; i < function->upvalueCount; i++) { + upvalues[i] = NULL; + } + ObjClosure *closure = ALLOCATE_OBJ(ObjClosure, OBJ_CLOSURE); closure->function = function; + closure->upvalues = upvalues; + closure->upvalueCount = function->upvalueCount; return closure; } @@ -81,6 +88,14 @@ ObjString *copyString(const char *chars, int length) { return allocateString(heapChars, length, hash); } +ObjUpvalue *newUpvalue(Value *slot) { + ObjUpvalue *upvalue = ALLOCATE_OBJ(ObjUpvalue, OBJ_UPVALUE); + upvalue->closed = NIL_VAL; + upvalue->location = slot; + upvalue->next = NULL; + return upvalue; +} + static void printFunction(ObjFunction *function) { if (function->name == NULL) { printf("