From 9de87f449518415a7cc181d4592f28185aa5d6a0 Mon Sep 17 00:00:00 2001 From: Tom Willemse Date: Thu, 21 Oct 2021 20:54:35 -0700 Subject: [PATCH] Chapter 22.3 --- clox/src/compiler.c | 56 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) 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 #include +#include #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 = ¤t->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 = ¤t->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); }