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
+105 -17
View File
@@ -1,9 +1,15 @@
#include "interpreter.h"
#include "token.h"
#include <errno.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;
@@ -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;
+9 -2
View File
@@ -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