#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; } void* VisitGroupingExpression(Expr* expression) { return Evaluate(expression); } 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: return left > right; case Greater_Equal: return left >= right; case Less: return left < right; case Less_Equal: return left <= right; case Minus: 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: left->value.number /= right->value.number; FreeObject(right); return left; //return *((double*)left) / *((double*)right); case Star: left->value.number *= right->value.number; FreeObject(right); return left; //return *((double*)left) * *((double*)right); case Plus: 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; } } break; } FreeObject(left); FreeObject(right); // Unreachable return NULL; } Object* VisitUnaryExpression(Expr* expression) { void* right = Evaluate(expression); switch (expression->type) { case Minus: //right needs to be negated, but that kind of introduces a //memory leak since we can't really change it, what with the //whole "const void*" thing and all. return right; case Bang: return !IsTruthy(right); } return NULL; //Should be unreachable. } Object* Evaluate(Expr* expression) { //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; return 1; } int IsEqual(Object* a, Object* b) { if (a->instance == NIL && b->instance == NIL) return 1; if (a->instance == NIL) return 0; if (b->instance == Number && b->instance == Number) { return a->value.number == b->value.number; } if (a->instance == String && b->instance == String) { return strcmp(a->value.string, b->value.string) == 0; } return 0; }