aboutsummaryrefslogtreecommitdiffstats
path: root/clox/src/vm.c
diff options
context:
space:
mode:
Diffstat (limited to 'clox/src/vm.c')
-rw-r--r--clox/src/vm.c58
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();