aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Tom Willemse2021-10-21 20:54:35 -0700
committerGravatar Tom Willemse2021-10-21 20:54:35 -0700
commit9de87f449518415a7cc181d4592f28185aa5d6a0 (patch)
tree9d06d6190d395bf065f957cdc6ca1f0ec73f8019
parent42a7e262927bfdbbfa15d688610eca37fd0d12e2 (diff)
downloadcrafting-interpreters-9de87f449518415a7cc181d4592f28185aa5d6a0.tar.gz
crafting-interpreters-9de87f449518415a7cc181d4592f28185aa5d6a0.zip
Chapter 22.3
-rw-r--r--clox/src/compiler.c56
1 files changed, 55 insertions, 1 deletions
diff --git a/clox/src/compiler.c b/clox/src/compiler.c
index 1e48d22..98de087 100644
--- a/clox/src/compiler.c
+++ b/clox/src/compiler.c
@@ -1,5 +1,6 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "common.h"
#include "compiler.h"
@@ -151,7 +152,15 @@ static void endCompiler() {
static void beginScope() { current->scopeDepth++; }
-static void endScope() { current->scopeDepth--; }
+static void endScope() {
+ current->scopeDepth--;
+
+ while (current->localCount > 0 &&
+ current->locals[current->localCount - 1].depth > current->scopeDepth) {
+ emitByte(OP_POP);
+ current->localCount--;
+ }
+}
static void expression();
static void statement();
@@ -419,12 +428,57 @@ static uint8_t identifierConstant(Token *name) {
return makeConstant(OBJ_VAL(copyString(name->start, name->length)));
}
+static bool identifiersEqual(Token *a, Token *b) {
+ if (a->length != b->length)
+ return false;
+ return memcmp(a->start, b->start, a->length) == 0;
+}
+
+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 = current->scopeDepth;
+}
+
+static void declareVariable() {
+ if (current->scopeDepth == 0)
+ return;
+
+ Token *name = &parser.previous;
+ for (int i = current->localCount - 1; i >= 0; i--) {
+ Local *local = &current->locals[i];
+ if (local->depth != -1 && local->depth < current->scopeDepth) {
+ break;
+ }
+
+ if (identifiersEqual(name, &local->name)) {
+ error("Already a variable with this name in this scope.");
+ }
+ }
+
+ addLocal(*name);
+}
+
static uint8_t parseVariable(const char *errorMessage) {
consume(TOKEN_IDENTIFIER, errorMessage);
+
+ declareVariable();
+ if (current->scopeDepth > 0)
+ return 0;
+
return identifierConstant(&parser.previous);
}
static void defineVariable(uint8_t global) {
+ if (current->scopeDepth > 0) {
+ return;
+ }
+
emitBytes(OP_DEFINE_GLOBAL, global);
}