diff options
Diffstat (limited to 'clox/src/vm.c')
-rw-r--r-- | clox/src/vm.c | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/clox/src/vm.c b/clox/src/vm.c index b728ed5..b11a52a 100644 --- a/clox/src/vm.c +++ b/clox/src/vm.c @@ -19,6 +19,7 @@ static Value clockNative(int argCount, Value *args) { static void resetStack() { vm.stackTop = vm.stack; vm.frameCount = 0; + vm.openUpvalues = NULL; } static void runtimeError(const char *format, ...) { @@ -118,6 +119,39 @@ static bool callValue(Value callee, int argCount) { return false; } +static ObjUpvalue *captureUpvalue(Value *local) { + ObjUpvalue *prevUpvalue = NULL; + ObjUpvalue *upvalue = vm.openUpvalues; + while (upvalue != NULL && upvalue->location > local) { + prevUpvalue = upvalue; + upvalue = upvalue->next; + } + + if (upvalue != NULL && upvalue->location == local) { + return upvalue; + } + + ObjUpvalue *createdUpvalue = newUpvalue(local); + createdUpvalue->next = upvalue; + + if (prevUpvalue == NULL) { + vm.openUpvalues = createdUpvalue; + } else { + prevUpvalue->next = createdUpvalue; + } + + return createdUpvalue; +} + +static void closeUpvalues(Value *last) { + while (vm.openUpvalues != NULL && vm.openUpvalues->location >= last) { + ObjUpvalue *upvalue = vm.openUpvalues; + upvalue->closed = *upvalue->location; + upvalue->location = &upvalue->closed; + vm.openUpvalues = upvalue->next; + } +} + static bool isFalsey(Value value) { return IS_NIL(value) || (IS_BOOL(value) && !AS_BOOL(value)); } @@ -225,6 +259,16 @@ static InterpretResult run() { } break; } + case OP_GET_UPVALUE: { + uint8_t slot = READ_BYTE(); + push(*frame->closure->upvalues[slot]->location); + break; + } + case OP_SET_UPVALUE: { + uint8_t slot = READ_BYTE(); + *frame->closure->upvalues[slot]->location = peek(0); + break; + } case OP_EQUAL: { Value b = pop(); Value a = pop(); @@ -303,10 +347,24 @@ static InterpretResult run() { ObjFunction *function = AS_FUNCTION(READ_CONSTANT()); ObjClosure *closure = newClosure(function); push(OBJ_VAL(closure)); + for (int i = 0; i < closure->upvalueCount; i++) { + uint8_t isLocal = READ_BYTE(); + uint8_t index = READ_BYTE(); + if (isLocal) { + closure->upvalues[i] = captureUpvalue(frame->slots + index); + } else { + closure->upvalues[i] = frame->closure->upvalues[index]; + } + } break; } + case OP_CLOSE_UPVALUE: + closeUpvalues(vm.stackTop - 1); + pop(); + break; case OP_RETURN: { Value result = pop(); + closeUpvalues(frame->slots); vm.frameCount--; if (vm.frameCount == 0) { pop(); |