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:
+105
-17
@@ -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 (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;
|
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
@@ -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
|
||||||
Reference in New Issue
Block a user