Chapter 25.3 & 25.4

This commit is contained in:
Tom Willemse 2022-06-02 22:27:43 -07:00
parent e74cbddb04
commit 57ed9226c0
8 changed files with 105 additions and 1 deletions

View file

@ -32,6 +32,7 @@ typedef enum {
OP_LOOP, OP_LOOP,
OP_CALL, OP_CALL,
OP_CLOSURE, OP_CLOSURE,
OP_CLOSE_UPVALUE,
OP_RETURN, OP_RETURN,
} OpCode; } OpCode;

View file

@ -42,6 +42,7 @@ typedef struct {
typedef struct { typedef struct {
Token name; Token name;
int depth; int depth;
bool isCaptured;
} Local; } Local;
typedef struct { typedef struct {
@ -197,6 +198,7 @@ static void initCompiler(Compiler *compiler, FunctionType type) {
Local *local = &current->locals[current->localCount++]; Local *local = &current->locals[current->localCount++];
local->depth = 0; local->depth = 0;
local->isCaptured = false;
local->name.start = ""; local->name.start = "";
local->name.length = 0; local->name.length = 0;
} }
@ -224,7 +226,11 @@ static void endScope() {
while (current->localCount > 0 && while (current->localCount > 0 &&
current->locals[current->localCount - 1].depth > current->scopeDepth) { 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--; current->localCount--;
} }
} }
@ -740,6 +746,7 @@ static int resolveUpvalue(Compiler *compiler, Token *name) {
int local = resolveLocal(compiler->enclosing, name); int local = resolveLocal(compiler->enclosing, name);
if (local != -1) { if (local != -1) {
compiler->enclosing->locals[local].isCaptured = true;
return addUpvalue(compiler, (uint8_t)local, true); return addUpvalue(compiler, (uint8_t)local, true);
} }
@ -760,6 +767,7 @@ static void addLocal(Token name) {
Local *local = &current->locals[current->localCount++]; Local *local = &current->locals[current->localCount++];
local->name = name; local->name = name;
local->depth = -1; local->depth = -1;
local->isCaptured = false;
} }
static void declareVariable() { static void declareVariable() {

View file

@ -118,6 +118,8 @@ int disassembleInstruction(Chunk *chunk, int offset) {
return offset; return offset;
} }
case OP_CLOSE_UPVALUE:
return simpleInstruction("OP_CLOSE_UPVALUE", offset);
case OP_RETURN: case OP_RETURN:
return simpleInstruction("OP_RETURN", offset); return simpleInstruction("OP_RETURN", offset);
default: default:

View file

@ -18,6 +18,8 @@ void *reallocate(void *pointer, size_t oldSize, size_t newSize) {
static void freeObject(Obj *object) { static void freeObject(Obj *object) {
switch (object->type) { switch (object->type) {
case OBJ_CLOSURE: { case OBJ_CLOSURE: {
ObjClosure *closure = (ObjClosure *)object;
FREE_ARRAY(ObjUpvalue *, closure->upvalues, closure->upvalueCount);
FREE(ObjClosure, object); FREE(ObjClosure, object);
break; break;
} }
@ -36,6 +38,9 @@ static void freeObject(Obj *object) {
FREE(ObjString, object); FREE(ObjString, object);
break; break;
} }
case OBJ_UPVALUE:
FREE(ObjUpvalue, object);
break;
} }
} }

View file

@ -20,8 +20,15 @@ static Obj *allocateObject(size_t size, ObjType type) {
} }
ObjClosure *newClosure(ObjFunction *function) { 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); ObjClosure *closure = ALLOCATE_OBJ(ObjClosure, OBJ_CLOSURE);
closure->function = function; closure->function = function;
closure->upvalues = upvalues;
closure->upvalueCount = function->upvalueCount;
return closure; return closure;
} }
@ -81,6 +88,14 @@ ObjString *copyString(const char *chars, int length) {
return allocateString(heapChars, length, hash); 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) { static void printFunction(ObjFunction *function) {
if (function->name == NULL) { if (function->name == NULL) {
printf("<script>"); printf("<script>");
@ -103,5 +118,8 @@ void printObject(Value value) {
case OBJ_STRING: case OBJ_STRING:
printf("%s", AS_CSTRING(value)); printf("%s", AS_CSTRING(value));
break; break;
case OBJ_UPVALUE:
printf("upvalue");
break;
} }
} }

View file

@ -23,6 +23,7 @@ typedef enum {
OBJ_FUNCTION, OBJ_FUNCTION,
OBJ_NATIVE, OBJ_NATIVE,
OBJ_STRING, OBJ_STRING,
OBJ_UPVALUE,
} ObjType; } ObjType;
struct Obj { struct Obj {
@ -52,9 +53,18 @@ struct ObjString {
uint32_t hash; uint32_t hash;
}; };
typedef struct ObjUpvalue {
Obj obj;
Value *location;
Value closed;
struct ObjUpvalue *next;
} ObjUpvalue;
typedef struct { typedef struct {
Obj obj; Obj obj;
ObjFunction *function; ObjFunction *function;
ObjUpvalue **upvalues;
int upvalueCount;
} ObjClosure; } ObjClosure;
ObjClosure *newClosure(ObjFunction *function); ObjClosure *newClosure(ObjFunction *function);
@ -62,6 +72,7 @@ ObjFunction *newFunction();
ObjNative *newNative(NativeFn function); ObjNative *newNative(NativeFn function);
ObjString *takeString(char *chars, int length); ObjString *takeString(char *chars, int length);
ObjString *copyString(const char *chars, int length); ObjString *copyString(const char *chars, int length);
ObjUpvalue *newUpvalue(Value *slot);
void printObject(Value value); void printObject(Value value);
static inline bool isObjType(Value value, ObjType type) { static inline bool isObjType(Value value, ObjType type) {

View file

@ -19,6 +19,7 @@ static Value clockNative(int argCount, Value *args) {
static void resetStack() { static void resetStack() {
vm.stackTop = vm.stack; vm.stackTop = vm.stack;
vm.frameCount = 0; vm.frameCount = 0;
vm.openUpvalues = NULL;
} }
static void runtimeError(const char *format, ...) { static void runtimeError(const char *format, ...) {
@ -118,6 +119,39 @@ static bool callValue(Value callee, int argCount) {
return false; 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) { static bool isFalsey(Value value) {
return IS_NIL(value) || (IS_BOOL(value) && !AS_BOOL(value)); return IS_NIL(value) || (IS_BOOL(value) && !AS_BOOL(value));
} }
@ -225,6 +259,16 @@ static InterpretResult run() {
} }
break; 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: { case OP_EQUAL: {
Value b = pop(); Value b = pop();
Value a = pop(); Value a = pop();
@ -303,10 +347,24 @@ static InterpretResult run() {
ObjFunction *function = AS_FUNCTION(READ_CONSTANT()); ObjFunction *function = AS_FUNCTION(READ_CONSTANT());
ObjClosure *closure = newClosure(function); ObjClosure *closure = newClosure(function);
push(OBJ_VAL(closure)); 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; break;
} }
case OP_CLOSE_UPVALUE:
closeUpvalues(vm.stackTop - 1);
pop();
break;
case OP_RETURN: { case OP_RETURN: {
Value result = pop(); Value result = pop();
closeUpvalues(frame->slots);
vm.frameCount--; vm.frameCount--;
if (vm.frameCount == 0) { if (vm.frameCount == 0) {
pop(); pop();

View file

@ -23,6 +23,7 @@ typedef struct {
Value *stackTop; Value *stackTop;
Table globals; Table globals;
Table strings; Table strings;
ObjUpvalue *openUpvalues;
Obj *objects; Obj *objects;
} VM; } VM;