diff --git a/src/env.c b/src/env.c index 154468a..9520a7a 100644 --- a/src/env.c +++ b/src/env.c @@ -242,21 +242,22 @@ struct helpText { const char* symbol; const char* help; const char*const* tests; + size_t testCount; }; int currentHelp = 0; struct helpText helpTexts[100]; -#define pf(_name, _func) buildFuncSym(_name, &(_func), _func ## Doc, NULL) #define pfn(_func) buildFuncSym(_func ## Symbol, &(_func), _func ## Doc, NULL) -#define pft(_name, _func) buildFuncSym(_name, &(_func), _func ## Doc, _func ## Tests) +#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) +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; helpTexts[currentHelp].symbol = symbol; helpTexts[currentHelp].tests = tests; + helpTexts[currentHelp].testCount = testLength; currentHelp += 1; } @@ -266,12 +267,20 @@ struct symFunc buildFuncSym(const char* symbol, Object (* func)(Object, Object, }; } -const char* getHelp(const char* symbol) +char* getHelp(const char* symbol) { for (int i = 0; i < currentHelp; i++) { struct helpText h = helpTexts[i]; if (strcmp(symbol, h.symbol) == 0) { - return h.help; + char* text = calloc(sizeof(char), 1024); + char* textCursor = text; + textCursor += sprintf(textCursor, "%s", h.help); + for (int ti = 0; ti < h.testCount; ti += 2) { + const char* test = h.tests[ti]; + const char* expected = h.tests[ti + 1]; + textCursor += sprintf(textCursor, "\n %s => %s", test, expected); + } + return text; } } return "Help not found!"; @@ -293,9 +302,8 @@ int runTests() for (int hi = 0; hi < currentHelp; hi++) { struct helpText h = helpTexts[hi]; if (h.tests) { - int ti = 0; char result[1024]; - while (h.tests[ti]) { + for (int ti = 0; ti < h.testCount; ti += 2) { const char* test = h.tests[ti]; const char* expected = h.tests[ti + 1]; struct Environment env = defaultEnv(); @@ -310,7 +318,6 @@ int runTests() } else { passCount++; } - ti += 2; } } } @@ -354,8 +361,8 @@ struct Environment defaultEnv() {"<", <h}, {"&", &and}, {"|", &or}, - pft("cat", catObjects), - pft("fil", filter), + pf("cat", catObjects), + pf("fil", filter), pf("len", len), pf("ap", append), pf("pre", prepend), @@ -379,7 +386,8 @@ struct Environment defaultEnv() pf("serve", startServer), #endif #ifdef STANDALONE - pfn(segfault), + pf("seg", segfault), + //pfn(segfault), pf("prn", print), pf("pch", pChar), pf("penv", printEnvO), diff --git a/src/env.h b/src/env.h index 379b225..0841eae 100644 --- a/src/env.h +++ b/src/env.h @@ -43,7 +43,8 @@ struct StructDef getStructDef(struct Environment* env, const char* name); int getStructIndex(struct Environment* env, const char* name); -const char* getHelp(const char* symbol); +/// Needs to be freed! +char* getHelp(const char* symbol); int runTests(); diff --git a/src/object.c b/src/object.c index 3a47abe..8913166 100644 --- a/src/object.c +++ b/src/object.c @@ -477,8 +477,8 @@ void _printObj(const Object* obj, int newline) printObj(&obj->lambda->body); return; } - char temp[200] = ""; - stringObj(temp, obj); + char temp[1024] = ""; + stringNObj(temp, obj, 1024); if (newline) { printf("%s\n", temp); if (obj->type == TYPE_ERROR) { diff --git a/src/pebblisp.h b/src/pebblisp.h index d5fa281..d80c0c9 100644 --- a/src/pebblisp.h +++ b/src/pebblisp.h @@ -6,18 +6,22 @@ #include "env.h" #include "object.h" +#define static_assert _Static_assert + +#define array_length(_array) (sizeof(_array) / sizeof((_array)[0])) + #define fn(_name, _docs, ...) static const char * const _name ## Doc = _docs; \ +static const char * const _name ## Tests[] = {__VA_ARGS__}; \ +static_assert(array_length(_name ## Tests) % 2 == 0, "Array of test strings must have exactly one expected result for each test."); \ Object _name -#define fnn(_name, _symbol, _docs)\ +#define fnn(_name, _symbol, _docs, ...)\ static const char * const _name ## Doc = _docs;\ static const char * const _name ## Symbol = _symbol;\ +static const char * const _name ## Tests[] = {__VA_ARGS__}; \ +static_assert(array_length(_name ## Tests) % 2 == 0, "Array of test strings must have exactly one expected result for each test."); \ Object _name -#define fnt(_name, _docs, ...) static const char * const _name ## Doc = _docs;\ - static const char * const _name ## Tests[] = {__VA_ARGS__, NULL}; \ - Object _name - struct Slice { const char* text; unsigned char length; diff --git a/src/plfunc.c b/src/plfunc.c index deecedd..0d96fde 100644 --- a/src/plfunc.c +++ b/src/plfunc.c @@ -233,8 +233,7 @@ Object basicOp(const Object* obj1, const Object* obj2, const char op, if (lists == 0) { return _basicOp(obj1, obj2, op, env); - } else if (lists == - 1) { // Single operand is applied to each element in list + } else if (lists == 1) { // Single operand is applied to each element in list const Object* listObj = (obj1->type == TYPE_LIST) ? obj1 : obj2; const Object* singleObj = (obj1->type == TYPE_LIST) ? obj2 : obj1; @@ -245,7 +244,7 @@ Object basicOp(const Object* obj1, const Object* obj2, const char op, } return newList; - } else { // 2 lists with the op applied to matching indices of both lists + } else { // 2 lists with the op applied to matching indices of both lists if (listLength(obj1) == listLength(obj2)) { Object newList = listObject(); FOR_POINTERS_IN_LISTS(obj1, obj2) { @@ -275,25 +274,25 @@ Object len(Object obj1, Object o_ignore, struct Environment* e_ignore) return basicOp(&obj1, &obj2, _char, env); \ } -BASIC_OP(add, '+'); +BASIC_OP(add, '+') -BASIC_OP(sub, '-'); +BASIC_OP(sub, '-') -BASIC_OP(mul, '*'); +BASIC_OP(mul, '*') -BASIC_OP(dvi, '/'); +BASIC_OP(dvi, '/') -BASIC_OP(mod, '%'); +BASIC_OP(mod, '%') -BASIC_OP(equ, '='); +BASIC_OP(equ, '=') -BASIC_OP(gth, '>'); +BASIC_OP(gth, '>') -BASIC_OP(lth, '<'); +BASIC_OP(lth, '<') -BASIC_OP(and, '&'); +BASIC_OP(and, '&') -BASIC_OP(or, '|'); +BASIC_OP(or, '|') #undef BASIC_OP @@ -343,8 +342,10 @@ Object systemCall(Object process, Object _, struct Environment* env) Object help(Object symbol, Object ignore, struct Environment* ignore2) { - const char* help = getHelp(symbol.string); - return objFromSlice(&help[-1], strlen(help) + 2); + char* help = getHelp(symbol.string); + Object helpText = newObject(TYPE_STRING); + helpText.string = help; + return helpText; } #endif // STANDALONE \ No newline at end of file diff --git a/src/plfunc.h b/src/plfunc.h index 6f8307d..8069a14 100644 --- a/src/plfunc.h +++ b/src/plfunc.h @@ -28,29 +28,41 @@ BASIC_OP(or); #undef BASIC_OP -fnt(catObjects, - "Concatenate string versions of the given objects.\n", +fn(catObjects, + "Concatenate string versions of the given objects.", "(cat \"Stuff: \" (1 2 3))", "Stuff: ( 1 2 3 )" )(Object obj1, Object obj2, struct Environment* env); -fnt(filter, - "Filter a list based on the given condition.\n", +fn(filter, + "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", - "(ap (1 2) 3)", "( 1 2 3 )") -(Object list, Object newElement, struct Environment* env); + "Append the given element. Creates a new list.", + "(ap (1 2) 3)", "( 1 2 3 )" +)(Object list, Object newElement, struct Environment* env); -fn(prepend, "(pre (2 3) 1) => ( 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 )" +)(Object list, Object newElement, struct Environment* env); -fn(len, "(len (2 3)) => 2") -(Object obj1, Object o_ignore, struct Environment* e_ignore); +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" +)(Object obj1, Object o_ignore, struct Environment* e_ignore); -fn(reduce, "(reduce ((1 2 3) 0) +) => 6") -(Object listInitial, Object func, struct Environment* env); +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" +)(Object listInitial, Object func, struct Environment* env); fn(at, "(at 1 (1 2 3)) => 2") (Object index, Object list, struct Environment* env);