From 81d5a545cf977da22b9df0e4da3337c31a01a9f2 Mon Sep 17 00:00:00 2001 From: = <=> Date: Thu, 28 May 2020 15:28:28 +0100 Subject: [PATCH] Some new list functions and better error handling New list functions include (append) (at) (rest) and (reverse). Single quotes now supported for strings. --- src/env.c | 10 ++++-- src/object.c | 24 ++++++++++++--- src/object.h | 7 +++-- src/pebblisp.c | 84 +++++++++++++++++++++++++++++++++++++++++--------- src/pebblisp.h | 4 +++ src/tokens.c | 5 +-- 6 files changed, 109 insertions(+), 25 deletions(-) diff --git a/src/env.c b/src/env.c index 104fd07..c909557 100644 --- a/src/env.c +++ b/src/env.c @@ -28,7 +28,7 @@ Object fetchFromEnvironment(const char *name, struct Environment *env) debugObj(&env->objects[i]); if(strcmp(name, env->strings[i]) == 0) { printd("Returning!\n"); - return env->objects[i]; + return cloneObject(env->objects[i]); } } @@ -191,10 +191,16 @@ struct Environment defaultEnv() addFunc("=", &equ, &e); addFunc(">", >h, &e); addFunc("<", <h, &e); - addFunc("len", &len, &e); + addFunc("cat", &catObjects, &e); addFunc("fil", &filter, &e); + addFunc("len", &len, &e); + addFunc("ap", &append, &e); + addFunc("at", &at, &e); + addFunc("rest", &rest, &e); + addFunc("rev", &reverse, &e); + int i = 0; while(codes[i]) { parseEval(codes[i++], &e); diff --git a/src/object.c b/src/object.c index bd02a2f..ad2952e 100644 --- a/src/object.c +++ b/src/object.c @@ -33,7 +33,13 @@ int listLength(const Object *listObj) } Object len(Object obj1, Object o_ignore, struct Environment *e_ignore) - { return numberObject(listLength(&obj1)); } +{ + Object o = numberObject(listLength(&obj1)); + if(o.number < 0) { + return errorObject(NOT_A_LIST); + } + return o; +} /** * Returns a pointer to the Object at the given index in a given list @@ -207,7 +213,9 @@ static const char *errorText[] = { "LISTS_NOT_SAME_SIZE", "SYMBOLS_CANT_START_WITH_DIGITS", "UNSUPPORTED_NUMBER_TYPE", - "NOT_A_SYMBOL" + "NOT_A_SYMBOL", + "ONLY_ONE_ARGUMENT", + "NOT_A_LIST" }; /** @@ -285,7 +293,11 @@ char* stringObj(char *dest, const Object *obj) stringList(dest, obj); break; case TYPE_ERROR: + #ifdef STANDALONE + snprintf(dest, RESULT_LENGTH, "%s", errorText[(int)(obj->err)]); + #else snprintf(dest, RESULT_LENGTH, "E%d", obj->err); + #endif break; case TYPE_FUNC: case TYPE_LAMBDA: @@ -352,7 +364,6 @@ void _printObj(const Object *obj, int newline) printf("%s\n", temp); else printf("%s", temp); - printErr(obj); } /** @@ -361,7 +372,7 @@ void _printObj(const Object *obj, int newline) * 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) +inline void printObj(const Object *obj) { _printObj(obj, 1); } @@ -661,6 +672,11 @@ inline Object constructLambda(const Object *params, const Object *body) return o; } +inline int isError(const Object obj, const enum errorCode err) +{ + return obj.type == TYPE_ERROR && obj.err == err; +} + inline Object errorObject(enum errorCode err) { Object o = newObject(TYPE_ERROR); diff --git a/src/object.h b/src/object.h index b442ab8..46b64f5 100644 --- a/src/object.h +++ b/src/object.h @@ -17,8 +17,6 @@ #define P1 POINTER #define P2 _element2 -#define SKIP_FIRST() if(_element == _list->list) {continue;} - enum errorCode { MISMATCHED_PARENS, BAD_LIST_OF_SYMBOL_STRINGS, @@ -36,7 +34,9 @@ enum errorCode { LISTS_NOT_SAME_SIZE, SYMBOLS_CANT_START_WITH_DIGITS, UNSUPPORTED_NUMBER_TYPE, - NOT_A_SYMBOL + NOT_A_SYMBOL, + ONLY_ONE_ARGUMENT, + NOT_A_LIST }; #define MALLOC_FLAG 64 @@ -101,6 +101,7 @@ void appendList(Object *dest, const Object *src); int isStringy(const Object test); int isValidType(const Object test); +int isError(const Object obj, const enum errorCode err); Object cloneList(const Object src); Object cloneString(Object obj); diff --git a/src/pebblisp.c b/src/pebblisp.c index fd4128d..6ebab27 100644 --- a/src/pebblisp.c +++ b/src/pebblisp.c @@ -40,7 +40,7 @@ Object evalMapArgs(const Object *argForms, struct Environment *env) if(!argForms) return errorObject(NULL_MAP_ARGS); - const Object lambda = eval(argForms, env); + Object lambda = eval(argForms, env); const Object *inputList = argForms->forward; if(lambda.type != TYPE_LAMBDA || inputList->type != TYPE_LIST) @@ -61,6 +61,7 @@ Object evalMapArgs(const Object *argForms, struct Environment *env) deleteEnv(&newEnv); cleanObject(&tempList); } + cleanObject(&lambda); return list; } @@ -130,18 +131,21 @@ Object eval(const Object *obj, struct Environment *env) eval_forms(rest, obj, env); Object func_eval = rest[0]; - for(int i = 1; i < length; i++) { - Object toClean = func_eval; - func_eval = first_eval.func(func_eval, rest[i], env); - //if(i != length - 1) - cleanObject(&toClean); - cleanObject(&rest[i]); + if(length == 1) { + func_eval = first_eval.func( + func_eval, errorObject(ONLY_ONE_ARGUMENT), env); + if(isError(func_eval, ONLY_ONE_ARGUMENT)) // Consider it a partial function + return cloneObject(*obj); + } else { + for(int i = 1; i < length; i++) { + Object toClean = func_eval; + func_eval = first_eval.func(func_eval, rest[i], env); + //if(i != length - 1) + cleanObject(&toClean); + cleanObject(&rest[i]); + } } - // Consider the object a partial function - if(length == 1) - return cloneObject(*obj); - return func_eval; } else if (first_eval.type == TYPE_LAMBDA) { @@ -149,6 +153,7 @@ Object eval(const Object *obj, struct Environment *env) envForLambda(&first_eval.lambda->params, first_form->forward, env); Object ret = eval(&first_eval.lambda->body, &newEnv); deleteEnv(&newEnv); + cleanObject(&first_eval); return ret; } else { @@ -233,6 +238,9 @@ Object _basicOp(const Object *obj1, const Object *obj2, const char op, Object basicOp(const Object *obj1, const Object *obj2, const char op, struct Environment *env) { + if(isError(*obj2, ONLY_ONE_ARGUMENT)) + return *obj2; + int lists = (obj1->type == TYPE_LIST) + (obj2->type == TYPE_LIST); if(lists == 0) { return _basicOp(obj1, obj2, op, env); @@ -285,14 +293,56 @@ Object filter(Object obj1, Object obj2, struct Environment *env) FOR_POINTER_IN_LIST(filteringList) { Object conditional = cloneObject(obj1); nf_addToList(&conditional, *POINTER); // cloneObject()? - conditional = eval(&conditional, env); - if(conditional.number == 1) { + Object result = eval(&conditional, env); + cleanObject(&conditional); + if(result.number == 1) { nf_addToList(&filteredList, *POINTER); } } return filteredList; } +Object append(Object list, Object newElement, struct Environment *env) +{ + Object newList = cloneObject(list); + nf_addToList(&newList, newElement); + return newList; +} + +Object at(Object index, Object list, struct Environment *env) +{ + return cloneObject(*itemAt(&list, index.number)); +} + +Object rest(Object list, Object ignore, struct Environment *env) +{ + Object ret = listObject(); + Object *l = &list; + FOR_POINTER_IN_LIST(l) { + if(POINTER == l->list) + continue; + nf_addToList(&ret, *POINTER); + } + return ret; +} + +Object reverse(Object _list, Object ignore, struct Environment *ignore2) +{ + const Object *list = &_list; + Object rev = listObject(); + + Object *tail = NULL; + FOR_POINTER_IN_LIST(list) { + Object *oldTail = tail; + allocObject(&tail, cloneObject(*POINTER)); + if(oldTail) + tail->forward = oldTail; + } + + rev.list = tail; + return rev; +} + void copySlice(char * dest, struct Slice *src) { if(!dest || !src) @@ -343,6 +393,8 @@ Result readSeq(struct Slice *tokens) return result(res, rest); } Result r = parse(tokens); + if(r.obj.type == TYPE_ERROR) + return r; nf_addToList(&res, cloneObject(r.obj)); tokens = r.slices; cleanObject(&r.obj); @@ -377,7 +429,7 @@ Object parseAtom(struct Slice *s) } else if (s->length == 1 && (s->text[0] == 'F' || s->text[0] == 'f')) { return boolObject(0); - } else if (s->text[0] == '"') { + } else if (s->text[0] == '"' || s->text[0] == '\'') { return objFromSlice(s->text, s->length); } else { return symFromSlice(s->text, s->length); @@ -411,6 +463,8 @@ Object parseEval(const char *input, struct Environment *env) struct Slice *tok = tokens; if(tok[i].text[0] != '(') { Object parsed = parse(tok).obj; + if(parsed.type == TYPE_ERROR) + return parsed; obj = eval(&parsed, env); cleanObject(&parsed); } else { @@ -422,6 +476,8 @@ Object parseEval(const char *input, struct Environment *env) if(parens == 0) { cleanObject(&obj); Object parsed = parse(tok).obj; + if(parsed.type == TYPE_ERROR) + return parsed; tok = &tok[i + 1]; i = -1; //printObj(&parsed); diff --git a/src/pebblisp.h b/src/pebblisp.h index 294c06b..65a3753 100644 --- a/src/pebblisp.h +++ b/src/pebblisp.h @@ -50,5 +50,9 @@ BASIC_OP(gth); BASIC_OP(lth); #undef BASIC_OP Object catObjects(const Object obj1, const Object obj2, struct Environment *env); Object filter(Object obj1, Object obj2, struct Environment *env); +Object append(Object list, Object newElement, struct Environment *env); +Object at(Object index, Object list, struct Environment *env); +Object rest(Object list, Object ignore, struct Environment *env); +Object reverse(Object _list, Object ignore, struct Environment *ignore2); #endif diff --git a/src/tokens.c b/src/tokens.c index b3ada0e..8e6b8bd 100644 --- a/src/tokens.c +++ b/src/tokens.c @@ -79,8 +79,9 @@ struct Slice *nf_tokenize(const char *input) if(isSingle(input[i])) { i++; - } else if(input[i] == '"') { - while(input[++i] != '"' && input[i] != '\0') { + } else if(input[i] == '"' || input[i] == '\'') { + const char quote = input[i]; + while(input[++i] != quote && input[i] != '\0') { l++; } i++;