diff options
Diffstat (limited to 'clox/src/compiler.c')
-rw-r--r-- | clox/src/compiler.c | 38 |
1 files changed, 34 insertions, 4 deletions
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 = ¤t->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; } |