aboutsummaryrefslogtreecommitdiffstats
path: root/clox/src
diff options
context:
space:
mode:
authorGravatar Tom Willemse2021-09-06 02:03:31 -0700
committerGravatar Tom Willemse2021-09-06 02:03:31 -0700
commitc10cbcdf99824bf81fb0874deb258d5c8c7cb22d (patch)
tree2872be7d0038f7b0f5a88a2e34875fd856e0101a /clox/src
parent6508cfd8fe55e03a587b2f72d3ffc901d7ada049 (diff)
downloadcrafting-interpreters-c10cbcdf99824bf81fb0874deb258d5c8c7cb22d.tar.gz
crafting-interpreters-c10cbcdf99824bf81fb0874deb258d5c8c7cb22d.zip
Chapter 18
Diffstat (limited to 'clox/src')
-rw-r--r--clox/src/chunk.h7
-rw-r--r--clox/src/compiler.c57
-rw-r--r--clox/src/debug.c14
-rw-r--r--clox/src/value.c29
-rw-r--r--clox/src/value.h1
-rw-r--r--clox/src/vm.c28
6 files changed, 125 insertions, 11 deletions
diff --git a/clox/src/chunk.h b/clox/src/chunk.h
index 185f13c..399a514 100644
--- a/clox/src/chunk.h
+++ b/clox/src/chunk.h
@@ -6,10 +6,17 @@
typedef enum {
OP_CONSTANT,
+ OP_NIL,
+ OP_TRUE,
+ OP_FALSE,
+ OP_EQUAL,
+ OP_GREATER,
+ OP_LESS,
OP_ADD,
OP_SUBTRACT,
OP_MULTIPLY,
OP_DIVIDE,
+ OP_NOT,
OP_NEGATE,
OP_RETURN,
} OpCode;
diff --git a/clox/src/compiler.c b/clox/src/compiler.c
index 81e1616..ab8fe7d 100644
--- a/clox/src/compiler.c
+++ b/clox/src/compiler.c
@@ -132,6 +132,24 @@ static void binary() {
parsePrecedence((Precedence)(rule->precedence + 1));
switch (operatorType) {
+ case TOKEN_BANG_EQUAL:
+ emitBytes(OP_EQUAL, OP_NOT);
+ break;
+ case TOKEN_EQUAL_EQUAL:
+ emitByte(OP_EQUAL);
+ break;
+ case TOKEN_GREATER:
+ emitByte(OP_GREATER);
+ break;
+ case TOKEN_GREATER_EQUAL:
+ emitBytes(OP_LESS, OP_NOT);
+ break;
+ case TOKEN_LESS:
+ emitByte(OP_LESS);
+ break;
+ case TOKEN_LESS_EQUAL:
+ emitBytes(OP_GREATER, OP_NOT);
+ break;
case TOKEN_PLUS:
emitByte(OP_ADD);
break;
@@ -149,6 +167,22 @@ static void binary() {
}
}
+static void literal() {
+ switch (parser.previous.type) {
+ case TOKEN_FALSE:
+ emitByte(OP_FALSE);
+ break;
+ case TOKEN_NIL:
+ emitByte(OP_NIL);
+ break;
+ case TOKEN_TRUE:
+ emitByte(OP_TRUE);
+ break;
+ default:
+ return; /* Unreachable */
+ }
+}
+
static void expression() { parsePrecedence(PREC_ASSIGNMENT); }
static void number() {
@@ -164,6 +198,9 @@ static void unary() {
// Emit the operator instruction.
switch (operatorType) {
+ case TOKEN_BANG:
+ emitByte(OP_NOT);
+ break;
case TOKEN_MINUS:
emitByte(OP_NEGATE);
break;
@@ -189,31 +226,31 @@ ParseRule rules[] = {
[TOKEN_SEMICOLON] = {NULL, NULL, PREC_NONE},
[TOKEN_SLASH] = {NULL, binary, PREC_FACTOR},
[TOKEN_STAR] = {NULL, binary, PREC_FACTOR},
- [TOKEN_BANG] = {NULL, NULL, PREC_NONE},
- [TOKEN_BANG_EQUAL] = {NULL, NULL, PREC_NONE},
+ [TOKEN_BANG] = {unary, NULL, PREC_NONE},
+ [TOKEN_BANG_EQUAL] = {NULL, binary, PREC_EQUALITY},
[TOKEN_EQUAL] = {NULL, NULL, PREC_NONE},
- [TOKEN_EQUAL_EQUAL] = {NULL, NULL, PREC_NONE},
- [TOKEN_GREATER] = {NULL, NULL, PREC_NONE},
- [TOKEN_GREATER_EQUAL] = {NULL, NULL, PREC_NONE},
- [TOKEN_LESS] = {NULL, NULL, PREC_NONE},
- [TOKEN_LESS_EQUAL] = {NULL, NULL, PREC_NONE},
+ [TOKEN_EQUAL_EQUAL] = {NULL, binary, PREC_EQUALITY},
+ [TOKEN_GREATER] = {NULL, binary, PREC_COMPARISON},
+ [TOKEN_GREATER_EQUAL] = {NULL, binary, PREC_COMPARISON},
+ [TOKEN_LESS] = {NULL, binary, PREC_COMPARISON},
+ [TOKEN_LESS_EQUAL] = {NULL, binary, PREC_COMPARISON},
[TOKEN_IDENTIFIER] = {NULL, NULL, PREC_NONE},
[TOKEN_STRING] = {NULL, NULL, PREC_NONE},
[TOKEN_NUMBER] = {number, NULL, PREC_NONE},
[TOKEN_AND] = {NULL, NULL, PREC_NONE},
[TOKEN_CLASS] = {NULL, NULL, PREC_NONE},
[TOKEN_ELSE] = {NULL, NULL, PREC_NONE},
- [TOKEN_FALSE] = {NULL, NULL, PREC_NONE},
+ [TOKEN_FALSE] = {literal, NULL, PREC_NONE},
[TOKEN_FOR] = {NULL, NULL, PREC_NONE},
[TOKEN_FUN] = {NULL, NULL, PREC_NONE},
[TOKEN_IF] = {NULL, NULL, PREC_NONE},
- [TOKEN_NIL] = {NULL, NULL, PREC_NONE},
+ [TOKEN_NIL] = {literal, NULL, PREC_NONE},
[TOKEN_OR] = {NULL, NULL, PREC_NONE},
[TOKEN_PRINT] = {NULL, NULL, PREC_NONE},
[TOKEN_RETURN] = {NULL, NULL, PREC_NONE},
[TOKEN_SUPER] = {NULL, NULL, PREC_NONE},
[TOKEN_THIS] = {NULL, NULL, PREC_NONE},
- [TOKEN_TRUE] = {NULL, NULL, PREC_NONE},
+ [TOKEN_TRUE] = {literal, NULL, PREC_NONE},
[TOKEN_VAR] = {NULL, NULL, PREC_NONE},
[TOKEN_WHILE] = {NULL, NULL, PREC_NONE},
[TOKEN_ERROR] = {NULL, NULL, PREC_NONE},
diff --git a/clox/src/debug.c b/clox/src/debug.c
index 570bde9..788e759 100644
--- a/clox/src/debug.c
+++ b/clox/src/debug.c
@@ -36,6 +36,18 @@ int disassembleInstruction(Chunk *chunk, int offset) {
switch (instruction) {
case OP_CONSTANT:
return constantInstruction("OP_CONSTANT", chunk, offset);
+ case OP_NIL:
+ return simpleInstruction("OP_NIL", offset);
+ case OP_TRUE:
+ return simpleInstruction("OP_TRUE", offset);
+ case OP_FALSE:
+ return simpleInstruction("OP_FALSE", offset);
+ case OP_EQUAL:
+ return simpleInstruction("OP_EQUAL", offset);
+ case OP_GREATER:
+ return simpleInstruction("OP_GREATER", offset);
+ case OP_LESS:
+ return simpleInstruction("OP_LESS", offset);
case OP_ADD:
return simpleInstruction("OP_ADD", offset);
case OP_SUBTRACT:
@@ -44,6 +56,8 @@ int disassembleInstruction(Chunk *chunk, int offset) {
return simpleInstruction("OP_MULTIPLY", offset);
case OP_DIVIDE:
return simpleInstruction("OP_DIVIDE", offset);
+ case OP_NOT:
+ return simpleInstruction("OP_NOT", offset);
case OP_NEGATE:
return simpleInstruction("OP_NEGATE", offset);
case OP_RETURN:
diff --git a/clox/src/value.c b/clox/src/value.c
index 0737999..34e55b8 100644
--- a/clox/src/value.c
+++ b/clox/src/value.c
@@ -26,4 +26,31 @@ void freeValueArray(ValueArray *array) {
initValueArray(array);
}
-void printValue(Value value) { printf("%g", AS_NUMBER(value)); }
+void printValue(Value value) {
+ switch (value.type) {
+ case VAL_BOOL:
+ printf(AS_BOOL(value) ? "true" : "false");
+ break;
+ case VAL_NIL:
+ printf("nil");
+ break;
+ case VAL_NUMBER:
+ printf("%g", AS_NUMBER(value));
+ break;
+ }
+}
+
+bool valuesEqual(Value a, Value b) {
+ if (a.type != b.type)
+ return false;
+ switch (a.type) {
+ case VAL_BOOL:
+ return AS_BOOL(a) == AS_BOOL(b);
+ case VAL_NIL:
+ return true;
+ case VAL_NUMBER:
+ return AS_NUMBER(a) == AS_NUMBER(b);
+ default:
+ return false; /* Unreachable */
+ }
+}
diff --git a/clox/src/value.h b/clox/src/value.h
index 7478aaf..96df347 100644
--- a/clox/src/value.h
+++ b/clox/src/value.h
@@ -34,6 +34,7 @@ typedef struct {
Value *values;
} ValueArray;
+bool valuesEqual(Value a, Value b);
void initValueArray(ValueArray *array);
void writeValueArray(ValueArray *array, Value value);
void freeValueArray(ValueArray *array);
diff --git a/clox/src/vm.c b/clox/src/vm.c
index 381c8c0..df9f490 100644
--- a/clox/src/vm.c
+++ b/clox/src/vm.c
@@ -39,6 +39,10 @@ Value pop() {
static Value peek(int distance) { return vm.stackTop[-1 - distance]; }
+static bool isFalsey(Value value) {
+ return IS_NIL(value) || (IS_BOOL(value) && !AS_BOOL(value));
+}
+
static InterpretResult run() {
#define READ_BYTE() (*vm.ip++)
#define READ_CONSTANT() (vm.chunk->constants.values[READ_BYTE()])
@@ -71,6 +75,27 @@ static InterpretResult run() {
push(constant);
break;
}
+ case OP_NIL:
+ push(NIL_VAL);
+ break;
+ case OP_TRUE:
+ push(BOOL_VAL(true));
+ break;
+ case OP_FALSE:
+ push(BOOL_VAL(false));
+ break;
+ case OP_EQUAL: {
+ Value b = pop();
+ Value a = pop();
+ push(BOOL_VAL(valuesEqual(a, b)));
+ break;
+ }
+ case OP_GREATER:
+ BINARY_OP(BOOL_VAL, >);
+ break;
+ case OP_LESS:
+ BINARY_OP(BOOL_VAL, <);
+ break;
case OP_ADD:
BINARY_OP(NUMBER_VAL, +);
break;
@@ -83,6 +108,9 @@ static InterpretResult run() {
case OP_DIVIDE:
BINARY_OP(NUMBER_VAL, /);
break;
+ case OP_NOT:
+ push(BOOL_VAL(isFalsey(pop())));
+ break;
case OP_NEGATE:
if (!IS_NUMBER(peek(0))) {
runtimeError("Operand must be a number.");