diff --git a/clox/src/chunk.h b/clox/src/chunk.h index e992c04..ae0ab72 100644 --- a/clox/src/chunk.h +++ b/clox/src/chunk.h @@ -34,6 +34,7 @@ typedef enum { OP_CLOSURE, OP_CLOSE_UPVALUE, OP_RETURN, + OP_CLASS, } OpCode; typedef struct { diff --git a/clox/src/compiler.c b/clox/src/compiler.c index f31d015..b21a53d 100644 --- a/clox/src/compiler.c +++ b/clox/src/compiler.c @@ -362,6 +362,55 @@ static void function(FunctionType type) { } } +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 = -1; + local->isCaptured = false; +} + +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 void classDeclaration() { + consume(TOKEN_IDENTIFIER, "Expect class name"); + uint8_t nameConstant = identifierConstant(&parser.previous); + declareVariable(); + + emitBytes(OP_CLASS, nameConstant); + defineVariable(nameConstant); + + consume(TOKEN_LEFT_BRACE, "Expect '{' before class body."); + consume(TOKEN_RIGHT_BRACE, "Expect '}' after class body."); +} + static void markInitialized() { if (current->scopeDepth == 0) return; @@ -518,7 +567,9 @@ static void synchronize() { } static void declaration() { - if (match(TOKEN_FUN)) { + if (match(TOKEN_CLASS)) { + classDeclaration(); + } else if (match(TOKEN_FUN)) { funDeclaration(); } else if (match(TOKEN_VAR)) { varDeclaration(); @@ -701,12 +752,6 @@ 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 int resolveLocal(Compiler *compiler, Token *name) { for (int i = compiler->localCount - 1; i >= 0; i--) { Local *local = &compiler->locals[i]; @@ -759,37 +804,6 @@ static int resolveUpvalue(Compiler *compiler, Token *name) { return -1; } -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 = -1; - local->isCaptured = false; -} - -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); diff --git a/clox/src/debug.c b/clox/src/debug.c index 750fdb9..a2c2c53 100644 --- a/clox/src/debug.c +++ b/clox/src/debug.c @@ -122,6 +122,8 @@ int disassembleInstruction(Chunk *chunk, int offset) { return simpleInstruction("OP_CLOSE_UPVALUE", offset); case OP_RETURN: return simpleInstruction("OP_RETURN", offset); + case OP_CLASS: + return constantInstruction("OP_CLASS", chunk, offset); default: printf("Unknown opcode %d\n", instruction); return offset + 1; diff --git a/clox/src/vm.c b/clox/src/vm.c index 601b128..37bf2d4 100644 --- a/clox/src/vm.c +++ b/clox/src/vm.c @@ -384,6 +384,9 @@ static InterpretResult run() { frame = &vm.frames[vm.frameCount - 1]; break; } + case OP_CLASS: + push(OBJ_VAL(newClass(READ_STRING()))); + break; } }