Handle more testing stuff statically.
Remove fnt and just have centralized fn. Longer printObj temp string. `?` now shows tests. Add more internal testing.
This commit is contained in:
parent
097cbf6a5c
commit
5a622736d3
30
src/env.c
30
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),
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -6,16 +6,20 @@
|
|||
#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;\
|
||||
Object _name
|
||||
|
||||
#define fnt(_name, _docs, ...) static const char * const _name ## Doc = _docs;\
|
||||
static const char * const _name ## Tests[] = {__VA_ARGS__, NULL}; \
|
||||
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
|
||||
|
||||
struct Slice {
|
||||
|
|
29
src/plfunc.c
29
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;
|
||||
|
||||
|
@ -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
|
38
src/plfunc.h
38
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);
|
||||
|
|
Loading…
Reference in New Issue