Chapter 25.3 & 25.4
This commit is contained in:
parent
e74cbddb04
commit
57ed9226c0
8 changed files with 105 additions and 1 deletions
|
@ -32,6 +32,7 @@ typedef enum {
|
|||
OP_LOOP,
|
||||
OP_CALL,
|
||||
OP_CLOSURE,
|
||||
OP_CLOSE_UPVALUE,
|
||||
OP_RETURN,
|
||||
} OpCode;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
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() {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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("<script>");
|
||||
|
@ -103,5 +118,8 @@ void printObject(Value value) {
|
|||
case OBJ_STRING:
|
||||
printf("%s", AS_CSTRING(value));
|
||||
break;
|
||||
case OBJ_UPVALUE:
|
||||
printf("upvalue");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ typedef enum {
|
|||
OBJ_FUNCTION,
|
||||
OBJ_NATIVE,
|
||||
OBJ_STRING,
|
||||
OBJ_UPVALUE,
|
||||
} ObjType;
|
||||
|
||||
struct Obj {
|
||||
|
@ -52,9 +53,18 @@ struct ObjString {
|
|||
uint32_t hash;
|
||||
};
|
||||
|
||||
typedef struct ObjUpvalue {
|
||||
Obj obj;
|
||||
Value *location;
|
||||
Value closed;
|
||||
struct ObjUpvalue *next;
|
||||
} ObjUpvalue;
|
||||
|
||||
typedef struct {
|
||||
Obj obj;
|
||||
ObjFunction *function;
|
||||
ObjUpvalue **upvalues;
|
||||
int upvalueCount;
|
||||
} ObjClosure;
|
||||
|
||||
ObjClosure *newClosure(ObjFunction *function);
|
||||
|
@ -62,6 +72,7 @@ ObjFunction *newFunction();
|
|||
ObjNative *newNative(NativeFn function);
|
||||
ObjString *takeString(char *chars, int length);
|
||||
ObjString *copyString(const char *chars, int length);
|
||||
ObjUpvalue *newUpvalue(Value *slot);
|
||||
void printObject(Value value);
|
||||
|
||||
static inline bool isObjType(Value value, ObjType type) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -23,6 +23,7 @@ typedef struct {
|
|||
Value *stackTop;
|
||||
Table globals;
|
||||
Table strings;
|
||||
ObjUpvalue *openUpvalues;
|
||||
Obj *objects;
|
||||
} VM;
|
||||
|
||||
|
|
Loading…
Reference in a new issue