diff --git a/src/object.c b/src/object.c index fbdfe09..ef1c076 100644 --- a/src/object.c +++ b/src/object.c @@ -52,23 +52,87 @@ Object *tail(const Object *listObj) return t; } +/** + * Checks if a given object is empty + * BOOL, NUMBER, and ERROR types return true only when 0 + * LIST, LAMBDA, and FUNC types return true only when NULL + * SYMBOL returns true only when it begins with a nullchar + * Returns false if obj is NULL + */ +inline int isEmpty(const Object *obj) +{ + if(obj == NULL) + return 0; + + switch(obj->type) { + case TYPE_NUMBER: + case TYPE_BOOL: + return obj->number == 0; + case TYPE_LIST: + return obj->list == NULL; + case TYPE_LAMBDA: + return obj->lambda == NULL; + case TYPE_SYMBOL: + return obj->name[0] == '\0'; + case TYPE_FUNC: + return obj->func == NULL; + case TYPE_ERROR: + return obj->err == 0; + default: + return 0; + } +} + +void allocObject(Object **spot, const Object src) +{ + *spot = malloc(sizeof(struct Object)); + **spot = src; + (*spot)->forward = NULL; +} + +// Insert `src` into list `dest` before index `ind` +// Adds to the end if the index is too high. +void insertIntoList(Object *dest, int ind, const Object src) +{ + // Only work with non-null list types + if(!dest || dest->type != TYPE_LIST || ind < 0) + return; + + if(isEmpty(dest)) { + allocObject(&dest->list, src); + return; + } + + // TODO Check for off-by-one errors + // ensure pointers connect old and new + Object *march = dest->list; + for(int i = 1; i < ind; i++) { + if(march->forward == NULL) { + allocObject(&march->forward, src); + return; + } + march = march->forward; + } + + // Save and re-apply current march->forward + Object *oldForward = march->forward; + allocObject(&march->forward, src); + march->forward->forward = oldForward; +} + // Adds an object to the end of a list object void addToList(Object *dest, const Object src) { if(!dest || dest->type != TYPE_LIST) return; - if(dest->list == NULL) { - dest->list = malloc(sizeof(struct Object)); - *dest->list = src; - dest->list->forward = NULL; + if(isEmpty(dest)) { + allocObject(&dest->list, src); return; } Object *end = tail(dest); - end->forward = malloc(sizeof(struct Object)); - *end->forward = src; - end->forward->forward = NULL; + allocObject(&end->forward, src); } void printErr(const Object *obj) @@ -200,6 +264,11 @@ void deleteList(const Object *dest) } } +/** + * Copies all items from `src` to `dest` + * Does nothing if either is NULL, or neither are lists + * First deletes all items from `dest` + */ void copyList(Object *dest, const Object *src) { if(!dest || !src || dest->type != TYPE_LIST || src->type != TYPE_LIST) @@ -213,6 +282,7 @@ void copyList(Object *dest, const Object *src) } } +// Returns a basic object with NULL forward and the given `type` inline Object newObject(Type type) { Object no; @@ -221,6 +291,7 @@ inline Object newObject(Type type) return no; } +// Returns an empty list object inline Object listObject() { Object list = newObject(TYPE_LIST); @@ -235,10 +306,16 @@ inline Object numberObject(int num) return o; } +inline Object boolObject(int b) +{ + Object o = newObject(TYPE_BOOL); + o.number = b; + return o; +} + inline Object symbolObject() { - Object o = newObject(TYPE_SYMBOL); - return o; + return newObject(TYPE_SYMBOL); } inline Object lambdaObject() diff --git a/src/object.h b/src/object.h index 6bb5c93..ad2dc14 100644 --- a/src/object.h +++ b/src/object.h @@ -13,7 +13,8 @@ enum errorCode { NULL_PARSE, NULL_LAMBDA_LIST, LAMBDA_ARGS_NOT_LIST, - DID_NOT_FIND_SYMBOL + DID_NOT_FIND_SYMBOL, + UNEXPECTED_FORM }; #ifdef STANDALONE @@ -25,7 +26,8 @@ enum errorCode { "NULL_PARSE", "NULL_LAMBDA_LIST", "LAMBDA_ARGS_NOT_LIST", - "DID_NOT_FIND_SYMBOL" + "DID_NOT_FIND_SYMBOL", + "UNEXPECTED_FORM" }; #endif @@ -50,12 +52,12 @@ struct Object { Object *list; char name[MAX_TOK_LEN]; Object (*func)(Object, Object); - struct Lambda *lambda; // Maybe better as not a pointer + struct Lambda *lambda; // Maybe better as not a pointer? enum errorCode err; }; }; -// Maybe better as pointers +// Maybe better as pointers? struct Lambda { Object params; Object body; @@ -66,6 +68,7 @@ void printList(const Object *list); void printObj(const Object *obj); void debugObj(const Object *obj); +int isEmpty(const Object *obj); Object *tail(const Object *listObj); void addToList(Object *dest, Object src); void deleteList(const Object *dest); @@ -74,12 +77,15 @@ Object *itemAt(const Object *listObj, int n); void copyList(Object *dest, const Object *src); void cleanObject(Object *target); +void allocObject(Object **spot, const Object src); Object newObject(Type type); Object listObject(); -Object numberObject(int num); Object lambdaObject(); -Object constructLambda(const Object *params, const Object *body); +Object symbolObject(); +Object boolObject(int b); +Object numberObject(int num); Object errorObject(enum errorCode err); +Object constructLambda(const Object *params, const Object *body); #endif diff --git a/src/pebblisp.c b/src/pebblisp.c index 736a83f..679aaa2 100644 --- a/src/pebblisp.c +++ b/src/pebblisp.c @@ -80,26 +80,25 @@ Result readSeq(struct Slice *tokens) Object parseAtom(struct Slice *s) { - Object o; - o.forward = NULL; if(isDigit(s->text[0])) { - o.type = TYPE_NUMBER; - o.number = 0; + int num = 0; for(int i = 0; i < s->length; i++) { - o.number *= 10; - o.number += s->text[i] - '0'; + num *= 10; + num += s->text[i] - '0'; } + return numberObject(num); + } else if (s->text[0] == 'T' && s->text[1] == '\0') { - o.type = TYPE_BOOL; - o.number = 1; + return boolObject(1); + } else if (s->text[0] == 'F' && s->text[1] == '\0') { - o.type = TYPE_BOOL; - o.number = 0; + return boolObject(0); + } else { - o.type = TYPE_SYMBOL; + Object o = symbolObject(); copySlice(o.name, s); + return o; } - return o; } Object evalDefArgs(const Object *arg_forms, struct Environment *env) @@ -242,12 +241,8 @@ Object eval(const Object *obj, struct Environment *env) } } case TYPE_LAMBDA: - { - Object o; - o.type = TYPE_ERROR; - printf("UNEXPECTED FORM\n"); - return o; - } + return errorObject(UNEXPECTED_FORM); + default: ; } @@ -292,50 +287,33 @@ void printEnv(struct Environment *env) Object basicOp(Object *obj1, Object *obj2, const char op) { - Object o; - o.forward = NULL; - - o.type = TYPE_NUMBER; const int n1 = obj1->number; const int n2 = obj2->number; switch(op){ case '+': - o.number = n1 + n2; - return o; + return numberObject(n1 + n2); case '-': - o.number = n1 - n2; - return o; + return numberObject(n1 - n2); case '*': - o.number = n1 * n2; - return o; + return numberObject(n1 * n2); case '/': - o.number = n1 / n2; - return o; - } + return numberObject(n1 / n2); - o.type = TYPE_BOOL; - switch(op) { case '=': - o.number = n1 == n2; - return o; + return boolObject(n1 == n2); case '>': - o.number = n1 > n2; - return o; + return boolObject(n1 > n2); case '<': - o.number = n1 < n2; - return o; + return boolObject(n1 < n2); } - o = *obj1; - return o; + return *obj1; } #define bopf(_name, _char) \ Object _name(Object obj1, Object obj2) \ -{ \ - return basicOp(&obj1, &obj2, _char); \ -} + { return basicOp(&obj1, &obj2, _char); } bopf(add, '+'); bopf(sub, '-'); @@ -405,9 +383,6 @@ Object parseEval(const char *input, struct Environment *env) } #endif Object parsed = parse(tokens).obj; - // printf("PARSEEVAL() PRINTLIST():\n"); - // debugObject(&parsed); - // printf("end PARSEEVAL() PRINTLIST():\n\n"); free(tokens); return eval(&parsed, env); }