Start some internal testing frameworking.
This commit is contained in:
parent
3bf65577c0
commit
097cbf6a5c
|
@ -12,7 +12,7 @@ mkfile_dir := $(dir $(mkfile_path))
|
|||
GCC_COM ?= gcc -g -O0 -Wall -o $(exe) -D WEBSERVER -D STANDALONE -DSCRIPTDIR=\"$(SCRIPTDIR)\"
|
||||
|
||||
all:
|
||||
$(GCC_COM) $(files) $(libs) && echo && ./tests.sh
|
||||
$(GCC_COM) $(files) $(libs) && echo && ./tests.sh && ./pl --run-tests
|
||||
|
||||
notest:
|
||||
$(GCC_COM) $(file_libs)
|
||||
|
|
85
src/env.c
85
src/env.c
|
@ -52,6 +52,7 @@ struct Environment envForLambda(const Object* params, const Object* arg_forms,
|
|||
}
|
||||
|
||||
struct Environment env = {
|
||||
.name = "lambdaEnv",
|
||||
.outer = outer,
|
||||
.strings = NULL,
|
||||
.objects = NULL,
|
||||
|
@ -240,17 +241,24 @@ void setGlobal(struct Environment* env)
|
|||
struct helpText {
|
||||
const char* symbol;
|
||||
const char* help;
|
||||
const char*const* tests;
|
||||
};
|
||||
int currentHelp = 0;
|
||||
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].symbol = symbol;
|
||||
helpTexts[currentHelp].tests = tests;
|
||||
currentHelp += 1;
|
||||
}
|
||||
|
||||
return (struct symFunc) {
|
||||
.func = func,
|
||||
|
@ -269,6 +277,54 @@ const char* getHelp(const char* symbol)
|
|||
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("[32;1m");
|
||||
}
|
||||
printf("%d tests passed![0m\n", passCount);
|
||||
if (failureCount > 0) {
|
||||
printf("[31m");
|
||||
}
|
||||
printf("%d tests failed![0m\n", failureCount);
|
||||
return failureCount;
|
||||
}
|
||||
|
||||
struct Environment defaultEnv()
|
||||
{
|
||||
char** strings = calloc(sizeof(char*), MAX_ENV_ELM);
|
||||
|
@ -276,6 +332,7 @@ struct Environment defaultEnv()
|
|||
char size = MAX_ENV_ELM;
|
||||
|
||||
struct Environment e = {
|
||||
.name = "defaultEnv",
|
||||
.outer = NULL,
|
||||
.strings = strings,
|
||||
.objects = objects,
|
||||
|
@ -297,8 +354,8 @@ struct Environment defaultEnv()
|
|||
{"<", <h},
|
||||
{"&", &and},
|
||||
{"|", &or},
|
||||
pf("cat", catObjects),
|
||||
pf("fil", filter),
|
||||
pft("cat", catObjects),
|
||||
pft("fil", filter),
|
||||
pf("len", len),
|
||||
pf("ap", append),
|
||||
pf("pre", prepend),
|
||||
|
@ -312,22 +369,23 @@ struct Environment defaultEnv()
|
|||
pf("isnum", isNum),
|
||||
pf("islist", isList),
|
||||
pf("isstr", isString),
|
||||
{"iserr", &isErr},
|
||||
pf("iserr", isErr),
|
||||
pf("char", charVal),
|
||||
{"eval", &parseEvalO},
|
||||
{"poss", &possessive},
|
||||
pf("eval", parseEvalO),
|
||||
pf("poss", possessive),
|
||||
#ifdef WEBSERVER
|
||||
pf("get", addGetRoute),
|
||||
pf("post", addPostRoute),
|
||||
pf("serve", startServer),
|
||||
#endif
|
||||
#ifdef STANDALONE
|
||||
{"prn", &print},
|
||||
{"pch", &pChar},
|
||||
{"penv", &printEnvO},
|
||||
//{"sys", &systemCall},
|
||||
{"loadfile", &loadFile},
|
||||
{"inp", &takeInput},
|
||||
pfn(segfault),
|
||||
pf("prn", print),
|
||||
pf("pch", pChar),
|
||||
pf("penv", printEnvO),
|
||||
pf("sys", systemCall),
|
||||
pf("loadfile", loadFile),
|
||||
pf("inp", takeInput),
|
||||
pf("?", help)
|
||||
#endif
|
||||
};
|
||||
|
@ -336,6 +394,7 @@ struct Environment defaultEnv()
|
|||
addFunc(symFuncs[i].sym, symFuncs[i].func, &e);
|
||||
}
|
||||
|
||||
helpInitialized = 1;
|
||||
return e;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ struct Environment {
|
|||
struct StructDef* structDefs;
|
||||
|
||||
int refs;
|
||||
const char* name;
|
||||
};
|
||||
|
||||
struct Environment* global();
|
||||
|
@ -44,4 +45,6 @@ int getStructIndex(struct Environment* env, const char* name);
|
|||
|
||||
const char* getHelp(const char* symbol);
|
||||
|
||||
int runTests();
|
||||
|
||||
#endif
|
||||
|
|
|
@ -36,12 +36,13 @@ and the interpreter won't even instantly crash over it! It's truly astounding
|
|||
stuff, when you think about it."
|
||||
))
|
||||
|
||||
(def homepage (fn () (html (
|
||||
(def homepage (fn (req) (html (
|
||||
(head (
|
||||
(link ((rel "stylesheet") (href "styles.css")))
|
||||
))
|
||||
(body (
|
||||
(h1 "This is a sweet PebbLisp blog")
|
||||
(h1 "This is a sweet PebbLisp site")
|
||||
(p (cat "" req))
|
||||
(htmlize p1)
|
||||
(htmlize p2)))
|
||||
))))
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "object.h"
|
||||
#include "pebblisp.h"
|
||||
#include "env.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
@ -476,11 +477,16 @@ void _printObj(const Object* obj, int newline)
|
|||
printObj(&obj->lambda->body);
|
||||
return;
|
||||
}
|
||||
|
||||
char temp[200] = "";
|
||||
stringObj(temp, obj);
|
||||
if (newline) {
|
||||
printf("%s\n", temp);
|
||||
if (obj->type == TYPE_ERROR) {
|
||||
if (obj->error && obj->error->plContext) {
|
||||
printf("%s\n", obj->error->plContext->text);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf("%s", temp);
|
||||
}
|
||||
|
@ -922,6 +928,7 @@ inline Object errorObject(enum errorCode err)
|
|||
o.error = malloc(sizeof(struct Error));
|
||||
o.error->code = err;
|
||||
o.error->context = NULL;
|
||||
o.error->plContext = NULL;
|
||||
#endif
|
||||
|
||||
return o;
|
||||
|
|
|
@ -85,11 +85,11 @@ typedef struct Object Object;
|
|||
|
||||
struct Lambda;
|
||||
struct Environment;
|
||||
struct Slice;
|
||||
struct Other;
|
||||
struct Error {
|
||||
enum errorCode code;
|
||||
char* context;
|
||||
struct Slice* plContext;
|
||||
};
|
||||
|
||||
struct Object {
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
#ifdef STANDALONE
|
||||
#define _GNU_SOURCE
|
||||
#include <signal.h>
|
||||
#include <ucontext.h>
|
||||
#endif
|
||||
|
||||
#include "pebblisp.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)
|
||||
{
|
||||
struct Error err = noError();
|
||||
|
@ -623,6 +630,7 @@ Object parseEval(const char* input, struct Environment* env)
|
|||
struct Slice* tok = tokens;
|
||||
while (tok[i].text != NULL) {
|
||||
if (tok[i].text[0] == '(') {
|
||||
lastOpen = &tok[i];
|
||||
parens++;
|
||||
} else if (tok[i].text[0] == ')') {
|
||||
parens--;
|
||||
|
@ -633,6 +641,7 @@ Object parseEval(const char* input, struct Environment* env)
|
|||
Object parsed = parse(tok).obj;
|
||||
if (parsed.type == TYPE_ERROR) {
|
||||
obj = parsed; // TODO Check necessity
|
||||
obj.error->plContext = lastOpen;
|
||||
break;
|
||||
}
|
||||
if (tok[i].text[0] == ')') {
|
||||
|
@ -733,10 +742,48 @@ void loadArgsIntoEnv(int argc, const char* argv[], struct Environment* env)
|
|||
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[])
|
||||
{
|
||||
struct Environment env = defaultEnv();
|
||||
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);
|
||||
if (argc >= 2) {
|
||||
FILE* file = fopen(argv[1], "r");
|
||||
|
|
|
@ -6,11 +6,22 @@
|
|||
#include "env.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 {
|
||||
const char* text;
|
||||
unsigned char length;
|
||||
int lineNumber;
|
||||
};
|
||||
|
||||
typedef struct Result {
|
||||
|
@ -43,12 +54,6 @@ Object simpleFuncEval(Object func, Object arg1, Object arg2, struct Environment*
|
|||
|
||||
#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(const char* filename, struct Environment* env);
|
||||
|
|
91
src/plfunc.h
91
src/plfunc.h
|
@ -4,7 +4,7 @@
|
|||
#include "pebblisp.h"
|
||||
|
||||
#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);
|
||||
|
||||
|
@ -28,85 +28,118 @@ BASIC_OP(or);
|
|||
|
||||
#undef BASIC_OP
|
||||
|
||||
F(catObjects,
|
||||
"Concatenate string versions of the given objects.\n"
|
||||
"(cat \"Stuff: \" (1 2 3)) => \"Stuff: ( 1 2 3 )\""
|
||||
fnt(catObjects,
|
||||
"Concatenate string versions of the given objects.\n",
|
||||
"(cat \"Stuff: \" (1 2 3))", "Stuff: ( 1 2 3 )"
|
||||
)(Object obj1, Object obj2, struct Environment* env);
|
||||
|
||||
F(filter, "(filter (< 50) (25 60 100)) => ( 60 100 )")
|
||||
(Object condition, Object list, struct Environment* env);
|
||||
fnt(filter,
|
||||
"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);
|
||||
|
||||
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);
|
||||
|
||||
F(len, "(len (2 3)) => 2")
|
||||
fn(len, "(len (2 3)) => 2")
|
||||
(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);
|
||||
|
||||
F(at, "(at 1 (1 2 3)) => 2")
|
||||
fn(at, "(at 1 (1 2 3)) => 2")
|
||||
(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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
F(isList,
|
||||
fn(isList,
|
||||
"(islist (1 2 3)) => T\n"
|
||||
"(islist ()) => T\n"
|
||||
"(islist \"Stringy\") => F"
|
||||
)(Object test, Object ignore, struct Environment* ignore2);
|
||||
|
||||
F(isString,
|
||||
fn(isString,
|
||||
"(isstr \"Heyo\") => T\n"
|
||||
"(isstr \"\") => T\n"
|
||||
"(isstr 10) => F"
|
||||
)(Object test, Object ignore, struct Environment* ignore2);
|
||||
|
||||
F(isErr, "")
|
||||
(Object test, Object ignore, struct Environment* ignore2);
|
||||
fn(isErr,
|
||||
"(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\" 10) => \"\""
|
||||
)(Object string, Object at, struct Environment* ignore);
|
||||
|
||||
F(charVal,
|
||||
fn(charVal,
|
||||
"(char \"h\") => 104\n"
|
||||
"(char \"hello\") => 104\n"
|
||||
"(char \"\") => 0"
|
||||
)(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);
|
||||
|
||||
F(possessive,
|
||||
"(struct Post (title body)) (def p (Post \"TI\" \"BO\")) p's title => TI"
|
||||
fn(possessive,
|
||||
"(struct Post (title body))\n"
|
||||
"(def p (Post \"TI\" \"BO\"))\n"
|
||||
"p's title => TI"
|
||||
)(Object structo, Object field, struct Environment* env);
|
||||
|
||||
#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);
|
||||
|
||||
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);
|
||||
|
||||
F(printEnvO, "Prints out the current scoped environment.")
|
||||
fn(printEnvO, "Prints out the current scoped environment.")
|
||||
(Object i1, Object i2, struct Environment* env);
|
||||
|
||||
F(help, "(? +) => \"(+ 1 2) => 3\"")
|
||||
(Object symbol, Object ignore, struct Environment* ignore2);
|
||||
fn(systemCall,
|
||||
"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
|
||||
|
|
23
src/tests.sh
23
src/tests.sh
|
@ -55,21 +55,26 @@ check() {
|
|||
return 1
|
||||
fi
|
||||
|
||||
local output
|
||||
if $VALGRIND; then
|
||||
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
|
||||
local output="$(./pl "(loadfile \"examples/lib.pbl\") $2" | grep -v PLT)"
|
||||
output="$(./pl "(loadfile \"examples/lib.pbl\") $2" | grep -v PLT)"
|
||||
fi
|
||||
|
||||
if [ "$output" == "$3" ]; then
|
||||
if [ "$3" == "$regex" ]; then
|
||||
if [[ "$output" =~ ^$4$ ]]; then
|
||||
pass "$1"
|
||||
elif [ "$3" == "$regex" ] && [[ "$output" =~ $4 ]]; then
|
||||
return
|
||||
fi
|
||||
elif [ "$output" == "$3" ]; then
|
||||
pass "$1"
|
||||
else
|
||||
return
|
||||
fi
|
||||
|
||||
fail "$1" "$2"
|
||||
FAIL_OUTPUT="${FAIL_OUTPUT}\n [31m expected '$3' but received '$output'\n"
|
||||
fi
|
||||
}
|
||||
|
||||
echo "[1;33mSTARTING TESTS[0;m"
|
||||
|
@ -206,9 +211,9 @@ title "ShouldError"
|
|||
check "LenOfNotList" "(len 5)" "NOT_A_LIST"
|
||||
check "NoMapList" "(map sq)" "( )"
|
||||
check "UnevenLists" "(+ (1 2) (1 2 3))" "LISTS_NOT_SAME_SIZE"
|
||||
check "BadNumber" "(5df)" "BAD_NUMBER"
|
||||
check "BadHex" "(0x0zf)" "BAD_NUMBER"
|
||||
check "BadBinary" "(0b01120)" "BAD_NUMBER"
|
||||
check "BadNumber" "(5df)" regex "BAD_NUMBER.*"
|
||||
check "BadHex" "(0x0zf)" regex "BAD_NUMBER.*"
|
||||
check "BadBinary" "(0b01120)" regex "BAD_NUMBER.*"
|
||||
check "BadParens1" "(hey()" regex "'MISMATCHED_PARENS.*"
|
||||
check "BadParens2" "(hey)(" regex "'MISMATCHED_PARENS.*"
|
||||
check "BadParens3" "((hey(" regex "'MISMATCHED_PARENS.*"
|
||||
|
|
11
src/tokens.c
11
src/tokens.c
|
@ -66,6 +66,7 @@ struct Slice* nf_tokenize(const char* input, struct Error* err)
|
|||
|
||||
int i = 0;
|
||||
int slice = 0;
|
||||
int lineNumber = 1;
|
||||
|
||||
int parens = 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]);
|
||||
|
||||
if (isWhitespace(input[i]) || input[i] == ';') {
|
||||
if (input[i] == '\n') {
|
||||
lineNumber++;
|
||||
}
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
@ -92,6 +96,7 @@ struct Slice* nf_tokenize(const char* input, struct Error* err)
|
|||
}
|
||||
|
||||
slices[slice].text = &input[i];
|
||||
slices[slice].lineNumber = lineNumber;
|
||||
|
||||
if (isSingle(input[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] == '"') {
|
||||
break;
|
||||
}
|
||||
if (input[i] == '\n') {
|
||||
lineNumber++;
|
||||
}
|
||||
l++;
|
||||
if (input[i] == '\0' || input[i + 1] == '\0' || input[i + 2] == '\0') {
|
||||
err->context = malloc(sizeof(char) * ERR_LEN + 1);
|
||||
|
@ -118,6 +126,9 @@ struct Slice* nf_tokenize(const char* input, struct Error* err)
|
|||
} else {
|
||||
// Simple string
|
||||
while (input[++i] != '"' && input[i] != '\0') {
|
||||
if (input[i] == '\n') {
|
||||
lineNumber++;
|
||||
}
|
||||
l++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,8 +80,8 @@ answer_to_connection(void* cls, struct MHD_Connection* connection,
|
|||
Object queryParams = listObject();
|
||||
MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, add_query_param, &queryParams);
|
||||
|
||||
Object res = structObject(requestDefinition);
|
||||
res.structObject->fields[0] = queryParams;
|
||||
Object res = numberObject(1010);//structObject(requestDefinition);
|
||||
//res.structObject->fields[0] = queryParams;
|
||||
Object route = cloneObject(routes[i].routeAction);
|
||||
|
||||
Object result = listEvalLambda(&route, &res, routes[i].env);
|
||||
|
|
|
@ -16,21 +16,21 @@ int addRoute(struct Route route);
|
|||
|
||||
int start(int port);
|
||||
|
||||
F(startServer,
|
||||
fn(startServer,
|
||||
"(serve) => 0\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"
|
||||
" A simple way would be to use (inp) immediately after the (serve) call."
|
||||
)(Object path, Object textFunc, struct Environment* env);
|
||||
|
||||
F(addGetRoute,
|
||||
fn(addGetRoute,
|
||||
"Note: Implementation bugs currently prevent using an inline lambda.\n"
|
||||
" (def homepage (fn () (\"Hello, world!\")));(get \"/\" homepage)\n"
|
||||
" (def queryPage (fn (req) (req's queryParams)));(get \"/x\" queryPage)\n"
|
||||
" (serve)\n"
|
||||
)(Object path, Object textFunc, struct Environment* env);
|
||||
|
||||
F(addPostRoute,
|
||||
fn(addPostRoute,
|
||||
"Note: Implementation bugs currently prevent using an inline lambda.\n"
|
||||
" (def homepage (fn () (\"Hello, world!\")));(post \"/\" homepage)\n"
|
||||
" (serve)\n"
|
||||
|
|
Loading…
Reference in New Issue