Files
clox/interpreter.c
T

225 lines
6.5 KiB
C

#include "interpreter.h"
#include "token.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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);
double computed_value;
switch(expression->expression.Binary.op->type) {
case Greater:
computed_value = left->value.number > right->value.number;
FreeObject(left);
FreeObject(right);
return CreateObject(&computed_value, TRUE);
//return left > right;
case Greater_Equal:
computed_value = left->value.number >= right->value.number;
FreeObject(left);
FreeObject(right);
return CreateObject(&computed_value, TRUE);
//return left >= right;
case Less:
computed_value = left->value.number < right->value.number;
FreeObject(left);
FreeObject(right);
return CreateObject(&computed_value, TRUE);
//return left < right;
case Less_Equal:
computed_value = left->value.number <= right->value.number;
FreeObject(left);
FreeObject(right);
return CreateObject(&computed_value, TRUE);
//return left <= right;
case Bang_Equal:
computed_value = !IsEqual(left, right);
FreeObject(left);
FreeObject(right);
return CreateObject(&computed_value, TRUE);
//return !IsEqual(left, right);
case Equal_Equal:
computed_value = IsEqual(left, right);
FreeObject(left);
FreeObject(right);
return CreateObject(&computed_value, TRUE);
//return IsEqual(left, right);
case Minus:
left->value.number -= right->value.number;
FreeObject(right);
return left;
//return 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;
default:
FreeObject(left);
FreeObject(right);
return NULL; //Should be unreachable.
}
FreeObject(left);
FreeObject(right);
// Unreachable
return NULL;
}
Object* VisitUnaryExpression(Expr* expression) {
Object* right = Evaluate(expression);
Object* c;
double computed_value;
switch (expression->expression.Unary.op->type) {
case Minus:
computed_value = -right->value.number;
FreeObject(right);
c = CreateObject(&computed_value, Number);
//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 c;
case Bang:
computed_value = !IsTruthy(right);
FreeObject(right);
c = CreateObject(&computed_value, TRUE); //TRUE or FALSE, doesn't matter here since it becomes INS_BOOLEAN in the end.
return c;
default:
FreeObject(right);
return NULL; //Should be unreachable.
}
FreeObject(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 = *(double*) value;
break;
default:
if (value) {
int length = strlen(value);
object->instance = INS_STRING;
object->value.string = calloc(length + 1, sizeof(char));
strncpy(object->value.string, value, length);
} else object->instance = INS_NULL; //TODO: this is most likely an error, but we'll ignore that for now.
}
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;
a->value.string[a_length + b_length] = '\0';
strncat(a->value.string, b->value.string, b_length);
return 1;
}
int IsTruthy(Object* object) {
if (!object || object->instance == INS_NULL) return 0;
if (object->instance == INS_BOOLEAN) return object->value.boolean;
return 1;
}
int IsEqual(Object* a, Object* b) {
if (a->instance == INS_NULL && b->instance == INS_NULL) return 1;
if (a->instance == INS_NULL) return 0;
if (b->instance == INS_DOUBLE && b->instance == INS_DOUBLE) {
return a->value.number == b->value.number;
}
if (a->instance == INS_STRING && b->instance == INS_STRING) {
return strcmp(a->value.string, b->value.string) == 0;
}
return 0;
}