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:
Sage Vaillancourt 2022-03-22 11:44:22 -04:00 committed by Sage Vaillancourt
parent 097cbf6a5c
commit 5a622736d3
6 changed files with 73 additions and 47 deletions

View File

@ -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()
{"<", &lth},
{"&", &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),

View File

@ -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();

View File

@ -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) {

View File

@ -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 {

View File

@ -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

View File

@ -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);