aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Tom Willemse2022-05-31 23:02:18 -0700
committerGravatar Tom Willemse2022-05-31 23:02:18 -0700
commite74cbddb0463e93f5d9742accc20bbed027d0b9b (patch)
tree84d6f2bde00a3f529054f5bb9c0123815b427adc
parent1ae50814d3c7fc75fe02f7ce53497cb17f8114ff (diff)
downloadcrafting-interpreters-e74cbddb0463e93f5d9742accc20bbed027d0b9b.tar.gz
crafting-interpreters-e74cbddb0463e93f5d9742accc20bbed027d0b9b.zip
Chapter 25.2
-rw-r--r--clox/src/chunk.h2
-rw-r--r--clox/src/compiler.c53
-rw-r--r--clox/src/debug.c14
-rw-r--r--clox/src/object.c1
-rw-r--r--clox/src/object.h1
-rw-r--r--clox/src/vm.c1
-rw-r--r--src/fib.lox2
7 files changed, 74 insertions, 0 deletions
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 <stdio.h>
#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();