Start some internal testing frameworking.

This commit is contained in:
Sage Vaillancourt 2022-03-21 12:33:35 -04:00 committed by Sage Vaillancourt
parent 3bf65577c0
commit 097cbf6a5c
13 changed files with 245 additions and 74 deletions

View File

@ -12,7 +12,7 @@ mkfile_dir := $(dir $(mkfile_path))
GCC_COM ?= gcc -g -O0 -Wall -o $(exe) -D WEBSERVER -D STANDALONE -DSCRIPTDIR=\"$(SCRIPTDIR)\" GCC_COM ?= gcc -g -O0 -Wall -o $(exe) -D WEBSERVER -D STANDALONE -DSCRIPTDIR=\"$(SCRIPTDIR)\"
all: all:
$(GCC_COM) $(files) $(libs) && echo && ./tests.sh $(GCC_COM) $(files) $(libs) && echo && ./tests.sh && ./pl --run-tests
notest: notest:
$(GCC_COM) $(file_libs) $(GCC_COM) $(file_libs)

View File

@ -52,6 +52,7 @@ struct Environment envForLambda(const Object* params, const Object* arg_forms,
} }
struct Environment env = { struct Environment env = {
.name = "lambdaEnv",
.outer = outer, .outer = outer,
.strings = NULL, .strings = NULL,
.objects = NULL, .objects = NULL,
@ -240,17 +241,24 @@ void setGlobal(struct Environment* env)
struct helpText { struct helpText {
const char* symbol; const char* symbol;
const char* help; const char* help;
const char*const* tests;
}; };
int currentHelp = 0; int currentHelp = 0;
struct helpText helpTexts[100]; struct helpText helpTexts[100];
#define pf(_name, _func) buildHelp(_name, &(_func), _func ## Doc) #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)
struct symFunc buildHelp(const char* symbol, Object (* func)(Object, Object, struct Environment*), const char* help) int helpInitialized = 0;
struct symFunc buildFuncSym(const char* symbol, Object (* func)(Object, Object, struct Environment*), const char* help, const char*const* tests)
{ {
if (!helpInitialized) {
helpTexts[currentHelp].help = help; helpTexts[currentHelp].help = help;
helpTexts[currentHelp].symbol = symbol; helpTexts[currentHelp].symbol = symbol;
helpTexts[currentHelp].tests = tests;
currentHelp += 1; currentHelp += 1;
}
return (struct symFunc) { return (struct symFunc) {
.func = func, .func = func,
@ -269,6 +277,54 @@ const char* getHelp(const char* symbol)
return "Help not found!"; return "Help not found!";
} }
fnn(segfault, "seg", "Induces a segfault.")
(Object ignore1, Object ignore2, struct Environment* env)
{
int* p = NULL;
return numberObject(*p);
}
// Returns number of failures
int runTests()
{
printf("Running tests...\n");
int failureCount = 0;
int passCount = 0;
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]) {
const char* test = h.tests[ti];
const char* expected = h.tests[ti + 1];
struct Environment env = defaultEnv();
Object o = parseEval(test, &env);
stringObj(result, &o);
cleanObject(&o);
if (strcmp(result, expected) != 0) {
failureCount++;
printf("Test failed!\n");
printf("%s\n", test);
printf("Expected '%s' but received '%s'\n", expected, result);
} else {
passCount++;
}
ti += 2;
}
}
}
if (passCount > 0) {
printf("");
}
printf("%d tests passed!\n", passCount);
if (failureCount > 0) {
printf("");
}
printf("%d tests failed!\n", failureCount);
return failureCount;
}
struct Environment defaultEnv() struct Environment defaultEnv()
{ {
char** strings = calloc(sizeof(char*), MAX_ENV_ELM); char** strings = calloc(sizeof(char*), MAX_ENV_ELM);
@ -276,6 +332,7 @@ struct Environment defaultEnv()
char size = MAX_ENV_ELM; char size = MAX_ENV_ELM;
struct Environment e = { struct Environment e = {
.name = "defaultEnv",
.outer = NULL, .outer = NULL,
.strings = strings, .strings = strings,
.objects = objects, .objects = objects,
@ -297,8 +354,8 @@ struct Environment defaultEnv()
{"<", &lth}, {"<", &lth},
{"&", &and}, {"&", &and},
{"|", &or}, {"|", &or},
pf("cat", catObjects), pft("cat", catObjects),
pf("fil", filter), pft("fil", filter),
pf("len", len), pf("len", len),
pf("ap", append), pf("ap", append),
pf("pre", prepend), pf("pre", prepend),
@ -312,22 +369,23 @@ struct Environment defaultEnv()
pf("isnum", isNum), pf("isnum", isNum),
pf("islist", isList), pf("islist", isList),
pf("isstr", isString), pf("isstr", isString),
{"iserr", &isErr}, pf("iserr", isErr),
pf("char", charVal), pf("char", charVal),
{"eval", &parseEvalO}, pf("eval", parseEvalO),
{"poss", &possessive}, pf("poss", possessive),
#ifdef WEBSERVER #ifdef WEBSERVER
pf("get", addGetRoute), pf("get", addGetRoute),
pf("post", addPostRoute), pf("post", addPostRoute),
pf("serve", startServer), pf("serve", startServer),
#endif #endif
#ifdef STANDALONE #ifdef STANDALONE
{"prn", &print}, pfn(segfault),
{"pch", &pChar}, pf("prn", print),
{"penv", &printEnvO}, pf("pch", pChar),
//{"sys", &systemCall}, pf("penv", printEnvO),
{"loadfile", &loadFile}, pf("sys", systemCall),
{"inp", &takeInput}, pf("loadfile", loadFile),
pf("inp", takeInput),
pf("?", help) pf("?", help)
#endif #endif
}; };
@ -336,6 +394,7 @@ struct Environment defaultEnv()
addFunc(symFuncs[i].sym, symFuncs[i].func, &e); addFunc(symFuncs[i].sym, symFuncs[i].func, &e);
} }
helpInitialized = 1;
return e; return e;
} }

View File

@ -15,6 +15,7 @@ struct Environment {
struct StructDef* structDefs; struct StructDef* structDefs;
int refs; int refs;
const char* name;
}; };
struct Environment* global(); struct Environment* global();
@ -44,4 +45,6 @@ int getStructIndex(struct Environment* env, const char* name);
const char* getHelp(const char* symbol); const char* getHelp(const char* symbol);
int runTests();
#endif #endif

View File

@ -36,12 +36,13 @@ and the interpreter won't even instantly crash over it! It's truly astounding
stuff, when you think about it." stuff, when you think about it."
)) ))
(def homepage (fn () (html ( (def homepage (fn (req) (html (
(head ( (head (
(link ((rel "stylesheet") (href "styles.css"))) (link ((rel "stylesheet") (href "styles.css")))
)) ))
(body ( (body (
(h1 "This is a sweet PebbLisp blog") (h1 "This is a sweet PebbLisp site")
(p (cat "" req))
(htmlize p1) (htmlize p1)
(htmlize p2))) (htmlize p2)))
)))) ))))

View File

@ -1,4 +1,5 @@
#include "object.h" #include "object.h"
#include "pebblisp.h"
#include "env.h" #include "env.h"
#include <stdio.h> #include <stdio.h>
@ -476,11 +477,16 @@ void _printObj(const Object* obj, int newline)
printObj(&obj->lambda->body); printObj(&obj->lambda->body);
return; return;
} }
char temp[200] = ""; char temp[200] = "";
stringObj(temp, obj); stringObj(temp, obj);
if (newline) { if (newline) {
printf("%s\n", temp); printf("%s\n", temp);
if (obj->type == TYPE_ERROR) {
if (obj->error && obj->error->plContext) {
printf("%s\n", obj->error->plContext->text);
return;
}
}
} else { } else {
printf("%s", temp); printf("%s", temp);
} }
@ -922,6 +928,7 @@ inline Object errorObject(enum errorCode err)
o.error = malloc(sizeof(struct Error)); o.error = malloc(sizeof(struct Error));
o.error->code = err; o.error->code = err;
o.error->context = NULL; o.error->context = NULL;
o.error->plContext = NULL;
#endif #endif
return o; return o;

View File

@ -85,11 +85,11 @@ typedef struct Object Object;
struct Lambda; struct Lambda;
struct Environment; struct Environment;
struct Slice;
struct Other; struct Other;
struct Error { struct Error {
enum errorCode code; enum errorCode code;
char* context; char* context;
struct Slice* plContext;
}; };
struct Object { struct Object {

View File

@ -1,3 +1,9 @@
#ifdef STANDALONE
#define _GNU_SOURCE
#include <signal.h>
#include <ucontext.h>
#endif
#include "pebblisp.h" #include "pebblisp.h"
#include <stdlib.h> #include <stdlib.h>
@ -590,6 +596,7 @@ Result parseAtom(struct Slice* s)
} }
} }
struct Slice* lastOpen = NULL;
Object parseEval(const char* input, struct Environment* env) Object parseEval(const char* input, struct Environment* env)
{ {
struct Error err = noError(); struct Error err = noError();
@ -623,6 +630,7 @@ Object parseEval(const char* input, struct Environment* env)
struct Slice* tok = tokens; struct Slice* tok = tokens;
while (tok[i].text != NULL) { while (tok[i].text != NULL) {
if (tok[i].text[0] == '(') { if (tok[i].text[0] == '(') {
lastOpen = &tok[i];
parens++; parens++;
} else if (tok[i].text[0] == ')') { } else if (tok[i].text[0] == ')') {
parens--; parens--;
@ -633,6 +641,7 @@ Object parseEval(const char* input, struct Environment* env)
Object parsed = parse(tok).obj; Object parsed = parse(tok).obj;
if (parsed.type == TYPE_ERROR) { if (parsed.type == TYPE_ERROR) {
obj = parsed; // TODO Check necessity obj = parsed; // TODO Check necessity
obj.error->plContext = lastOpen;
break; break;
} }
if (tok[i].text[0] == ')') { if (tok[i].text[0] == ')') {
@ -733,10 +742,48 @@ void loadArgsIntoEnv(int argc, const char* argv[], struct Environment* env)
addToEnv(env, "args", args); addToEnv(env, "args", args);
} }
int nestedSegfault = 0;
void handler(int nSignum, siginfo_t* si, void* vcontext)
{
if (nestedSegfault) {
printf("Nested segfault!!!\n");
exit(139);
}
nestedSegfault = 1;
printf("Segfaulted!\n");
if (lastOpen) {
printf("line: %d\n%s\n", lastOpen->lineNumber, lastOpen->text);
} else {
printf("Happened before token processing.\n");
}
struct Environment *e = global();
*e = defaultEnv();
ucontext_t* context = vcontext;
context->uc_mcontext.gregs[REG_RIP]++;
exit(139);
}
int main(int argc, const char* argv[]) int main(int argc, const char* argv[])
{ {
struct Environment env = defaultEnv(); struct Environment env = defaultEnv();
setGlobal(&env); setGlobal(&env);
if (argc == 2 && strcmp(argv[1], "--run-tests") == 0) {
runTests();
return 0;
}
struct sigaction action;
memset(&action, 0, sizeof(struct sigaction));
action.sa_flags = SA_SIGINFO;
action.sa_sigaction = handler;
sigaction(SIGSEGV, &action, NULL);
// struct Environment* e = &env;
// e += 10000;
// printEnv(e);
readFile(SCRIPTDIR "/lib.pbl", &env); readFile(SCRIPTDIR "/lib.pbl", &env);
if (argc >= 2) { if (argc >= 2) {
FILE* file = fopen(argv[1], "r"); FILE* file = fopen(argv[1], "r");

View File

@ -6,11 +6,22 @@
#include "env.h" #include "env.h"
#include "object.h" #include "object.h"
#define F(_name, _docs) static const char * const _name ## Doc = _docs; Object _name #define fn(_name, _docs, ...) static const char * const _name ## Doc = _docs; \
Object _name
#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}; \
Object _name
struct Slice { struct Slice {
const char* text; const char* text;
unsigned char length; unsigned char length;
int lineNumber;
}; };
typedef struct Result { typedef struct Result {
@ -43,12 +54,6 @@ Object simpleFuncEval(Object func, Object arg1, Object arg2, struct Environment*
#ifdef STANDALONE #ifdef STANDALONE
Object takeInput(Object i1, Object i2, struct Environment* i3);
Object systemCall(Object call, Object _, struct Environment* i3);
Object loadFile(Object filename, Object _, struct Environment* env);
int _readFile(FILE* input, struct Environment* env); int _readFile(FILE* input, struct Environment* env);
int readFile(const char* filename, struct Environment* env); int readFile(const char* filename, struct Environment* env);

View File

@ -4,7 +4,7 @@
#include "pebblisp.h" #include "pebblisp.h"
#define BASIC_OP(_name) \ #define BASIC_OP(_name) \
Object _name(Object obj1, Object obj2, struct Environment *env); Object _name(Object obj1, Object obj2, struct Environment *env)
BASIC_OP(add); BASIC_OP(add);
@ -28,85 +28,118 @@ BASIC_OP(or);
#undef BASIC_OP #undef BASIC_OP
F(catObjects, fnt(catObjects,
"Concatenate string versions of the given objects.\n" "Concatenate string versions of the given objects.\n",
"(cat \"Stuff: \" (1 2 3)) => \"Stuff: ( 1 2 3 )\"" "(cat \"Stuff: \" (1 2 3))", "Stuff: ( 1 2 3 )"
)(Object obj1, Object obj2, struct Environment* env); )(Object obj1, Object obj2, struct Environment* env);
F(filter, "(filter (< 50) (25 60 100)) => ( 60 100 )") fnt(filter,
(Object condition, Object list, struct Environment* env); "Filter a list based on the given condition.\n",
"(fil (< 50) (25 60 100))", "( 60 100 )"
)(Object condition, Object list, struct Environment* env);
F(append, "(ap (1 2) 3) => ( 1 2 3 )") fn(append,
"Append the given element",
"(ap (1 2) 3)", "( 1 2 3 )")
(Object list, Object newElement, struct Environment* env); (Object list, Object newElement, struct Environment* env);
F(prepend, "(pre (2 3) 1) => ( 1 2 3 )") fn(prepend, "(pre (2 3) 1) => ( 1 2 3 )")
(Object list, Object newElement, struct Environment* env); (Object list, Object newElement, struct Environment* env);
F(len, "(len (2 3)) => 2") fn(len, "(len (2 3)) => 2")
(Object obj1, Object o_ignore, struct Environment* e_ignore); (Object obj1, Object o_ignore, struct Environment* e_ignore);
F(reduce, "(reduce ((1 2 3) 0) +) => 6") fn(reduce, "(reduce ((1 2 3) 0) +) => 6")
(Object listInitial, Object func, struct Environment* env); (Object listInitial, Object func, struct Environment* env);
F(at, "(at 1 (1 2 3)) => 2") fn(at, "(at 1 (1 2 3)) => 2")
(Object index, Object list, struct Environment* env); (Object index, Object list, struct Environment* env);
F(rest, "(rest (1 2 3)) => ( 2 3 )") fn(rest, "(rest (1 2 3)) => ( 2 3 )")
(Object list, Object ignore, struct Environment* env); (Object list, Object ignore, struct Environment* env);
F(reverse, "(rev (1 2 3)) => ( 3 2 1 )") fn(reverse, "(rev (1 2 3)) => ( 3 2 1 )")
(Object _list, Object ignore, struct Environment* ignore2); (Object _list, Object ignore, struct Environment* ignore2);
F(isNum, "(isnum 1) => T\n(isnum \"Hello\") => F") fn(isNum, "(isnum 1) => T\n(isnum \"Hello\") => F")
(Object test, Object ignore, struct Environment* ignore2); (Object test, Object ignore, struct Environment* ignore2);
F(isList, fn(isList,
"(islist (1 2 3)) => T\n" "(islist (1 2 3)) => T\n"
"(islist ()) => T\n" "(islist ()) => T\n"
"(islist \"Stringy\") => F" "(islist \"Stringy\") => F"
)(Object test, Object ignore, struct Environment* ignore2); )(Object test, Object ignore, struct Environment* ignore2);
F(isString, fn(isString,
"(isstr \"Heyo\") => T\n" "(isstr \"Heyo\") => T\n"
"(isstr \"\") => T\n" "(isstr \"\") => T\n"
"(isstr 10) => F" "(isstr 10) => F"
)(Object test, Object ignore, struct Environment* ignore2); )(Object test, Object ignore, struct Environment* ignore2);
F(isErr, "") fn(isErr,
(Object test, Object ignore, struct Environment* ignore2); "(iserr (eval \"(((\") => T\n"
"(iserr 5) => F"
)(Object test, Object ignore, struct Environment* ignore2);
F(charAt, fn(charAt,
"(chat \"Hello\" 1) => \"e\"\n" "(chat \"Hello\" 1) => \"e\"\n"
"(chat \"Hello\" 10) => \"\"" "(chat \"Hello\" 10) => \"\""
)(Object string, Object at, struct Environment* ignore); )(Object string, Object at, struct Environment* ignore);
F(charVal, fn(charVal,
"(char \"h\") => 104\n" "(char \"h\") => 104\n"
"(char \"hello\") => 104\n" "(char \"hello\") => 104\n"
"(char \"\") => 0" "(char \"\") => 0"
)(Object test, Object ignore, struct Environment* ignore2); )(Object test, Object ignore, struct Environment* ignore2);
F(parseEvalO, "(eval \"(1 2 3)\") => (1 2 3)") fn(parseEvalO, "(eval \"(1 2 3)\") => (1 2 3)")
(Object text, Object ignore, struct Environment* env); (Object text, Object ignore, struct Environment* env);
F(possessive, fn(possessive,
"(struct Post (title body)) (def p (Post \"TI\" \"BO\")) p's title => TI" "(struct Post (title body))\n"
"(def p (Post \"TI\" \"BO\"))\n"
"p's title => TI"
)(Object structo, Object field, struct Environment* env); )(Object structo, Object field, struct Environment* env);
#ifdef STANDALONE #ifdef STANDALONE
F(print, "Prints the string representation of the given object to stdout.") fn(print, "Prints the string representation of the given object to stdout.")
(Object p, Object ignore, struct Environment* ignore2); (Object p, Object ignore, struct Environment* ignore2);
F(pChar, "Prints the ascii character for the given number value.") fn(pChar, "Prints the ascii character for the given number value.")
(Object c, Object i1, struct Environment* i2); (Object c, Object i1, struct Environment* i2);
F(printEnvO, "Prints out the current scoped environment.") fn(printEnvO, "Prints out the current scoped environment.")
(Object i1, Object i2, struct Environment* env); (Object i1, Object i2, struct Environment* env);
F(help, "(? +) => \"(+ 1 2) => 3\"") fn(systemCall,
(Object symbol, Object ignore, struct Environment* ignore2); "Opens a shell and runs the given command, returning the command's exit code.\n"
"(sys \"echo yee\")\n"
"yee\n"
"=> 0"
)(Object process, Object _, struct Environment* env);
#endif fn(loadFile,
"Loads and parses the given file.\n"
"Returns 0 if the file was loaded and parsed successfully. Otherwise 1.\n"
"(loadfile \"printdate.pl\")\n"
"Mon 21 Mar 2022 10:35:03 AM EDT\n"
"=> 0"
)(Object filename, Object _, struct Environment* env);
fn(takeInput,
"Take console input with an optional prompt. For example:\n"
"`(def x (input))` will wait for user input with no prompt.\n"
"`(def x (input \">> \"))` wait for input, but prompt the user with '>> '.\n"
)(Object i1, Object i2, struct Environment* i3);
fn(help,
"Displays help text for the given function.\n"
"Currently requires the function name as a string, but future syntactic sugar may\n"
"loosen this requirement.\n"
"(? \"+\") => \"(+ 1 2) => 3\""
)(Object symbol, Object ignore, struct Environment* ignore2);
#endif // STANDALONE
#endif // PEBBLISP_PLFUNC_H #endif // PEBBLISP_PLFUNC_H

View File

@ -55,21 +55,26 @@ check() {
return 1 return 1
fi fi
local output
if $VALGRIND; then if $VALGRIND; then
echo -ne "\n $1\r " echo -ne "\n $1\r "
local output="$($VALCOM ./pl "(loadfile \"examples/lib.pbl\") $2" | grep -v PLT)" output="$($VALCOM ./pl "(loadfile \"examples/lib.pbl\") $2" | grep -v PLT)"
else else
local output="$(./pl "(loadfile \"examples/lib.pbl\") $2" | grep -v PLT)" output="$(./pl "(loadfile \"examples/lib.pbl\") $2" | grep -v PLT)"
fi fi
if [ "$output" == "$3" ]; then if [ "$3" == "$regex" ]; then
if [[ "$output" =~ ^$4$ ]]; then
pass "$1" pass "$1"
elif [ "$3" == "$regex" ] && [[ "$output" =~ $4 ]]; then return
fi
elif [ "$output" == "$3" ]; then
pass "$1" pass "$1"
else return
fi
fail "$1" "$2" fail "$1" "$2"
FAIL_OUTPUT="${FAIL_OUTPUT}\n  expected '$3' but received '$output'\n" FAIL_OUTPUT="${FAIL_OUTPUT}\n  expected '$3' but received '$output'\n"
fi
} }
echo "STARTING TESTS" echo "STARTING TESTS"
@ -206,9 +211,9 @@ title "ShouldError"
check "LenOfNotList" "(len 5)" "NOT_A_LIST" check "LenOfNotList" "(len 5)" "NOT_A_LIST"
check "NoMapList" "(map sq)" "( )" check "NoMapList" "(map sq)" "( )"
check "UnevenLists" "(+ (1 2) (1 2 3))" "LISTS_NOT_SAME_SIZE" check "UnevenLists" "(+ (1 2) (1 2 3))" "LISTS_NOT_SAME_SIZE"
check "BadNumber" "(5df)" "BAD_NUMBER" check "BadNumber" "(5df)" regex "BAD_NUMBER.*"
check "BadHex" "(0x0zf)" "BAD_NUMBER" check "BadHex" "(0x0zf)" regex "BAD_NUMBER.*"
check "BadBinary" "(0b01120)" "BAD_NUMBER" check "BadBinary" "(0b01120)" regex "BAD_NUMBER.*"
check "BadParens1" "(hey()" regex "'MISMATCHED_PARENS.*" check "BadParens1" "(hey()" regex "'MISMATCHED_PARENS.*"
check "BadParens2" "(hey)(" regex "'MISMATCHED_PARENS.*" check "BadParens2" "(hey)(" regex "'MISMATCHED_PARENS.*"
check "BadParens3" "((hey(" regex "'MISMATCHED_PARENS.*" check "BadParens3" "((hey(" regex "'MISMATCHED_PARENS.*"

View File

@ -66,6 +66,7 @@ struct Slice* nf_tokenize(const char* input, struct Error* err)
int i = 0; int i = 0;
int slice = 0; int slice = 0;
int lineNumber = 1;
int parens = 0; int parens = 0;
while (input[i] != '\0') { while (input[i] != '\0') {
@ -73,6 +74,9 @@ struct Slice* nf_tokenize(const char* input, struct Error* err)
// printd("input: '%c'\n", input[i]); // printd("input: '%c'\n", input[i]);
if (isWhitespace(input[i]) || input[i] == ';') { if (isWhitespace(input[i]) || input[i] == ';') {
if (input[i] == '\n') {
lineNumber++;
}
i++; i++;
continue; continue;
} }
@ -92,6 +96,7 @@ struct Slice* nf_tokenize(const char* input, struct Error* err)
} }
slices[slice].text = &input[i]; slices[slice].text = &input[i];
slices[slice].lineNumber = lineNumber;
if (isSingle(input[i])) { if (isSingle(input[i])) {
i++; i++;
@ -105,6 +110,9 @@ struct Slice* nf_tokenize(const char* input, struct Error* err)
if (input[i] == '"' && input[i + 1] == '"' && input[i + 2] == '"') { if (input[i] == '"' && input[i + 1] == '"' && input[i + 2] == '"') {
break; break;
} }
if (input[i] == '\n') {
lineNumber++;
}
l++; l++;
if (input[i] == '\0' || input[i + 1] == '\0' || input[i + 2] == '\0') { if (input[i] == '\0' || input[i + 1] == '\0' || input[i + 2] == '\0') {
err->context = malloc(sizeof(char) * ERR_LEN + 1); err->context = malloc(sizeof(char) * ERR_LEN + 1);
@ -118,6 +126,9 @@ struct Slice* nf_tokenize(const char* input, struct Error* err)
} else { } else {
// Simple string // Simple string
while (input[++i] != '"' && input[i] != '\0') { while (input[++i] != '"' && input[i] != '\0') {
if (input[i] == '\n') {
lineNumber++;
}
l++; l++;
} }
} }

View File

@ -80,8 +80,8 @@ answer_to_connection(void* cls, struct MHD_Connection* connection,
Object queryParams = listObject(); Object queryParams = listObject();
MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, add_query_param, &queryParams); MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, add_query_param, &queryParams);
Object res = structObject(requestDefinition); Object res = numberObject(1010);//structObject(requestDefinition);
res.structObject->fields[0] = queryParams; //res.structObject->fields[0] = queryParams;
Object route = cloneObject(routes[i].routeAction); Object route = cloneObject(routes[i].routeAction);
Object result = listEvalLambda(&route, &res, routes[i].env); Object result = listEvalLambda(&route, &res, routes[i].env);

View File

@ -16,21 +16,21 @@ int addRoute(struct Route route);
int start(int port); int start(int port);
F(startServer, fn(startServer,
"(serve) => 0\n" "(serve) => 0\n"
"Starts a simple web server with routes that have been added with (get) and (post).\n" "Starts a simple web server with routes that have been added with (get) and (post).\n"
"Note: This is a non-blocking call. It is recommended to wait for user input before exiting.\n" "Note: This is a non-blocking call. It is recommended to wait for user input before exiting.\n"
" A simple way would be to use (inp) immediately after the (serve) call." " A simple way would be to use (inp) immediately after the (serve) call."
)(Object path, Object textFunc, struct Environment* env); )(Object path, Object textFunc, struct Environment* env);
F(addGetRoute, fn(addGetRoute,
"Note: Implementation bugs currently prevent using an inline lambda.\n" "Note: Implementation bugs currently prevent using an inline lambda.\n"
" (def homepage (fn () (\"Hello, world!\")));(get \"/\" homepage)\n" " (def homepage (fn () (\"Hello, world!\")));(get \"/\" homepage)\n"
" (def queryPage (fn (req) (req's queryParams)));(get \"/x\" queryPage)\n" " (def queryPage (fn (req) (req's queryParams)));(get \"/x\" queryPage)\n"
" (serve)\n" " (serve)\n"
)(Object path, Object textFunc, struct Environment* env); )(Object path, Object textFunc, struct Environment* env);
F(addPostRoute, fn(addPostRoute,
"Note: Implementation bugs currently prevent using an inline lambda.\n" "Note: Implementation bugs currently prevent using an inline lambda.\n"
" (def homepage (fn () (\"Hello, world!\")));(post \"/\" homepage)\n" " (def homepage (fn () (\"Hello, world!\")));(post \"/\" homepage)\n"
" (serve)\n" " (serve)\n"