More refactoring trying to get this cleaned up while trying to keep it easy(ish) to extend for later chapters. I'll never take namespaces for granted again...

This commit is contained in:
2022-03-09 21:13:52 +00:00
parent e802c57a93
commit f666585f5f
2 changed files with 114 additions and 19 deletions
+103 -15
View File
@@ -1,9 +1,15 @@
#include "interpreter.h" #include "interpreter.h"
#include "token.h" #include "token.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
Object* Evaluate(Expr*); Object* Evaluate(Expr*);
Object* CreateObject(void*, TokenType);
void FreeObject(Object*);
int IsTruthy(Object*); int IsTruthy(Object*);
int IsEqual(Object*, Object*); int IsEqual(Object*, Object*);
int ConcatStringObject(Object*, const Object*);
const void* VisitLiteralExpression(Expr* expression) { const void* VisitLiteralExpression(Expr* expression) {
return expression->expression.Literal->literal; return expression->expression.Literal->literal;
@@ -13,9 +19,9 @@ void* VisitGroupingExpression(Expr* expression) {
return Evaluate(expression); return Evaluate(expression);
} }
void* VisitBinaryExpression(Expr* expression) { Object* VisitBinaryExpression(Expr* expression) {
void* left = Evaluate(expression->expression.Binary.left); Object* left = Evaluate(expression->expression.Binary.left);
void* right = Evaluate(expression->expression.Binary.right); Object* right = Evaluate(expression->expression.Binary.right);
switch(expression->expression.Binary.op->type) { switch(expression->expression.Binary.op->type) {
case Greater: case Greater:
@@ -27,30 +33,50 @@ void* VisitBinaryExpression(Expr* expression) {
case Less_Equal: case Less_Equal:
return left <= right; return left <= right;
case Minus: case Minus:
return left - right; left->value.number -= right->value.number;
FreeObject(right);
return left;
//return left - right;
case Bang_Equal: case Bang_Equal:
return !IsEqual(left, right); return !IsEqual(left, right);
case Equal_Equal: case Equal_Equal:
return IsEqual(left, right); return IsEqual(left, right);
case Slash: case Slash:
return *((double*)left) / *((double*)right); left->value.number /= right->value.number;
FreeObject(right);
return left;
//return *((double*)left) / *((double*)right);
case Star: case Star:
return *((double*)left) * *((double*)right); left->value.number *= right->value.number;
FreeObject(right);
return left;
//return *((double*)left) * *((double*)right);
case Plus: case Plus:
if (((Token*)left)->type == Number && ((Token*)right)->type == Number) { if (left->instance == INS_DOUBLE && right->instance == INS_DOUBLE) {
return left + right; left->value.number += right->value.number;
FreeObject(right);
return left;
} }
if (((Token*)left)->type == String && ((Token*)right)->type == String) { if (left->instance == INS_STRING && right->instance == INS_STRING) {
return NULL; //String concat if (ConcatStringObject(left, right)) {
FreeObject(right);
return left;
} }
}
break; break;
} }
FreeObject(left);
FreeObject(right);
// Unreachable // Unreachable
return NULL; return NULL;
} }
void* VisitUnaryExpression(Expr* expression) { Object* VisitUnaryExpression(Expr* expression) {
void* right = Evaluate(expression); void* right = Evaluate(expression);
switch (expression->type) { switch (expression->type) {
@@ -67,11 +93,75 @@ void* VisitUnaryExpression(Expr* expression) {
} }
Object* Evaluate(Expr* expression) { Object* Evaluate(Expr* expression) {
//accept //accept -> calls Visitor functions by type
return NULL; return NULL;
} }
Object* CreateObject(void* value, TokenType type) {
Object* object = calloc(1, sizeof(Object));
if (!object) {
fprintf(stderr, "Failed to calloc object. %s.\n", strerror(errno));
return NULL;
}
switch(type) {
case NIL:
object->instance = INS_NULL;
break;
case Number:
object->instance = INS_DOUBLE;
object->value.number = *((double*) value);
break;
case TRUE:
case FALSE:
object->instance = INS_BOOLEAN;
object->value.boolean = *((int*) value);
break;
default:
object->instance = INS_STRING;
if (value) {
int length = strlen(value);
object->value.string = calloc(length + 1, sizeof(char));
strncpy(object->value.string, value, length);
}
}
return object;
}
void FreeObject(Object* object) {
if (object->instance == INS_STRING) free(object->value.string);
free(object);
}
int ConcatStringObject(Object* a, const Object* b) {
if (!a || !b) return 0;
if (a->instance != INS_STRING || b->instance != INS_STRING) return 0;
int a_length = strlen(a->value.string);
int b_length = strlen(b->value.string);
char* c;
c = realloc(a->value.string, a_length + b_length + 1);
if (!c) {
fprintf(stderr, "Failed to realloc for object concat. %s.\n", strerror(errno));
return 0;
}
a->value.string = c;
strncat(a->value.string, b->value.string, b_length);
return 1;
}
int IsTruthy(Object* object) { int IsTruthy(Object* object) {
if (!object || object->instance == NIL) return 0; if (!object || object->instance == NIL) return 0;
if (object->instance == TRUE) return 0; if (object->instance == TRUE) return 0;
@@ -87,9 +177,7 @@ int IsEqual(Object* a, Object* b) {
} }
if (a->instance == String && b->instance == String) { if (a->instance == String && b->instance == String) {
int result = strcmp(a->value.string, b->value.string); return strcmp(a->value.string, b->value.string) == 0;
return result == 0;
} }
return 0; return 0;
+9 -2
View File
@@ -4,8 +4,15 @@
#include "expr.h" #include "expr.h"
#include "token.h" #include "token.h"
typedef enum {
INS_STRING,
INS_DOUBLE,
INS_BOOLEAN,
INS_NULL
} ObjectInstanceType;
typedef struct Object { typedef struct Object {
TokenType instance; ObjectInstanceType instance;
union { union {
char* string; char* string;
double number; double number;
@@ -15,6 +22,6 @@ typedef struct Object {
const void* VisitLiteralExpression(Expr*); const void* VisitLiteralExpression(Expr*);
void* VisitGroupingExpression(Expr*); void* VisitGroupingExpression(Expr*);
void* VisitBinaryExpression(Expr*); Object* VisitBinaryExpression(Expr*);
#endif #endif