diff --git a/interpreter.c b/interpreter.c index 480871e..67cabc4 100644 --- a/interpreter.c +++ b/interpreter.c @@ -1,9 +1,15 @@ #include "interpreter.h" #include "token.h" +#include +#include +#include Object* Evaluate(Expr*); +Object* CreateObject(void*, TokenType); +void FreeObject(Object*); int IsTruthy(Object*); int IsEqual(Object*, Object*); +int ConcatStringObject(Object*, const Object*); const void* VisitLiteralExpression(Expr* expression) { return expression->expression.Literal->literal; @@ -13,9 +19,9 @@ void* VisitGroupingExpression(Expr* expression) { return Evaluate(expression); } -void* VisitBinaryExpression(Expr* expression) { - void* left = Evaluate(expression->expression.Binary.left); - void* right = Evaluate(expression->expression.Binary.right); +Object* VisitBinaryExpression(Expr* expression) { + Object* left = Evaluate(expression->expression.Binary.left); + Object* right = Evaluate(expression->expression.Binary.right); switch(expression->expression.Binary.op->type) { case Greater: @@ -27,30 +33,50 @@ void* VisitBinaryExpression(Expr* expression) { case Less_Equal: return left <= right; case Minus: - return left - right; + left->value.number -= right->value.number; + FreeObject(right); + return left; + //return left - right; case Bang_Equal: return !IsEqual(left, right); case Equal_Equal: return IsEqual(left, right); case Slash: - return *((double*)left) / *((double*)right); + left->value.number /= right->value.number; + FreeObject(right); + return left; + //return *((double*)left) / *((double*)right); case Star: - return *((double*)left) * *((double*)right); + left->value.number *= right->value.number; + FreeObject(right); + return left; + //return *((double*)left) * *((double*)right); case Plus: - if (((Token*)left)->type == Number && ((Token*)right)->type == Number) { - return left + right; - } + if (left->instance == INS_DOUBLE && right->instance == INS_DOUBLE) { + left->value.number += right->value.number; + FreeObject(right); + + return left; + } + + if (left->instance == INS_STRING && right->instance == INS_STRING) { + if (ConcatStringObject(left, right)) { + FreeObject(right); + + return left; + } + } - if (((Token*)left)->type == String && ((Token*)right)->type == String) { - return NULL; //String concat - } break; } + + FreeObject(left); + FreeObject(right); // Unreachable return NULL; } -void* VisitUnaryExpression(Expr* expression) { +Object* VisitUnaryExpression(Expr* expression) { void* right = Evaluate(expression); switch (expression->type) { @@ -67,11 +93,75 @@ void* VisitUnaryExpression(Expr* expression) { } Object* Evaluate(Expr* expression) { - //accept + //accept -> calls Visitor functions by type 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) { + if (!object || object->instance == NIL) 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) { - int result = strcmp(a->value.string, b->value.string); - - return result == 0; + return strcmp(a->value.string, b->value.string) == 0; } return 0; diff --git a/interpreter.h b/interpreter.h index 089476a..fbbfb46 100644 --- a/interpreter.h +++ b/interpreter.h @@ -4,8 +4,15 @@ #include "expr.h" #include "token.h" +typedef enum { + INS_STRING, + INS_DOUBLE, + INS_BOOLEAN, + INS_NULL +} ObjectInstanceType; + typedef struct Object { - TokenType instance; + ObjectInstanceType instance; union { char* string; double number; @@ -15,6 +22,6 @@ typedef struct Object { const void* VisitLiteralExpression(Expr*); void* VisitGroupingExpression(Expr*); -void* VisitBinaryExpression(Expr*); +Object* VisitBinaryExpression(Expr*); #endif \ No newline at end of file