aboutsummaryrefslogtreecommitdiffstats
path: root/clox
diff options
context:
space:
mode:
authorGravatar Tom Willemse2022-01-21 21:24:26 -0800
committerGravatar Tom Willemse2022-01-21 21:24:26 -0800
commit9025da8168e505e2b0e32b89a0d94db935dace93 (patch)
tree162fa69ce309ab3eb0359ba59d1180c02d4869ec /clox
parent37ac05af6d0aa57ccc5ea805af262a407fedeeae (diff)
downloadcrafting-interpreters-9025da8168e505e2b0e32b89a0d94db935dace93.tar.gz
crafting-interpreters-9025da8168e505e2b0e32b89a0d94db935dace93.zip
Chapter 24.1
Diffstat (limited to 'clox')
-rw-r--r--clox/src/compiler.c47
-rw-r--r--clox/src/memory.c6
-rw-r--r--clox/src/object.c15
-rw-r--r--clox/src/object.h12
4 files changed, 80 insertions, 0 deletions
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("<fn %s>", 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);