Skip to content

Instantly share code, notes, and snippets.

@andersonsp
Created May 8, 2023 15:46
Show Gist options
  • Save andersonsp/cac05a9e2a9b68088c580297289960d5 to your computer and use it in GitHub Desktop.
Save andersonsp/cac05a9e2a9b68088c580297289960d5 to your computer and use it in GitHub Desktop.
// Compiler
//
static void endScope() {
current->scopeDepth--;
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--;
}
}
static int resolveLocal(Compiler* compiler, Token* name) {
for (int i = compiler->localCount - 1; i >= 0; i--) {
Local* local = &compiler->locals[i];
if (identifiersEqual(name, &local->name)) {
if (local->depth == -1) {
error("Can't read local variable in its own initializer.");
}
return i;
}
}
return -1;
}
static int addUpvalue(Compiler* compiler, uint8_t index, bool isLocal) {
int upvalueCount = compiler->function->upvalueCount;
for (int i = 0; i < upvalueCount; i++) {
Upvalue* upvalue = &compiler->upvalues[i];
if (upvalue->index == index && upvalue->isLocal == isLocal) {
return i;
}
}
if (upvalueCount == UINT8_COUNT) {
error("Too many closure variables in function.");
return 0;
}
compiler->upvalues[upvalueCount].isLocal = isLocal;
compiler->upvalues[upvalueCount].index = index;
return compiler->function->upvalueCount++;
}
static int resolveUpvalue(Compiler* compiler, Token* name) {
if (compiler->enclosing == NULL) return -1;
int local = resolveLocal(compiler->enclosing, name);
if (local != -1) {
compiler->enclosing->locals[local].isCaptured = true;
return addUpvalue(compiler, (uint8_t)local, true);
}
int upvalue = resolveUpvalue(compiler->enclosing, name);
if (upvalue != -1) {
return addUpvalue(compiler, (uint8_t)upvalue, false);
}
return -1;
}
static void addLocal(Token name) {
if (current->localCount == UINT8_COUNT) {
error("Too many local variables in function.");
return;
}
Local* local = &current->locals[current->localCount++];
local->name = name;
local->depth = -1;
local->isCaptured = false;
}
static void namedVariable(Token name, bool canAssign) {
uint8_t getOp, setOp;
int arg = resolveLocal(current, &name);
if (arg != -1) {
getOp = OP_GET_LOCAL;
setOp = OP_SET_LOCAL;
} else if ((arg = resolveUpvalue(current, &name)) != -1) {
getOp = OP_GET_UPVALUE;
setOp = OP_SET_UPVALUE;
} else {
arg = identifierConstant(&name);
getOp = OP_GET_GLOBAL;
setOp = OP_SET_GLOBAL;
}
if (canAssign && match(TOKEN_EQUAL)) {
expression();
emitBytes(setOp, (uint8_t)arg);
} else {
emitBytes(getOp, (uint8_t)arg);
}
}
// Runtime
//
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;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment