From e74cbddb0463e93f5d9742accc20bbed027d0b9b Mon Sep 17 00:00:00 2001 From: Tom Willemse Date: Tue, 31 May 2022 23:02:18 -0700 Subject: [PATCH] Chapter 25.2 --- clox/src/chunk.h | 2 ++ clox/src/compiler.c | 53 +++++++++++++++++++++++++++++++++++++++++++++ clox/src/debug.c | 14 ++++++++++++ clox/src/object.c | 1 + clox/src/object.h | 1 + clox/src/vm.c | 1 + src/fib.lox | 2 ++ 7 files changed, 74 insertions(+) diff --git a/clox/src/chunk.h b/clox/src/chunk.h index be3c1cb..fe585de 100644 --- a/clox/src/chunk.h +++ b/clox/src/chunk.h @@ -15,6 +15,8 @@ typedef enum { OP_GET_GLOBAL, OP_DEFINE_GLOBAL, OP_SET_GLOBAL, + OP_GET_UPVALUE, + OP_SET_UPVALUE, OP_EQUAL, OP_GREATER, OP_LESS, diff --git a/clox/src/compiler.c b/clox/src/compiler.c index 7500005..6e98b5e 100644 --- a/clox/src/compiler.c +++ b/clox/src/compiler.c @@ -44,6 +44,11 @@ typedef struct { int depth; } Local; +typedef struct { + uint8_t index; + bool isLocal; +} Upvalue; + typedef enum { TYPE_FUNCTION, TYPE_SCRIPT } FunctionType; typedef struct Compiler { @@ -53,9 +58,12 @@ typedef struct Compiler { Local locals[UINT8_COUNT]; int localCount; + Upvalue upvalues[UINT8_COUNT]; int scopeDepth; } Compiler; +static int resolveUpvalue(Compiler *, Token *); + Parser parser; Compiler *current = NULL; Chunk *compilingChunk; @@ -340,6 +348,11 @@ static void function(FunctionType type) { ObjFunction *function = endCompiler(); emitBytes(OP_CLOSURE, makeConstant(OBJ_VAL(function))); + + for (int i = 0; i < function->upvalueCount; i++) { + emitByte(compiler.upvalues[i].isLocal ? 1 : 0); + emitByte(compiler.upvalues[i].index); + } } static void markInitialized() { @@ -567,6 +580,9 @@ static void namedVariable(Token name, bool canAssign) { 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; @@ -698,6 +714,43 @@ static int resolveLocal(Compiler *compiler, Token *name) { 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) { + 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."); diff --git a/clox/src/debug.c b/clox/src/debug.c index b564aac..f175030 100644 --- a/clox/src/debug.c +++ b/clox/src/debug.c @@ -1,6 +1,7 @@ #include #include "debug.h" +#include "object.h" #include "value.h" void disassembleChunk(Chunk *chunk, const char *name) { @@ -68,6 +69,10 @@ int disassembleInstruction(Chunk *chunk, int offset) { return constantInstruction("OP_DEFINE_GLOBAL", chunk, offset); case OP_SET_GLOBAL: return constantInstruction("OP_SET_GLOBAL", chunk, offset); + case OP_GET_UPVALUE: + return byteInstruction("OP_GET_UPVALUE", chunk, offset); + case OP_SET_UPVALUE: + return byteInstruction("OP_SET_UPVALUE", chunk, offset); case OP_EQUAL: return simpleInstruction("OP_EQUAL", offset); case OP_GREATER: @@ -102,6 +107,15 @@ int disassembleInstruction(Chunk *chunk, int offset) { printf("%-16s %4d", "OP_CLOSURE", constant); printValue(chunk->constants.values[constant]); printf("\n"); + + ObjFunction *function = AS_FUNCTION(chunk->constants.values[constant]); + for (int j = 0; j < function->upvalueCount; j++) { + int isLocal = chunk->code[offset++]; + int index = chunk->code[offset++]; + printf("%04d | %s %d\n", offset - 2, + isLocal ? "local" : "upvalue", index); + } + return offset; } case OP_RETURN: diff --git a/clox/src/object.c b/clox/src/object.c index c12fb82..8d26d8b 100644 --- a/clox/src/object.c +++ b/clox/src/object.c @@ -28,6 +28,7 @@ ObjClosure *newClosure(ObjFunction *function) { ObjFunction *newFunction() { ObjFunction *function = ALLOCATE_OBJ(ObjFunction, OBJ_FUNCTION); function->arity = 0; + function->upvalueCount = 0; function->name = NULL; initChunk(&function->chunk); return function; diff --git a/clox/src/object.h b/clox/src/object.h index 54faf5b..f650b30 100644 --- a/clox/src/object.h +++ b/clox/src/object.h @@ -33,6 +33,7 @@ struct Obj { typedef struct { Obj obj; int arity; + int upvalueCount; Chunk chunk; ObjString *name; } ObjFunction; diff --git a/clox/src/vm.c b/clox/src/vm.c index 0ed46b4..b728ed5 100644 --- a/clox/src/vm.c +++ b/clox/src/vm.c @@ -270,6 +270,7 @@ static InterpretResult run() { push(NUMBER_VAL(-AS_NUMBER(pop()))); break; case OP_PRINT: { + printf("Printing!\n"); printValue(pop()); printf("\n"); break; diff --git a/src/fib.lox b/src/fib.lox index dd6fb5e..4e126bb 100644 --- a/src/fib.lox +++ b/src/fib.lox @@ -3,6 +3,8 @@ fun fib(n) { return fib(n - 1) + fib(n - 2); } +print "Hello"; + var before = clock(); print fib(40); var after = clock();