From 9025da8168e505e2b0e32b89a0d94db935dace93 Mon Sep 17 00:00:00 2001 From: Tom Willemse Date: Fri, 21 Jan 2022 21:24:26 -0800 Subject: [PATCH] Chapter 24.1 --- clox/src/compiler.c | 47 +++++++++++++++++++++++++++++++++++++++++++++ clox/src/memory.c | 6 ++++++ clox/src/object.c | 15 +++++++++++++++ clox/src/object.h | 12 ++++++++++++ 4 files changed, 80 insertions(+) diff --git a/clox/src/compiler.c b/clox/src/compiler.c index beda5d5..aed21f7 100644 --- a/clox/src/compiler.c +++ b/clox/src/compiler.c @@ -288,6 +288,51 @@ static void expressionStatement() { emitByte(OP_POP); } +static void forStatement() { + beginScope(); + consume(TOKEN_LEFT_PAREN, "Expect '(' after 'for'."); + if (match(TOKEN_SEMICOLON)) { + // No initializer + } else if (match(TOKEN_VAR)) { + varDeclaration(); + } else { + expressionStatement(); + } + + int loopStart = currentChunk()->count; + int exitJump = -1; + if (!match(TOKEN_SEMICOLON)) { + expression(); + consume(TOKEN_SEMICOLON, "Expect ';' after loop condition."); + + // Jump out of the loop if the condition is false. + exitJump = emitJump(OP_JUMP_IF_FALSE); + emitByte(OP_POP); /* Condition. */ + } + + if (!match(TOKEN_RIGHT_PAREN)) { + int bodyJump = emitJump(OP_JUMP); + int incrementStart = currentChunk()->count; + expression(); + emitByte(OP_POP); + consume(TOKEN_RIGHT_PAREN, "Expect ')' after for clauses."); + + emitLoop(loopStart); + loopStart = incrementStart; + patchJump(bodyJump); + } + + statement(); + emitLoop(loopStart); + + if (exitJump != -1) { + patchJump(exitJump); + emitByte(OP_POP); /* Condition. */ + } + + endScope(); +} + static void ifStatement() { consume(TOKEN_LEFT_PAREN, "Expect '(' after 'if'."); expression(); @@ -366,6 +411,8 @@ static void declaration() { static void statement() { if (match(TOKEN_PRINT)) { printStatement(); + } else if (match(TOKEN_FOR)) { + forStatement(); } else if (match(TOKEN_IF)) { ifStatement(); } else if (match(TOKEN_WHILE)) { diff --git a/clox/src/memory.c b/clox/src/memory.c index 169d846..8f8fd4a 100644 --- a/clox/src/memory.c +++ b/clox/src/memory.c @@ -17,6 +17,12 @@ void *reallocate(void *pointer, size_t oldSize, size_t newSize) { static void freeObject(Obj *object) { switch (object->type) { + case OBJ_FUNCTION: { + ObjFunction *function = (ObjFunction *)object; + freeChunk(&function->chunk); + FREE(ObjFunction, object); + break; + } case OBJ_STRING: { ObjString *string = (ObjString *)object; FREE_ARRAY(char, string->chars, string->length + 1); diff --git a/clox/src/object.c b/clox/src/object.c index 361e315..7170352 100644 --- a/clox/src/object.c +++ b/clox/src/object.c @@ -19,6 +19,14 @@ static Obj *allocateObject(size_t size, ObjType type) { return object; } +ObjFunction *newFunction() { + ObjFunction *function = ALLOCATE_OBJ(ObjFunction, OBJ_FUNCTION); + function->arity = 0; + function->name = NULL; + initChunk(&function->chunk); + return function; +} + static ObjString *allocateString(char *chars, int length, uint32_t hash) { ObjString *string = ALLOCATE_OBJ(ObjString, OBJ_STRING); string->length = length; @@ -60,8 +68,15 @@ ObjString *copyString(const char *chars, int length) { return allocateString(heapChars, length, hash); } +static void printFunction(ObjFunction *function) { + printf("", function->name->chars); +} + void printObject(Value value) { switch (OBJ_TYPE(value)) { + case OBJ_FUNCTION: + printFunction(AS_FUNCTION(value)); + break; case OBJ_STRING: printf("%s", AS_CSTRING(value)); break; diff --git a/clox/src/object.h b/clox/src/object.h index 717031b..812c464 100644 --- a/clox/src/object.h +++ b/clox/src/object.h @@ -1,17 +1,21 @@ #ifndef OBJECT_H #define OBJECT_H +#include "chunk.h" #include "common.h" #include "value.h" #define OBJ_TYPE(value) (AS_OBJ(value)->type) +#define IS_FUNCTION(value) isObjType(value, OBJ_FUNCTION) #define IS_STRING(value) isObjType(value, OBJ_STRING) +#define AS_FUNCTION(value) ((ObjFunction *)AS_OBJ(value)) #define AS_STRING(value) ((ObjString *)AS_OBJ(value)) #define AS_CSTRING(value) (((ObjString *)AS_OBJ(value))->chars) typedef enum { + OBJ_FUNCTION, OBJ_STRING, } ObjType; @@ -20,6 +24,13 @@ struct Obj { struct Obj *next; }; +typedef struct { + Obj obj; + int arity; + Chunk chunk; + ObjString *name; +} ObjFunction; + struct ObjString { Obj obj; int length; @@ -27,6 +38,7 @@ struct ObjString { uint32_t hash; }; +ObjFunction *newFunction(); ObjString *takeString(char *chars, int length); ObjString *copyString(const char *chars, int length); void printObject(Value value);