aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Tom Willemse2021-10-25 21:49:54 -0700
committerGravatar Tom Willemse2021-10-25 21:49:54 -0700
commit65275bde8a82f54710a65d6e6563394bb850b7ef (patch)
tree5fce3c2af65f1b5ae55823b28bd139860ff05f5c
parent9de87f449518415a7cc181d4592f28185aa5d6a0 (diff)
downloadcrafting-interpreters-65275bde8a82f54710a65d6e6563394bb850b7ef.tar.gz
crafting-interpreters-65275bde8a82f54710a65d6e6563394bb850b7ef.zip
Chapter 22
-rw-r--r--clox/src/chunk.h2
-rw-r--r--clox/src/compiler.c38
-rw-r--r--clox/src/debug.c10
-rw-r--r--clox/src/vm.c10
4 files changed, 56 insertions, 4 deletions
diff --git a/clox/src/chunk.h b/clox/src/chunk.h
index 2807d30..7777ad6 100644
--- a/clox/src/chunk.h
+++ b/clox/src/chunk.h
@@ -10,6 +10,8 @@ typedef enum {
OP_TRUE,
OP_FALSE,
OP_POP,
+ OP_GET_LOCAL,
+ OP_SET_LOCAL,
OP_GET_GLOBAL,
OP_DEFINE_GLOBAL,
OP_SET_GLOBAL,
diff --git a/clox/src/compiler.c b/clox/src/compiler.c
index 98de087..a964b79 100644
--- a/clox/src/compiler.c
+++ b/clox/src/compiler.c
@@ -170,6 +170,7 @@ static void parsePrecedence(Precedence precedence);
static uint8_t parseVariable(const char *name);
static void defineVariable(uint8_t global);
static uint8_t identifierConstant(Token *name);
+static int resolveLocal(Compiler *compiler, Token *name);
static void binary(bool canAssign) {
TokenType operatorType = parser.previous.type;
@@ -321,13 +322,23 @@ static void string(bool canAssign) {
}
static void namedVariable(Token name, bool canAssign) {
- uint8_t arg = identifierConstant(&name);
+ uint8_t getOp, setOp;
+ int arg = resolveLocal(current, &name);
+
+ if (arg != -1) {
+ getOp = OP_GET_LOCAL;
+ setOp = OP_SET_LOCAL;
+ } else {
+ arg = identifierConstant(&name);
+ getOp = OP_GET_GLOBAL;
+ setOp = OP_SET_GLOBAL;
+ }
if (canAssign && match(TOKEN_EQUAL)) {
expression();
- emitBytes(OP_SET_GLOBAL, arg);
+ emitBytes(setOp, arg);
} else {
- emitBytes(OP_GET_GLOBAL, arg);
+ emitBytes(getOp, arg);
}
}
@@ -434,6 +445,20 @@ static bool identifiersEqual(Token *a, Token *b) {
return memcmp(a->start, b->start, a->length) == 0;
}
+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 void addLocal(Token name) {
if (current->localCount == UINT8_COUNT) {
error("Too many local variables in function.");
@@ -442,7 +467,7 @@ static void addLocal(Token name) {
Local *local = &current->locals[current->localCount++];
local->name = name;
- local->depth = current->scopeDepth;
+ local->depth = -1;
}
static void declareVariable() {
@@ -474,8 +499,13 @@ static uint8_t parseVariable(const char *errorMessage) {
return identifierConstant(&parser.previous);
}
+static void markInitialized() {
+ current->locals[current->localCount - 1].depth = current->scopeDepth;
+}
+
static void defineVariable(uint8_t global) {
if (current->scopeDepth > 0) {
+ markInitialized();
return;
}
diff --git a/clox/src/debug.c b/clox/src/debug.c
index 61deb52..5a3cedc 100644
--- a/clox/src/debug.c
+++ b/clox/src/debug.c
@@ -24,6 +24,12 @@ static int simpleInstruction(const char *name, int offset) {
return offset + 1;
}
+static int byteInstruction(const char *name, Chunk *chunk, int offset) {
+ uint8_t slot = chunk->code[offset + 1];
+ printf("%-16s %4d\n", name, slot);
+ return offset + 2;
+}
+
int disassembleInstruction(Chunk *chunk, int offset) {
printf("%04d ", offset);
if (offset > 0 && chunk->lines[offset] == chunk->lines[offset - 1]) {
@@ -44,6 +50,10 @@ int disassembleInstruction(Chunk *chunk, int offset) {
return simpleInstruction("OP_FALSE", offset);
case OP_POP:
return simpleInstruction("OP_POP", offset);
+ case OP_GET_LOCAL:
+ return byteInstruction("OP_GET_LOCAL", chunk, offset);
+ case OP_SET_LOCAL:
+ return byteInstruction("OP_SET_LOCAL", chunk, offset);
case OP_GET_GLOBAL:
return constantInstruction("OP_GET_GLOBAL", chunk, offset);
case OP_DEFINE_GLOBAL:
diff --git a/clox/src/vm.c b/clox/src/vm.c
index 80e11c3..d869527 100644
--- a/clox/src/vm.c
+++ b/clox/src/vm.c
@@ -115,6 +115,16 @@ static InterpretResult run() {
case OP_POP:
pop();
break;
+ case OP_GET_LOCAL: {
+ uint8_t slot = READ_BYTE();
+ push(vm.stack[slot]);
+ break;
+ }
+ case OP_SET_LOCAL: {
+ uint8_t slot = READ_BYTE();
+ vm.stack[slot] = peek(0);
+ break;
+ }
case OP_GET_GLOBAL: {
ObjString *name = READ_STRING();
Value value;