From c97cbe850c575377c9ac7ff7c1e439c1c366bce7 Mon Sep 17 00:00:00 2001 From: = <=> Date: Sat, 16 May 2020 15:46:19 +0100 Subject: [PATCH] Ensure plain lists have elements evaluated Add relevant tests. Add new doc comments. Some code shifting. Tests pass. Valgrind is clean. --- src/object.c | 131 +++++++++++++++++++++++++++++++++++++++++-------- src/object.h | 2 + src/pebblisp.c | 26 ++++------ src/tests.sh | 4 ++ 4 files changed, 125 insertions(+), 38 deletions(-) diff --git a/src/object.c b/src/object.c index e29b355..f737dd3 100644 --- a/src/object.c +++ b/src/object.c @@ -142,17 +142,17 @@ void insertIntoList(Object *dest, int ind, const Object src) return; } - // The objects to preceed and follow the new one + // The Objects to preceed and follow the new one Object *beforeNew = itemAt(dest, ind - 1); Object *afterNew = beforeNew->forward; - // Replace the `before` object's pointer + // Replace the `before` Object's pointer allocObject(&beforeNew->forward, src); beforeNew->forward->forward = afterNew; } /** - * Replace an object in a list at a given index with a given object + * Replace an Object in a list at a given index with a given Object * Attempts to clean the replaced Object before adding the new one * Immediately returns if `list` is NULL or not a list type * @param list The list Object to replace an element of @@ -189,6 +189,11 @@ void nf_addToList(Object *dest, const Object src) allocObject(&tail(dest)->forward, src); } +/** + * Prints out the error of a given error Object + * Doesn't print anything if `obj` is NULL or not an error type + * @param obj A pointer to the Object to print + */ void printErr(const Object *obj) { if(!obj || obj->type != TYPE_ERROR) @@ -197,8 +202,18 @@ void printErr(const Object *obj) printf("%s\n", errorText[(int)(obj->err)]); } +/** + * Creates a string from a given list Object + * Blocks out with parens + * Returns immediately if `dest` is NULL, or `obj` is not a list type + * @param dest The string to copy the list text into + * @param obj The list Object to make a string from + */ void stringList(char *dest, const Object *obj) { + if(!dest || obj->type != TYPE_LIST) + return; + dest[0] = '('; dest[1] = '\0'; @@ -211,7 +226,22 @@ void stringList(char *dest, const Object *obj) strcat(dest, " )"); } -// Puts a string version of the given object into a given string +/** + * Creates a string from a given Object + * Returns NULL if either param is NULL + * + * Prints + * -# Numbers without spaces + * -# Symbols as their name + * -# Bools as 'T' or 'F' + * -# Strings as their string value + * -# Lists using stringList() + * -# Errors as the integer value, prepended with 'E' + * -# Otherwise as the raw number, prepended with 'X' + * + * @param dest The string to copy the list text into + * @param obj The list Object to make a string from + */ char* stringObj(char *dest, const Object *obj) { if(!dest || !obj) @@ -225,19 +255,23 @@ char* stringObj(char *dest, const Object *obj) snprintf(dest, RESULT_LENGTH, "%s", obj->name); } else if(t == TYPE_BOOL) { snprintf(dest, RESULT_LENGTH, "%s", obj->number ? "T" : "F"); - } else if(t == TYPE_ERROR) { - snprintf(dest, RESULT_LENGTH, "E%d", obj->err); } else if(t == TYPE_STRING) { snprintf(dest, RESULT_LENGTH, "%s", obj->string); } else if(t == TYPE_LIST) { stringList(dest, obj); + } else if(t == TYPE_ERROR) { + snprintf(dest, RESULT_LENGTH, "E%d", obj->err); } else { - snprintf(dest, RESULT_LENGTH, "%d", obj->number); + snprintf(dest, RESULT_LENGTH, "X%d", obj->number); } return dest; } +/** + * Prints a given Object only if the DEBUG flag is set + * @param obj The Object to debug + */ void debugObj(const Object *obj) { #ifdef DEBUG @@ -279,7 +313,12 @@ void _printObj(const Object *obj, int newline) printErr(obj); } -// Prints the given object +/** + * Prints the given Object and a newline. + * Uses stringObj() to create the printed string + * If the DEBUG flag is set, the Object's type will be printed first + * @param obj The Object to print + */ void printObj(const Object *obj) { _printObj(obj, 1); @@ -298,40 +337,60 @@ void _printList(const Object *list, int newline) printf("\n"); } +/** + * Prints each Object in a given list, surrounded by parentheses + * @param list The list Object to print + */ void printList(const Object *list) { _printList(list, 1); } +/** + * Performs appropriate free() on a given Object and NULLs its ->forward + * Returns immediately if param is NULL + * + * Strings: The Object's ->string is freed and NULLed + * Lists: deleteList() is called on the Object (may recurse) + * Lambdas: The body and params are cleaned, and the lambda itself is freed + * + * @param target The object to clean + */ void cleanObject(Object *target) { if(target == NULL) return; const Type t = target->type; - if(t == TYPE_LAMBDA) { + if(t == TYPE_STRING) { + free(target->string); + target->string = NULL; + } else if(t == TYPE_LIST) { + deleteList(target); + } else if(t == TYPE_LAMBDA) { cleanObject(&target->lambda->params); cleanObject(&target->lambda->body); free(target->lambda); - } else if(t == TYPE_LIST) { - deleteList(target); - } else if(t == TYPE_STRING) { - // TODO Why does this break? - // Probably multiple objects referencing the same string - - free(target->string); - target->string = NULL; } target->forward = NULL; } +/** + * Print the given object with a newline, then clean it + * @param target The object to print and clean + */ void printAndClean(Object *target) { printObj(target); cleanObject(target); } -// Frees all objects in a list +/** + * Frees all objects in a given list + * Runs cleanObject() on every item in the list (may recurse) + * + * @param dest The list object to clean up + */ void deleteList(Object *dest) { if(!dest) @@ -382,20 +441,36 @@ void _copyList(Object *dest, const Object *src, int delete) /** * Does a deep copy of all items from `src` to `dest` - * Does nothing if either is NULL, or not a list type + * Does nothing if either param is NULL, or not a list type * Does a shallow delete of items from `dest` before copying + * May recurse into lists in the list + * + * @param dest The list to copy to + * @param src The list to copy from */ void copyList(Object *dest, const Object *src) { _copyList(dest, src, 1); } +/** + * Does a deep copy of all items from `src` to the end of `dest` + * Does nothing if either param is NULL, or not a list type + * May recurse into lists in the list + * + * @param dest The list to copy to + * @param src The list to copy from + */ void appendList(Object *dest, const Object *src) { _copyList(dest, src, 0); } -// Returns a basic object with NULL forward and the given `type` +/** + * Returns a basic Object with NULL forward and the given type + * @param type The type of Object to create + * @return The created Object + */ inline Object newObject(Type type) { Object no; @@ -404,7 +479,7 @@ inline Object newObject(Type type) return no; } -// Returns an empty list object +// Returns an empty list Object inline Object listObject() { Object list = newObject(TYPE_LIST); @@ -412,6 +487,7 @@ inline Object listObject() return list; } +// Returns a list Object starting with the given Object inline Object startList(const Object start) { Object list = listObject(); @@ -419,6 +495,19 @@ inline Object startList(const Object start) return list; } +// Returns an Object with a deep copy of the given Object +inline Object cloneList(const Object src) +{ + Object list = listObject(); + copyList(&list, &src); + return list; +} + +inline Object cloneObject(const Object src) +{ + return src.type == TYPE_LIST? cloneList(src) : src; +} + inline Object numberObject(int num) { Object o = newObject(TYPE_NUMBER); diff --git a/src/object.h b/src/object.h index 16d9e2b..1b3a78d 100644 --- a/src/object.h +++ b/src/object.h @@ -118,6 +118,8 @@ void appendList(Object *dest, const Object *src); Object newObject(Type type); Object listObject(); Object startList(const Object start); +Object cloneList(const Object src); +Object cloneObject(const Object src); Object lambdaObject(); Object symbolObject(); Object objFromSlice(const char *string, int len); diff --git a/src/pebblisp.c b/src/pebblisp.c index dbe94b3..5e0391d 100644 --- a/src/pebblisp.c +++ b/src/pebblisp.c @@ -50,17 +50,11 @@ Object evalMapArgs(const Object *arg_forms, struct Environment *env) FOR_POINTER_IN_LIST(inputList) { // Create a new list for each element, // since lambda evaluation looks for a list - Object tempList; - if(POINTER->type == TYPE_LIST) { - Object tl = listObject(); - copyList(&tl, POINTER); - tempList = startList(tl); - } else { - tempList = startList(*POINTER); - } + Object tempList = startList(cloneObject(*POINTER)); + + Object *params = &lambda.lambda->params; + struct Environment newEnv = envForLambda(params, &tempList, env); - struct Environment newEnv = - envForLambda(&lambda.lambda->params, &tempList, env); // Add the lambda evaluation to the list nf_addToList(&list, eval(&lambda.lambda->body, &newEnv)); deleteEnv(&newEnv); @@ -155,10 +149,11 @@ Object eval(const Object *obj, struct Environment *env) return ret; } else { - Object newList = listObject(); - copyList(&newList, obj); - return newList; - //return *obj; + Object list = listObject(); + FOR_POINTER_IN_LIST(obj) { + nf_addToList(&list, eval(POINTER, env)); + } + return list; } } case TYPE_LAMBDA: @@ -423,12 +418,9 @@ int main(int argc, const char* argv[]) if(argc >= 2) { Object r = numberObject(0); for(int i = 1; i < argc; i++) { - // cleanObject(&r); r = parseEval(argv[i], &env); printAndClean(&r); } - // printObj(&r); - //printAndClean(&r); } else { repl(&env); } diff --git a/src/tests.sh b/src/tests.sh index 8385a01..888f4f0 100755 --- a/src/tests.sh +++ b/src/tests.sh @@ -58,6 +58,7 @@ check "EmptyCnd" "(if () T F)" "F" # check "EtyLstLt" "(if (()) T F)" "T" echo "" check "RegLists" "(1 2 3 4 5)" "( 1 2 3 4 5 )" +check "MultiTypeList" "(10 20 \"rascals\")" "( 10 20 rascals )" check "EmptyLst" "()" "( )" check "EmptLst2" "( )" "( )" echo "" @@ -82,6 +83,9 @@ check "ImplicitCat" "(+ \"There are \" (* 5 4) \" bonks\")" "There are 20 bonks" # Not recommended check "CatAssocLeft" "(+ 10 20 \" rascals\")" "30 rascals" echo"" +check "EvalElems" "((* 10 10) 7)" "( 100 7 )" +check "Duplicate" "(def dupe (fn (a) (a a a))) (dupe (*10 10))" "( 100 100 100 )" +echo"" if [ "$FAILS" -ne "0" ]; then echo "$FAILS Tests Failed"