From d743970b1ada12adcb5d302820ec29a27938c2f1 Mon Sep 17 00:00:00 2001 From: Sage Vaillancourt Date: Wed, 23 Mar 2022 01:00:11 -0400 Subject: [PATCH] Tweak (eval) to accept SLIST arguments. Tweak implicit-cat detection. Explicit empty-string notation in test display. A couple more tests. --- src/env.c | 15 +++++-- src/object.c | 5 +++ src/object.h | 2 + src/pebblisp.c | 17 ++++---- src/pebblisp.h | 2 + src/plfunc.c | 7 +++- src/plfunc.h | 108 ++++++++++++++++++++++++++++++------------------- 7 files changed, 101 insertions(+), 55 deletions(-) diff --git a/src/env.c b/src/env.c index af9fd34..169e8bb 100644 --- a/src/env.c +++ b/src/env.c @@ -241,7 +241,7 @@ void setGlobal(struct Environment* env) struct helpText { const char* symbol; const char* help; - const char*const* tests; + const char* const* tests; size_t testCount; }; int currentHelp = 0; @@ -251,7 +251,9 @@ struct helpText helpTexts[100]; #define pf(_name, _func) buildFuncSym(_name, &(_func), _func ## Doc, _func ## Tests, array_length(_func ## Tests)) int helpInitialized = 0; -struct symFunc buildFuncSym(const char* symbol, Object (* func)(Object, Object, struct Environment*), const char* help, const char*const* tests, size_t testLength) + +struct symFunc buildFuncSym(const char* symbol, Object (* func)(Object, Object, struct Environment*), const char* help, + const char* const* tests, size_t testLength) { if (!helpInitialized) { helpTexts[currentHelp].help = help; @@ -281,7 +283,7 @@ char* getHelp(const char* symbol) textCursor += sprintf(textCursor, "\n "); int c = 0; int depth = 0; - while(test[c]) { + while (test[c]) { if (test[c] == '(') { depth += 1; textCursor += sprintf(textCursor, "[3%dm", (depth % 6) + 2); @@ -295,7 +297,12 @@ char* getHelp(const char* symbol) c++; } //textCursor += sprintf(textCursor, "\n %s => %s", test, expected); - textCursor += sprintf(textCursor, " => %s", expected); + textCursor += sprintf(textCursor, " => "); + if (expected[0] == '\0') { + textCursor += sprintf(textCursor, ""); + } else { + textCursor += sprintf(textCursor, "%s", expected); + } } return text; } diff --git a/src/object.c b/src/object.c index 8913166..ebce459 100644 --- a/src/object.c +++ b/src/object.c @@ -907,6 +907,11 @@ inline int eitherIs(const enum Type type, const Object* o1, const Object* o2) return (o1->type == type) || (o2->type == type); } +inline int eitherIsNot(const enum Type type, const Object* o1, const Object* o2) +{ + return (o1->type != type) || (o2->type != type); +} + inline int areSameType(const Object* obj1, const Object* obj2) { return obj1->type == obj2->type; diff --git a/src/object.h b/src/object.h index dacff48..ce16014 100644 --- a/src/object.h +++ b/src/object.h @@ -192,6 +192,8 @@ int isError(Object obj, enum errorCode err); int bothAre(enum Type type, const Object* obj1, const Object* obj2); +int eitherIsNot(const enum Type type, const Object* o1, const Object* o2); + int eitherIs(enum Type type, const Object* obj1, const Object* obj2); int areSameType(const Object* obj1, const Object* obj2); diff --git a/src/pebblisp.c b/src/pebblisp.c index 9be72a7..400acc7 100644 --- a/src/pebblisp.c +++ b/src/pebblisp.c @@ -1,7 +1,9 @@ #ifdef STANDALONE #define _GNU_SOURCE + #include #include + #endif #include "pebblisp.h" @@ -399,17 +401,12 @@ Object eval(const Object* obj, struct Environment* env) case TYPE_BOOL: case TYPE_STRING: case TYPE_STRUCT: + case TYPE_SLIST: return cloneObject(*obj); case TYPE_SYMBOL: return fetchFromEnvironment(obj->string, env); - case TYPE_SLIST: { - Object o = cloneObject(*obj); - o.type = TYPE_LIST; - return o; - } - case TYPE_LIST: return evalList(obj, env); @@ -480,7 +477,9 @@ Result parse(struct Slice* slices) struct Slice* rest = &slices[1]; if (token->text[0] == '\'' && token->text[1] == '(') { Result r = readSeq(&slices[2]); - r.obj.type = TYPE_SLIST; + if (r.obj.type == TYPE_LIST) { + r.obj.type = TYPE_SLIST; + } return r; } else if (token->text[0] == '(') { // todo check for null rest @@ -597,6 +596,7 @@ Result parseAtom(struct Slice* s) } struct Slice* lastOpen = NULL; + Object parseEval(const char* input, struct Environment* env) { struct Error err = noError(); @@ -743,6 +743,7 @@ void loadArgsIntoEnv(int argc, const char* argv[], struct Environment* env) } int nestedSegfault = 0; + void handler(int nSignum, siginfo_t* si, void* vcontext) { if (nestedSegfault) { @@ -757,7 +758,7 @@ void handler(int nSignum, siginfo_t* si, void* vcontext) } else { printf("Happened before token processing.\n"); } - struct Environment *e = global(); + struct Environment* e = global(); *e = defaultEnv(); ucontext_t* context = vcontext; context->uc_mcontext.gregs[REG_RIP]++; diff --git a/src/pebblisp.h b/src/pebblisp.h index d80c0c9..2a9142d 100644 --- a/src/pebblisp.h +++ b/src/pebblisp.h @@ -43,6 +43,8 @@ Result parseAtom(struct Slice* slice); Object parseEval(const char* input, struct Environment* env); +Object evalList(const Object* obj, struct Environment* env); + void evalForms(Object* destList, const Object* src, struct Environment* env); void copySlice(char* dest, struct Slice* src); diff --git a/src/plfunc.c b/src/plfunc.c index 0d96fde..b154374 100644 --- a/src/plfunc.c +++ b/src/plfunc.c @@ -86,6 +86,9 @@ Object rest(Object list, Object ignore, struct Environment* env) Object reverse(Object _list, Object ignore, struct Environment* ignore2) { + if (!isListy(_list)) { + return errorObject(NOT_A_LIST); + } const Object* list = &_list; Object rev = listObject(); @@ -137,6 +140,8 @@ Object parseEvalO(Object text, Object ignore, struct Environment* env) Object parsed = parseEval(string.string, env); cleanObject(&string); return parsed; + } else if (text.type == TYPE_SLIST) { + return evalList(&text, env); } else if (text.type != TYPE_STRING) { return errorObject(CAN_ONLY_EVAL_STRINGS); } @@ -187,7 +192,7 @@ Object _basicOp(const Object* obj1, const Object* obj2, const char op, switch (op) { case '+': - if (eitherIs(TYPE_STRING, obj1, obj2)) { + if (eitherIsNot(TYPE_NUMBER, obj1, obj2)) { return catObjects(*obj1, *obj2, env); } return numberObject(n1 + n2); diff --git a/src/plfunc.h b/src/plfunc.h index e740a3d..d1a9ea8 100644 --- a/src/plfunc.h +++ b/src/plfunc.h @@ -29,84 +29,108 @@ BASIC_OP(or); #undef BASIC_OP fn(catObjects, - "Concatenate string versions of the given objects.", - "(cat \"Stuff: \" (1 2 3))", "Stuff: ( 1 2 3 )" + "Concatenate string versions of the given objects.", + "(cat \"Stuff: \" (1 2 3))", "Stuff: ( 1 2 3 )", )(Object obj1, Object obj2, struct Environment* env); fn(filter, - "Filter a list based on the given condition.", - "(fil (< 50) (25 60 100))", "( 60 100 )" + "Filter a list based on the given condition.", + "(fil (< 50) (25 60 100))", "( 60 100 )", )(Object condition, Object list, struct Environment* env); fn(append, - "Append the given element. Creates a new list.", - "(ap (1 2) 3)", "( 1 2 3 )" + "Append the given element. Creates a new list.", + "(ap (1 2) 3)", "( 1 2 3 )", )(Object list, Object newElement, struct Environment* env); fn(prepend, - "Prepend the given element. Creates a new list", - "(pre (2 3) 1)", "( 1 2 3 )" + "Prepend the given element. Creates a new list", + "(pre (2 3) 1)", "( 1 2 3 )", )(Object list, Object newElement, struct Environment* env); fn(len, - "Returns the length of the given list, or a NOT_A_LIST error if the expression is not a list.", - "(len (2 3))", "2", - "(len ())", "0", - "(len \"string\")", "NOT_A_LIST" + "Returns the length of the given list, or a NOT_A_LIST error if the expression is not a list.", + "(len (2 3))", "2", + "(len ())", "0", + "(len \"string\")", "NOT_A_LIST", )(Object obj1, Object o_ignore, struct Environment* e_ignore); fn(reduce, - "Performs a simple reduction. Does not currently work with lambdas.\n" - "Takes two arguments:\n" - " - A two-element list: (`values` `initial`)\n" - " - A function to apply to each value.", - "(reduce (5 6) +)", "11", - "(reduce ((1 2 3) 0) +)", "6" + "Performs a simple reduction. Does not currently work with lambdas.\n" + "Takes two arguments:\n" + " - A two-element list: (`values` `initial`)\n" + " - A function to apply to each value.", + "(reduce (5 6) +)", "11", + "(reduce ((1 2 3) 0) +)", "6", )(Object listInitial, Object func, struct Environment* env); -fn(at, "(at 1 (1 2 3)) => 2") -(Object index, Object list, struct Environment* env); +fn(at, + "Get item at the given index in the given list.", + "(at 1 (1 2 3))", "2", + "(at 99 (1 2 3))", "INDEX_PAST_END", + "(at 99 \"string\")", "INDEX_PAST_END", +)(Object index, Object list, struct Environment* env); -fn(rest, "(rest (1 2 3)) => ( 2 3 )") -(Object list, Object ignore, struct Environment* env); +fn(rest, + "Get the tail of a list. All but the first element.", + "(rest (1 2 3))", "( 2 3 )", + "(rest ())", "( )", + "(rest \"string\")", "( )", +)(Object list, Object ignore, struct Environment* env); -fn(reverse, "(rev (1 2 3)) => ( 3 2 1 )") -(Object _list, Object ignore, struct Environment* ignore2); +fn(reverse, + "Reverse a list.", + "(rev (1 2 3))", "( 3 2 1 )", + "(rev \"string\")", "NOT_A_LIST", +)(Object _list, Object ignore, struct Environment* ignore2); -fn(isNum, "(isnum 1) => T\n(isnum \"Hello\") => F") -(Object test, Object ignore, struct Environment* ignore2); +fn(isNum, + "Returns `T` only if the argument evaluates to a number.", + "(isnum 1)", "T", + "(isnum (+ 5 5))", "T", + "(isnum '(+ 5 5))", "F", + "(isnum \"Hello\")", "F", +)(Object test, Object ignore, struct Environment* ignore2); fn(isList, - "Returns `T` only if the argument is a list.", - "(islist (1 2 3))", "T", - "(islist ())", "T", - "(islist \"Stringy\")", "F", + "Returns `T` only if the argument is a list.", + "(islist (1 2 3))", "T", + "(islist ())", "T", + "(islist \"Stringy\")", "F", )(Object test, Object ignore, struct Environment* ignore2); fn(isString, - "(isstr \"Heyo\") => T\n" - "(isstr \"\") => T\n" - "(isstr 10) => F" + "Returns `T` only if the argument is a string.", + "(isstr \"Heyo\")", "T", + "(isstr \"\")", "T", + "(isstr (cat 5 5))", "T", + "(isstr 10)", "F", )(Object test, Object ignore, struct Environment* ignore2); fn(isErr, - "(iserr (eval \"(((\") => T\n" - "(iserr 5) => F" + "Check if the argument is an error.", + "(iserr (at 10 ()))", "T", + "(iserr 5)", "F", )(Object test, Object ignore, struct Environment* ignore2); fn(charAt, - "(chat \"Hello\" 1) => \"e\"\n" - "(chat \"Hello\" 10) => \"\"" + "Get the char in the given string at the given index.", + "(chat \"Hello\" 1)", "e", + "(chat \"Hello\" 10)", "", )(Object string, Object at, struct Environment* ignore); fn(charVal, - "(char \"h\") => 104\n" - "(char \"hello\") => 104\n" - "(char \"\") => 0" + "Get the ascii integer representaton of the given character.", + "(char \"h\")", "104", + "(char \"hello\")", "104", + "(char \"\")", "0", )(Object test, Object ignore, struct Environment* ignore2); -fn(parseEvalO, "(eval \"(1 2 3)\") => (1 2 3)") -(Object text, Object ignore, struct Environment* env); +fn(parseEvalO, + "Evaluate the given string or quoted list.", + "(eval \"(1 2 3)\")", "( 1 2 3 )", + "(eval '(+ 5 5))", "10", +)(Object text, Object ignore, struct Environment* env); fn(possessive, "(struct Post (title body))\n"