Add help text for STANDALONE.
Pull most user functions into the new plfunc. Could integrate some tests directly into pl with --run-tests
This commit is contained in:
parent
30e8c87e66
commit
3bf65577c0
|
@ -1,4 +1,4 @@
|
|||
files = pebblisp.c tokens.c object.c env.c web.c
|
||||
files = pebblisp.c tokens.c object.c env.c web.c plfunc.c
|
||||
libs = -lreadline -lmicrohttpd
|
||||
exe = pl
|
||||
|
||||
|
@ -9,7 +9,7 @@ SCRIPTDIR ?= /usr/local/share/pebblisp
|
|||
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
mkfile_dir := $(dir $(mkfile_path))
|
||||
|
||||
GCC_COM ?= gcc -g -O0 -Wall -o $(exe) -D STANDALONE -DSCRIPTDIR=\"$(SCRIPTDIR)\"
|
||||
GCC_COM ?= gcc -g -O0 -Wall -o $(exe) -D WEBSERVER -D STANDALONE -DSCRIPTDIR=\"$(SCRIPTDIR)\"
|
||||
|
||||
all:
|
||||
$(GCC_COM) $(files) $(libs) && echo && ./tests.sh
|
||||
|
|
77
src/env.c
77
src/env.c
|
@ -5,6 +5,8 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "pebblisp.h"
|
||||
#include "web.h"
|
||||
#include "plfunc.h"
|
||||
|
||||
Object fetchFromEnvironment(const char* name, struct Environment* env)
|
||||
{
|
||||
|
@ -223,16 +225,48 @@ struct symFunc {
|
|||
Object (* func)(Object, Object, struct Environment*);
|
||||
};
|
||||
|
||||
struct Environment* _global;
|
||||
struct Environment* globalEnv;
|
||||
|
||||
struct Environment* global()
|
||||
{
|
||||
return _global;
|
||||
return globalEnv;
|
||||
}
|
||||
|
||||
void setGlobal(struct Environment* env)
|
||||
{
|
||||
_global = env;
|
||||
globalEnv = env;
|
||||
}
|
||||
|
||||
struct helpText {
|
||||
const char* symbol;
|
||||
const char* help;
|
||||
};
|
||||
int currentHelp = 0;
|
||||
struct helpText helpTexts[100];
|
||||
|
||||
#define pf(_name, _func) buildHelp(_name, &(_func), _func ## Doc)
|
||||
|
||||
struct symFunc buildHelp(const char* symbol, Object (* func)(Object, Object, struct Environment*), const char* help)
|
||||
{
|
||||
helpTexts[currentHelp].help = help;
|
||||
helpTexts[currentHelp].symbol = symbol;
|
||||
currentHelp += 1;
|
||||
|
||||
return (struct symFunc) {
|
||||
.func = func,
|
||||
.sym = symbol,
|
||||
};
|
||||
}
|
||||
|
||||
const 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;
|
||||
}
|
||||
}
|
||||
return "Help not found!";
|
||||
}
|
||||
|
||||
struct Environment defaultEnv()
|
||||
|
@ -263,25 +297,30 @@ struct Environment defaultEnv()
|
|||
{"<", <h},
|
||||
{"&", &and},
|
||||
{"|", &or},
|
||||
{"cat", &catObjects},
|
||||
{"fil", &filter},
|
||||
{"len", &len},
|
||||
{"ap", &append},
|
||||
{"pre", &prepend},
|
||||
{"reduce", &reduce},
|
||||
{"at", &at},
|
||||
{"rest", &rest},
|
||||
{"chat", &charAt},
|
||||
pf("cat", catObjects),
|
||||
pf("fil", filter),
|
||||
pf("len", len),
|
||||
pf("ap", append),
|
||||
pf("pre", prepend),
|
||||
pf("reduce", reduce),
|
||||
pf("at", at),
|
||||
pf("rest", rest),
|
||||
pf("chat", charAt),
|
||||
#ifndef LOW_MEM
|
||||
{"rev", &reverse},
|
||||
pf("rev", reverse),
|
||||
#endif
|
||||
{"isnum", &isNum},
|
||||
{"islist", &isList},
|
||||
{"isstr", &isString},
|
||||
pf("isnum", isNum),
|
||||
pf("islist", isList),
|
||||
pf("isstr", isString),
|
||||
{"iserr", &isErr},
|
||||
{"char", &charVal},
|
||||
pf("char", charVal),
|
||||
{"eval", &parseEvalO},
|
||||
{"poss", &possessive},
|
||||
#ifdef WEBSERVER
|
||||
pf("get", addGetRoute),
|
||||
pf("post", addPostRoute),
|
||||
pf("serve", startServer),
|
||||
#endif
|
||||
#ifdef STANDALONE
|
||||
{"prn", &print},
|
||||
{"pch", &pChar},
|
||||
|
@ -289,9 +328,7 @@ struct Environment defaultEnv()
|
|||
//{"sys", &systemCall},
|
||||
{"loadfile", &loadFile},
|
||||
{"inp", &takeInput},
|
||||
{"get", &addGetRoute},
|
||||
{"post", &addPostRoute},
|
||||
{"serve", &startServer}
|
||||
pf("?", help)
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -42,4 +42,6 @@ struct StructDef getStructDef(struct Environment* env, const char* name);
|
|||
|
||||
int getStructIndex(struct Environment* env, const char* name);
|
||||
|
||||
const char* getHelp(const char* symbol);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -45,15 +45,6 @@ int listLength(const Object* listObj)
|
|||
return len;
|
||||
}
|
||||
|
||||
Object len(Object obj1, Object o_ignore, struct Environment* e_ignore)
|
||||
{
|
||||
Object o = numberObject(listLength(&obj1));
|
||||
if (o.number < 0) {
|
||||
return errorObject(NOT_A_LIST);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pointer to the Object at the given index in a given list
|
||||
* @param listObj The list to fetch an Object from
|
||||
|
|
|
@ -244,9 +244,6 @@ struct Error noError();
|
|||
|
||||
Object constructLambda(const Object* params, const Object* body, struct Environment* env);
|
||||
|
||||
// Object version of listLength()
|
||||
Object len(Object obj1, Object, struct Environment*);
|
||||
|
||||
int getAllocations();
|
||||
|
||||
size_t getBytes();
|
||||
|
|
408
src/pebblisp.c
408
src/pebblisp.c
|
@ -1,6 +1,5 @@
|
|||
#include "pebblisp.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
@ -8,6 +7,7 @@
|
|||
#include <readline/history.h>
|
||||
|
||||
#include "tokens.h"
|
||||
#include "plfunc.h"
|
||||
|
||||
#ifdef STANDALONE
|
||||
|
||||
|
@ -414,371 +414,6 @@ Object eval(const Object* obj, struct Environment* env)
|
|||
return errorObject(BAD_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* (reduce (list, initial) (fn (prev total) (+ prev total)))
|
||||
*/
|
||||
Object reduce(const Object listInitial, const Object func, struct Environment* env)
|
||||
{
|
||||
Object* list = itemAt(&listInitial, 0);
|
||||
Object total = cloneObject(*list->forward); // From given initial value
|
||||
|
||||
if (list->type != TYPE_LIST) {
|
||||
return simpleFuncEval(func, total, *list, env);
|
||||
}
|
||||
|
||||
FOR_POINTER_IN_LIST(list) {
|
||||
total = simpleFuncEval(func, total, *POINTER, env);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
#define CAT_MAX 1024
|
||||
|
||||
Object catObjects(const Object obj1, const Object obj2, struct Environment* env)
|
||||
{
|
||||
Object evalObj1 = eval(&obj1, env);
|
||||
Object evalObj2 = eval(&obj2, env);
|
||||
if (isError(evalObj2, ONLY_ONE_ARGUMENT)) {
|
||||
return evalObj1;
|
||||
}
|
||||
|
||||
char str1[CAT_MAX] = "";
|
||||
char str2[CAT_MAX] = "";
|
||||
stringObj(str1, &evalObj1);
|
||||
stringObj(str2, &evalObj2);
|
||||
cleanObject(&evalObj1);
|
||||
cleanObject(&evalObj2);
|
||||
size_t length = strlen(str1) + strlen(str2) + 1;
|
||||
|
||||
Object o = newObject(TYPE_STRING);
|
||||
o.string = calloc(sizeof(char), length);
|
||||
strcat(o.string, str1);
|
||||
strcat(o.string, str2);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
Object listEquality(const Object* list1, const Object* list2)
|
||||
{
|
||||
FOR_POINTERS_IN_LISTS(list1, list2) {
|
||||
if (P1->type != P2->type || P1->number != P2->number) {
|
||||
return boolObject(0);
|
||||
}
|
||||
}
|
||||
return boolObject(1);
|
||||
}
|
||||
|
||||
Object _basicOp(const Object* obj1, const Object* obj2, const char op,
|
||||
struct Environment* env)
|
||||
{
|
||||
const int n1 = obj1->number;
|
||||
const int n2 = obj2->number;
|
||||
|
||||
switch (op) {
|
||||
case '+':
|
||||
if (eitherIs(TYPE_STRING, obj1, obj2)) {
|
||||
return catObjects(*obj1, *obj2, env);
|
||||
}
|
||||
return numberObject(n1 + n2);
|
||||
case '-':
|
||||
return numberObject(n1 - n2);
|
||||
case '*':
|
||||
return numberObject(n1 * n2);
|
||||
case '/':
|
||||
return numberObject(n1 / n2);
|
||||
case '%':
|
||||
return numberObject(n1 % n2);
|
||||
|
||||
case '&':
|
||||
return boolObject(n1 != 0 && n2 != 0);
|
||||
case '|':
|
||||
return boolObject(n1 != 0 || n2 != 0);
|
||||
|
||||
case '=':
|
||||
if (bothAre(TYPE_STRING, obj1, obj2)) {
|
||||
return boolObject(!strcmp(obj1->string, obj2->string));
|
||||
}
|
||||
if (bothAre(TYPE_LIST, obj1, obj2)) {
|
||||
return listEquality(obj1, obj2);
|
||||
}
|
||||
return boolObject(n1 == n2 && areSameType(obj1, obj2));
|
||||
case '>':
|
||||
return boolObject(n1 > n2);
|
||||
case '<':
|
||||
return boolObject(n1 < n2);
|
||||
default:
|
||||
return *obj1;
|
||||
}
|
||||
}
|
||||
|
||||
Object basicOp(const Object* obj1, const Object* obj2, const char op,
|
||||
struct Environment* env)
|
||||
{
|
||||
if (isError(*obj2, ONLY_ONE_ARGUMENT)) {
|
||||
return *obj2;
|
||||
}
|
||||
|
||||
int lists = (obj1->type == TYPE_LIST) + (obj2->type == TYPE_LIST);
|
||||
if (lists == 0) {
|
||||
return _basicOp(obj1, obj2, op, env);
|
||||
|
||||
} 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;
|
||||
|
||||
Object newList = listObject();
|
||||
FOR_POINTER_IN_LIST(listObj) {
|
||||
Object adding = eval(POINTER, env);
|
||||
nf_addToList(&newList, _basicOp(&adding, singleObj, op, env));
|
||||
}
|
||||
return newList;
|
||||
|
||||
} 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) {
|
||||
const Object ev1 = eval(P1, env);
|
||||
const Object ev2 = eval(P2, env);
|
||||
nf_addToList(&newList, _basicOp(&ev1, &ev2, op, env));
|
||||
}
|
||||
return newList;
|
||||
} else {
|
||||
return errorObject(LISTS_NOT_SAME_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define BASIC_OP(_name, _char) \
|
||||
Object _name(Object obj1, Object obj2, struct Environment *env) \
|
||||
{ \
|
||||
return basicOp(&obj1, &obj2, _char, env); \
|
||||
}
|
||||
|
||||
BASIC_OP(add, '+');
|
||||
|
||||
BASIC_OP(sub, '-');
|
||||
|
||||
BASIC_OP(mul, '*');
|
||||
|
||||
BASIC_OP(dvi, '/');
|
||||
|
||||
BASIC_OP(mod, '%');
|
||||
|
||||
BASIC_OP(equ, '=');
|
||||
|
||||
BASIC_OP(gth, '>');
|
||||
|
||||
BASIC_OP(lth, '<');
|
||||
|
||||
BASIC_OP(and, '&');
|
||||
|
||||
BASIC_OP(or, '|');
|
||||
|
||||
#undef BASIC_OP
|
||||
|
||||
Object filter(Object obj1, Object obj2, struct Environment* env)
|
||||
{
|
||||
Object filteredList = listObject();
|
||||
Object* filteringList = &obj2;
|
||||
FOR_POINTER_IN_LIST(filteringList) {
|
||||
Object conditional = cloneObject(obj1);
|
||||
nf_addToList(&conditional, *POINTER); // cloneObject()?
|
||||
Object result = eval(&conditional, env);
|
||||
cleanObject(&conditional);
|
||||
if (result.number == 1) {
|
||||
nf_addToList(&filteredList, *POINTER);
|
||||
}
|
||||
}
|
||||
return filteredList;
|
||||
}
|
||||
|
||||
Object append(Object list, Object newElement, struct Environment* env)
|
||||
{
|
||||
Object newList = cloneObject(list);
|
||||
nf_addToList(&newList, cloneObject(newElement));
|
||||
return newList;
|
||||
}
|
||||
|
||||
Object prepend(Object list, Object newElement, struct Environment* env)
|
||||
{
|
||||
Object newList = listObject();
|
||||
nf_addToList(&newList, cloneObject(newElement));
|
||||
appendList(&newList, &list);
|
||||
return newList;
|
||||
}
|
||||
|
||||
Object at(Object index, Object list, struct Environment* env)
|
||||
{
|
||||
const Object* found = itemAt(&list, index.number);
|
||||
if (found) {
|
||||
return cloneObject(*found);
|
||||
} else {
|
||||
return errorObject(INDEX_PAST_END);
|
||||
}
|
||||
}
|
||||
|
||||
Object rest(Object list, Object ignore, struct Environment* env)
|
||||
{
|
||||
Object ret = listObject();
|
||||
Object* l = &list;
|
||||
FOR_POINTER_IN_LIST(l) {
|
||||
if (POINTER == l->list) {
|
||||
continue;
|
||||
}
|
||||
nf_addToList(&ret, cloneObject(*POINTER));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Object reverse(Object _list, Object ignore, struct Environment* ignore2)
|
||||
{
|
||||
const Object* list = &_list;
|
||||
Object rev = listObject();
|
||||
|
||||
Object* tail = NULL;
|
||||
FOR_POINTER_IN_LIST(list) {
|
||||
Object* oldTail = tail;
|
||||
allocObject(&tail, cloneObject(*POINTER));
|
||||
if (oldTail) {
|
||||
tail->forward = oldTail;
|
||||
}
|
||||
}
|
||||
|
||||
rev.list = tail;
|
||||
return rev;
|
||||
}
|
||||
|
||||
Object isNum(Object test, Object ignore, struct Environment* ignore2)
|
||||
{
|
||||
return test.type == TYPE_NUMBER ? boolObject(1) : boolObject(0);
|
||||
}
|
||||
|
||||
Object isList(Object test, Object ignore, struct Environment* ignore2)
|
||||
{
|
||||
return test.type == TYPE_LIST ? boolObject(1) : boolObject(0);
|
||||
}
|
||||
|
||||
Object isString(Object test, Object ignore, struct Environment* ignore2)
|
||||
{
|
||||
return test.type == TYPE_STRING ? boolObject(1) : boolObject(0);
|
||||
}
|
||||
|
||||
// Get the int value of a string's first character
|
||||
Object charVal(Object test, Object ignore, struct Environment* ignore2)
|
||||
{
|
||||
return numberObject(test.string[0]);
|
||||
// return test.type == TYPE_STRING && test.string[0] == '\0' ?
|
||||
// boolObject(1) : boolObject(0);
|
||||
}
|
||||
|
||||
Object isErr(Object test, Object ignore, struct Environment* ignore2)
|
||||
{
|
||||
return test.type == TYPE_ERROR ? boolObject(1) : boolObject(0);
|
||||
}
|
||||
|
||||
Object charAt(Object string, Object at, struct Environment* ignore)
|
||||
{
|
||||
char* c = malloc(sizeof(char) * 2);
|
||||
c[0] = string.string[at.number];
|
||||
c[1] = '\0';
|
||||
string.string = c;
|
||||
return string;
|
||||
}
|
||||
|
||||
#ifdef STANDALONE
|
||||
|
||||
Object print(Object p, Object ignore, struct Environment* env)
|
||||
{
|
||||
Object c = cloneObject(p);
|
||||
Object e = eval(&c, env);
|
||||
_printObj(&e, 0);
|
||||
cleanObject(&c);
|
||||
cleanObject(&e);
|
||||
return numberObject(0);
|
||||
}
|
||||
|
||||
void addRouteO(Object path, Object textFunc, struct Environment* env, enum RouteType type)
|
||||
{
|
||||
char* p = malloc(sizeof(char) * strlen(path.string) + 1);
|
||||
strcpy(p, path.string);
|
||||
|
||||
struct Route r;
|
||||
r.path = p;
|
||||
r.routeAction = cloneObject(textFunc);
|
||||
r.env = env;
|
||||
r.type = type;
|
||||
env->refs += 1;
|
||||
//r.text = t;
|
||||
addRoute(r);
|
||||
}
|
||||
|
||||
Object addGetRoute(Object path, Object textFunc, struct Environment* env)
|
||||
{
|
||||
addRouteO(path, textFunc, env, GET);
|
||||
return numberObject(1);
|
||||
}
|
||||
|
||||
Object addPostRoute(Object path, Object textFunc, struct Environment* env)
|
||||
{
|
||||
addRouteO(path, textFunc, env, POST);
|
||||
return numberObject(1);
|
||||
}
|
||||
|
||||
Object startServer(Object portObject, Object ignored, struct Environment* env)
|
||||
{
|
||||
int port = 8888;
|
||||
if (portObject.type == TYPE_NUMBER) {
|
||||
port = portObject.number;
|
||||
}
|
||||
return numberObject(start(port));
|
||||
}
|
||||
|
||||
Object pChar(Object c, Object i1, struct Environment* i2)
|
||||
{
|
||||
if (c.type != TYPE_NUMBER) {
|
||||
return errorObject(BAD_NUMBER);
|
||||
}
|
||||
printf("%c", c.number % 256);
|
||||
return numberObject(0);
|
||||
}
|
||||
|
||||
Object printEnvO(Object i1, Object i2, struct Environment* env)
|
||||
{
|
||||
printEnv(global());
|
||||
return numberObject(0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Object parseEvalO(Object text, Object ignore, struct Environment* env)
|
||||
{
|
||||
if (text.type == TYPE_SYMBOL) {
|
||||
Object string = eval(&text, env);
|
||||
Object parsed = parseEval(string.string, env);
|
||||
cleanObject(&string);
|
||||
return parsed;
|
||||
} else if (text.type != TYPE_STRING) {
|
||||
return errorObject(CAN_ONLY_EVAL_STRINGS);
|
||||
}
|
||||
return parseEval(text.string, env);
|
||||
}
|
||||
|
||||
#ifdef STANDALONE
|
||||
|
||||
Object takeInput(Object prompt, Object i2, struct Environment* i3)
|
||||
{
|
||||
if (prompt.type == TYPE_STRING) {
|
||||
printf("%s", prompt.string);
|
||||
}
|
||||
char input[256] = "";
|
||||
fgets(input, 256, stdin);
|
||||
return stringFromSlice(input, strlen(input) - 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void copySlice(char* dest, struct Slice* src)
|
||||
{
|
||||
if (!dest || !src) {
|
||||
|
@ -925,9 +560,9 @@ Result parseAtom(struct Slice* s)
|
|||
if (c != '0' || s->length == 1) {
|
||||
return (Result) {parseDecimal(s), s};
|
||||
#ifndef LOW_MEM
|
||||
} else if (c == '0' && s->text[1] == 'x') {
|
||||
} else if (s->text[1] == 'x') {
|
||||
return (Result) {parseHex(s), s};
|
||||
} else if (c == '0' && s->text[1] == 'b') {
|
||||
} else if (s->text[1] == 'b') {
|
||||
return (Result) {parseBin(s), s};
|
||||
#endif
|
||||
} else {
|
||||
|
@ -1021,6 +656,16 @@ Object parseEval(const char* input, struct Environment* env)
|
|||
|
||||
#ifdef STANDALONE
|
||||
|
||||
int readFile(const char* filename, struct Environment* env)
|
||||
{
|
||||
FILE* input = fopen(filename, "r");
|
||||
if (!input) {
|
||||
return 1;
|
||||
}
|
||||
_readFile(input, env);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _readFile(FILE* input, struct Environment* env)
|
||||
{
|
||||
Object r = numberObject(0);
|
||||
|
@ -1063,33 +708,6 @@ int _readFile(FILE* input, struct Environment* env)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int readFile(const char* filename, struct Environment* env)
|
||||
{
|
||||
FILE* input = fopen(filename, "r");
|
||||
if (!input) {
|
||||
return 1;
|
||||
}
|
||||
_readFile(input, env);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Object loadFile(Object filename, Object _, struct Environment* env)
|
||||
{
|
||||
if (isStringy(filename)) {
|
||||
readFile(filename.string, env);
|
||||
return numberObject(0);
|
||||
}
|
||||
return numberObject(1);
|
||||
}
|
||||
|
||||
Object systemCall(Object process, Object _, struct Environment* env)
|
||||
{
|
||||
if (isStringy(process)) {
|
||||
return numberObject(system(process.string));
|
||||
}
|
||||
return numberObject(255);
|
||||
}
|
||||
|
||||
void repl(struct Environment* env)
|
||||
{
|
||||
char* buf;
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
#ifndef PEBBLISP_H
|
||||
#define PEBBLISP_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "env.h"
|
||||
#include "object.h"
|
||||
|
||||
#define F(_name, _docs) static const char * const _name ## Doc = _docs; Object _name
|
||||
|
||||
struct Slice {
|
||||
const char* text;
|
||||
unsigned char length;
|
||||
|
@ -35,67 +39,7 @@ Object listEvalLambda(Object* lambda, const Object* remaining,
|
|||
|
||||
void debugSlice(struct Slice* s);
|
||||
|
||||
#define BASIC_OP(_name) \
|
||||
Object _name(Object obj1, Object obj2, struct Environment *env);
|
||||
|
||||
BASIC_OP(add);
|
||||
|
||||
BASIC_OP(sub);
|
||||
|
||||
BASIC_OP(mul);
|
||||
|
||||
BASIC_OP(dvi);
|
||||
|
||||
BASIC_OP(mod);
|
||||
|
||||
BASIC_OP(equ);
|
||||
|
||||
BASIC_OP(gth);
|
||||
|
||||
BASIC_OP(lth);
|
||||
|
||||
BASIC_OP(and);
|
||||
|
||||
BASIC_OP(or);
|
||||
#undef BASIC_OP
|
||||
|
||||
Object catObjects(Object obj1, Object obj2, struct Environment* env);
|
||||
|
||||
Object filter(Object obj1, Object obj2, struct Environment* env);
|
||||
|
||||
Object append(Object list, Object newElement, struct Environment* env);
|
||||
|
||||
Object prepend(Object list, Object newElement, struct Environment* env);
|
||||
|
||||
Object reduce(Object listInitial, Object func, struct Environment* env);
|
||||
|
||||
Object at(Object index, Object list, struct Environment* env);
|
||||
|
||||
Object rest(Object list, Object ignore, struct Environment* env);
|
||||
|
||||
Object reverse(Object _list, Object ignore, struct Environment* ignore2);
|
||||
|
||||
Object isNum(Object test, Object ignore, struct Environment* ignore2);
|
||||
|
||||
Object isList(Object test, Object ignore, struct Environment* ignore2);
|
||||
|
||||
Object isString(Object test, Object ignore, struct Environment* ignore2);
|
||||
|
||||
Object isErr(Object test, Object ignore, struct Environment* ignore2);
|
||||
|
||||
Object charAt(Object string, Object at, struct Environment* ignore);
|
||||
|
||||
Object charVal(Object test, Object ignore, struct Environment* ignore2);
|
||||
|
||||
Object print(Object p, Object ignore, struct Environment* ignore2);
|
||||
|
||||
Object pChar(Object c, Object i1, struct Environment* i2);
|
||||
|
||||
Object printEnvO(Object i1, Object i2, struct Environment* env);
|
||||
|
||||
Object parseEvalO(Object text, Object ignore, struct Environment* env);
|
||||
|
||||
Object possessive(Object structo, Object field, struct Environment* env);
|
||||
Object simpleFuncEval(Object func, Object arg1, Object arg2, struct Environment* env);
|
||||
|
||||
#ifdef STANDALONE
|
||||
|
||||
|
@ -105,12 +49,10 @@ Object systemCall(Object call, Object _, struct Environment* i3);
|
|||
|
||||
Object loadFile(Object filename, Object _, struct Environment* env);
|
||||
|
||||
Object startServer(Object path, Object textFunc, struct Environment* env);
|
||||
int _readFile(FILE* input, struct Environment* env);
|
||||
|
||||
Object addGetRoute(Object path, Object textFunc, struct Environment* env);
|
||||
int readFile(const char* filename, struct Environment* env);
|
||||
|
||||
Object addPostRoute(Object path, Object textFunc, struct Environment* env);
|
||||
|
||||
#endif
|
||||
#endif /* STANDALONE */
|
||||
|
||||
#endif
|
|
@ -0,0 +1,350 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "plfunc.h"
|
||||
|
||||
/**
|
||||
* (reduce (list, initial) (fn (prev total) (+ prev total)))
|
||||
*/
|
||||
Object reduce(const Object listInitial, const Object func, struct Environment* env)
|
||||
{
|
||||
Object* list = itemAt(&listInitial, 0);
|
||||
Object total = cloneObject(*list->forward); // From given initial value
|
||||
|
||||
if (list->type != TYPE_LIST) {
|
||||
return simpleFuncEval(func, total, *list, env);
|
||||
}
|
||||
|
||||
FOR_POINTER_IN_LIST(list) {
|
||||
total = simpleFuncEval(func, total, *POINTER, env);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
Object charAt(Object string, Object at, struct Environment* ignore)
|
||||
{
|
||||
char* c = malloc(sizeof(char) * 2);
|
||||
c[0] = string.string[at.number];
|
||||
c[1] = '\0';
|
||||
string.string = c;
|
||||
return string;
|
||||
}
|
||||
|
||||
Object filter(Object condition, Object list, struct Environment* env)
|
||||
{
|
||||
Object filteredList = listObject();
|
||||
FOR_POINTER_IN_LIST(&list) {
|
||||
Object conditional = cloneObject(condition);
|
||||
nf_addToList(&conditional, *POINTER);
|
||||
Object result = eval(&conditional, env);
|
||||
cleanObject(&conditional);
|
||||
if (result.number == 1) {
|
||||
nf_addToList(&filteredList, *POINTER);
|
||||
}
|
||||
}
|
||||
return filteredList;
|
||||
}
|
||||
|
||||
Object append(Object list, Object newElement, struct Environment* env)
|
||||
{
|
||||
Object newList = cloneObject(list);
|
||||
nf_addToList(&newList, cloneObject(newElement));
|
||||
return newList;
|
||||
}
|
||||
|
||||
Object prepend(Object list, Object newElement, struct Environment* env)
|
||||
{
|
||||
Object newList = listObject();
|
||||
nf_addToList(&newList, cloneObject(newElement));
|
||||
appendList(&newList, &list);
|
||||
return newList;
|
||||
}
|
||||
|
||||
Object at(Object index, Object list, struct Environment* env)
|
||||
{
|
||||
const Object* found = itemAt(&list, index.number);
|
||||
if (found) {
|
||||
return cloneObject(*found);
|
||||
} else {
|
||||
return errorObject(INDEX_PAST_END);
|
||||
}
|
||||
}
|
||||
|
||||
Object rest(Object list, Object ignore, struct Environment* env)
|
||||
{
|
||||
Object ret = listObject();
|
||||
Object* l = &list;
|
||||
FOR_POINTER_IN_LIST(l) {
|
||||
if (POINTER == l->list) {
|
||||
continue;
|
||||
}
|
||||
nf_addToList(&ret, cloneObject(*POINTER));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Object reverse(Object _list, Object ignore, struct Environment* ignore2)
|
||||
{
|
||||
const Object* list = &_list;
|
||||
Object rev = listObject();
|
||||
|
||||
Object* tail = NULL;
|
||||
FOR_POINTER_IN_LIST(list) {
|
||||
Object* oldTail = tail;
|
||||
allocObject(&tail, cloneObject(*POINTER));
|
||||
if (oldTail) {
|
||||
tail->forward = oldTail;
|
||||
}
|
||||
}
|
||||
|
||||
rev.list = tail;
|
||||
return rev;
|
||||
}
|
||||
|
||||
Object isNum(Object test, Object ignore, struct Environment* ignore2)
|
||||
{
|
||||
return test.type == TYPE_NUMBER ? boolObject(1) : boolObject(0);
|
||||
}
|
||||
|
||||
Object isList(Object test, Object ignore, struct Environment* ignore2)
|
||||
{
|
||||
return test.type == TYPE_LIST ? boolObject(1) : boolObject(0);
|
||||
}
|
||||
|
||||
Object isString(Object test, Object ignore, struct Environment* ignore2)
|
||||
{
|
||||
return test.type == TYPE_STRING ? boolObject(1) : boolObject(0);
|
||||
}
|
||||
|
||||
// Get the int value of a string's first character
|
||||
Object charVal(Object test, Object ignore, struct Environment* ignore2)
|
||||
{
|
||||
return numberObject(test.string[0]);
|
||||
// return test.type == TYPE_STRING && test.string[0] == '\0' ?
|
||||
// boolObject(1) : boolObject(0);
|
||||
}
|
||||
|
||||
Object isErr(Object test, Object ignore, struct Environment* ignore2)
|
||||
{
|
||||
return test.type == TYPE_ERROR ? boolObject(1) : boolObject(0);
|
||||
}
|
||||
|
||||
Object parseEvalO(Object text, Object ignore, struct Environment* env)
|
||||
{
|
||||
if (text.type == TYPE_SYMBOL) {
|
||||
Object string = eval(&text, env);
|
||||
Object parsed = parseEval(string.string, env);
|
||||
cleanObject(&string);
|
||||
return parsed;
|
||||
} else if (text.type != TYPE_STRING) {
|
||||
return errorObject(CAN_ONLY_EVAL_STRINGS);
|
||||
}
|
||||
return parseEval(text.string, env);
|
||||
}
|
||||
|
||||
Object listEquality(const Object* list1, const Object* list2)
|
||||
{
|
||||
FOR_POINTERS_IN_LISTS(list1, list2) {
|
||||
if (P1->type != P2->type || P1->number != P2->number) {
|
||||
return boolObject(0);
|
||||
}
|
||||
}
|
||||
return boolObject(1);
|
||||
}
|
||||
|
||||
#define CAT_MAX 1024
|
||||
|
||||
Object catObjects(const Object obj1, const Object obj2, struct Environment* env)
|
||||
{
|
||||
Object evalObj1 = eval(&obj1, env);
|
||||
Object evalObj2 = eval(&obj2, env);
|
||||
if (isError(evalObj2, ONLY_ONE_ARGUMENT)) {
|
||||
return evalObj1;
|
||||
}
|
||||
|
||||
char str1[CAT_MAX] = "";
|
||||
char str2[CAT_MAX] = "";
|
||||
stringObj(str1, &evalObj1);
|
||||
stringObj(str2, &evalObj2);
|
||||
cleanObject(&evalObj1);
|
||||
cleanObject(&evalObj2);
|
||||
size_t length = strlen(str1) + strlen(str2) + 1;
|
||||
|
||||
Object o = newObject(TYPE_STRING);
|
||||
o.string = calloc(sizeof(char), length);
|
||||
strcat(o.string, str1);
|
||||
strcat(o.string, str2);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
Object _basicOp(const Object* obj1, const Object* obj2, const char op,
|
||||
struct Environment* env)
|
||||
{
|
||||
const int n1 = obj1->number;
|
||||
const int n2 = obj2->number;
|
||||
|
||||
switch (op) {
|
||||
case '+':
|
||||
if (eitherIs(TYPE_STRING, obj1, obj2)) {
|
||||
return catObjects(*obj1, *obj2, env);
|
||||
}
|
||||
return numberObject(n1 + n2);
|
||||
case '-':
|
||||
return numberObject(n1 - n2);
|
||||
case '*':
|
||||
return numberObject(n1 * n2);
|
||||
case '/':
|
||||
return numberObject(n1 / n2);
|
||||
case '%':
|
||||
return numberObject(n1 % n2);
|
||||
|
||||
case '&':
|
||||
return boolObject(n1 != 0 && n2 != 0);
|
||||
case '|':
|
||||
return boolObject(n1 != 0 || n2 != 0);
|
||||
|
||||
case '=':
|
||||
if (bothAre(TYPE_STRING, obj1, obj2)) {
|
||||
return boolObject(!strcmp(obj1->string, obj2->string));
|
||||
}
|
||||
if (bothAre(TYPE_LIST, obj1, obj2)) {
|
||||
return listEquality(obj1, obj2);
|
||||
}
|
||||
return boolObject(n1 == n2 && areSameType(obj1, obj2));
|
||||
case '>':
|
||||
return boolObject(n1 > n2);
|
||||
case '<':
|
||||
return boolObject(n1 < n2);
|
||||
default:
|
||||
return *obj1;
|
||||
}
|
||||
}
|
||||
|
||||
Object basicOp(const Object* obj1, const Object* obj2, const char op,
|
||||
struct Environment* env)
|
||||
{
|
||||
if (isError(*obj2, ONLY_ONE_ARGUMENT)) {
|
||||
return *obj2;
|
||||
}
|
||||
|
||||
int lists = (obj1->type == TYPE_LIST) + (obj2->type == TYPE_LIST);
|
||||
if (lists == 0) {
|
||||
return _basicOp(obj1, obj2, op, env);
|
||||
|
||||
} 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;
|
||||
|
||||
Object newList = listObject();
|
||||
FOR_POINTER_IN_LIST(listObj) {
|
||||
Object adding = eval(POINTER, env);
|
||||
nf_addToList(&newList, _basicOp(&adding, singleObj, op, env));
|
||||
}
|
||||
return newList;
|
||||
|
||||
} 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) {
|
||||
const Object ev1 = eval(P1, env);
|
||||
const Object ev2 = eval(P2, env);
|
||||
nf_addToList(&newList, _basicOp(&ev1, &ev2, op, env));
|
||||
}
|
||||
return newList;
|
||||
} else {
|
||||
return errorObject(LISTS_NOT_SAME_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Object len(Object obj1, Object o_ignore, struct Environment* e_ignore)
|
||||
{
|
||||
Object o = numberObject(listLength(&obj1));
|
||||
if (o.number < 0) {
|
||||
return errorObject(NOT_A_LIST);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
#define BASIC_OP(_name, _char) \
|
||||
Object _name(Object obj1, Object obj2, struct Environment *env) \
|
||||
{ \
|
||||
return basicOp(&obj1, &obj2, _char, env); \
|
||||
}
|
||||
|
||||
BASIC_OP(add, '+');
|
||||
|
||||
BASIC_OP(sub, '-');
|
||||
|
||||
BASIC_OP(mul, '*');
|
||||
|
||||
BASIC_OP(dvi, '/');
|
||||
|
||||
BASIC_OP(mod, '%');
|
||||
|
||||
BASIC_OP(equ, '=');
|
||||
|
||||
BASIC_OP(gth, '>');
|
||||
|
||||
BASIC_OP(lth, '<');
|
||||
|
||||
BASIC_OP(and, '&');
|
||||
|
||||
BASIC_OP(or, '|');
|
||||
|
||||
#undef BASIC_OP
|
||||
|
||||
#ifdef STANDALONE
|
||||
|
||||
Object pChar(Object c, Object i1, struct Environment* i2)
|
||||
{
|
||||
if (c.type != TYPE_NUMBER) {
|
||||
return errorObject(BAD_NUMBER);
|
||||
}
|
||||
printf("%c", c.number % 256);
|
||||
return numberObject(0);
|
||||
}
|
||||
|
||||
Object printEnvO(Object i1, Object i2, struct Environment* env)
|
||||
{
|
||||
printEnv(global());
|
||||
return numberObject(0);
|
||||
}
|
||||
|
||||
Object takeInput(Object prompt, Object i2, struct Environment* i3)
|
||||
{
|
||||
if (prompt.type == TYPE_STRING) {
|
||||
printf("%s", prompt.string);
|
||||
}
|
||||
char input[256] = "";
|
||||
fgets(input, 256, stdin);
|
||||
return stringFromSlice(input, strlen(input) - 1);
|
||||
}
|
||||
|
||||
Object loadFile(Object filename, Object _, struct Environment* env)
|
||||
{
|
||||
if (isStringy(filename)) {
|
||||
readFile(filename.string, env);
|
||||
return numberObject(0);
|
||||
}
|
||||
return numberObject(1);
|
||||
}
|
||||
|
||||
Object systemCall(Object process, Object _, struct Environment* env)
|
||||
{
|
||||
if (isStringy(process)) {
|
||||
return numberObject(system(process.string));
|
||||
}
|
||||
return numberObject(255);
|
||||
}
|
||||
|
||||
Object help(Object symbol, Object ignore, struct Environment* ignore2)
|
||||
{
|
||||
const char* help = getHelp(symbol.string);
|
||||
return objFromSlice(&help[-1], strlen(help) + 2);
|
||||
}
|
||||
|
||||
#endif // STANDALONE
|
|
@ -0,0 +1,112 @@
|
|||
#ifndef PEBBLISP_PLFUNC_H
|
||||
#define PEBBLISP_PLFUNC_H
|
||||
|
||||
#include "pebblisp.h"
|
||||
|
||||
#define BASIC_OP(_name) \
|
||||
Object _name(Object obj1, Object obj2, struct Environment *env);
|
||||
|
||||
BASIC_OP(add);
|
||||
|
||||
BASIC_OP(sub);
|
||||
|
||||
BASIC_OP(mul);
|
||||
|
||||
BASIC_OP(dvi);
|
||||
|
||||
BASIC_OP(mod);
|
||||
|
||||
BASIC_OP(equ);
|
||||
|
||||
BASIC_OP(gth);
|
||||
|
||||
BASIC_OP(lth);
|
||||
|
||||
BASIC_OP(and);
|
||||
|
||||
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 )\""
|
||||
)(Object obj1, Object obj2, struct Environment* env);
|
||||
|
||||
F(filter, "(filter (< 50) (25 60 100)) => ( 60 100 )")
|
||||
(Object condition, Object list, struct Environment* env);
|
||||
|
||||
F(append, "(ap (1 2) 3) => ( 1 2 3 )")
|
||||
(Object list, Object newElement, struct Environment* env);
|
||||
|
||||
F(prepend, "(pre (2 3) 1) => ( 1 2 3 )")
|
||||
(Object list, Object newElement, struct Environment* env);
|
||||
|
||||
F(len, "(len (2 3)) => 2")
|
||||
(Object obj1, Object o_ignore, struct Environment* e_ignore);
|
||||
|
||||
F(reduce, "(reduce ((1 2 3) 0) +) => 6")
|
||||
(Object listInitial, Object func, struct Environment* env);
|
||||
|
||||
F(at, "(at 1 (1 2 3)) => 2")
|
||||
(Object index, Object list, struct Environment* env);
|
||||
|
||||
F(rest, "(rest (1 2 3)) => ( 2 3 )")
|
||||
(Object list, Object ignore, struct Environment* env);
|
||||
|
||||
F(reverse, "(rev (1 2 3)) => ( 3 2 1 )")
|
||||
(Object _list, Object ignore, struct Environment* ignore2);
|
||||
|
||||
F(isNum, "(isnum 1) => T\n(isnum \"Hello\") => F")
|
||||
(Object test, Object ignore, struct Environment* ignore2);
|
||||
|
||||
F(isList,
|
||||
"(islist (1 2 3)) => T\n"
|
||||
"(islist ()) => T\n"
|
||||
"(islist \"Stringy\") => F"
|
||||
)(Object test, Object ignore, struct Environment* ignore2);
|
||||
|
||||
F(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);
|
||||
|
||||
F(charAt,
|
||||
"(chat \"Hello\" 1) => \"e\"\n"
|
||||
"(chat \"Hello\" 10) => \"\""
|
||||
)(Object string, Object at, struct Environment* ignore);
|
||||
|
||||
F(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)")
|
||||
(Object text, Object ignore, struct Environment* env);
|
||||
|
||||
F(possessive,
|
||||
"(struct Post (title body)) (def p (Post \"TI\" \"BO\")) 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.")
|
||||
(Object p, Object ignore, struct Environment* ignore2);
|
||||
|
||||
F(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.")
|
||||
(Object i1, Object i2, struct Environment* env);
|
||||
|
||||
F(help, "(? +) => \"(+ 1 2) => 3\"")
|
||||
(Object symbol, Object ignore, struct Environment* ignore2);
|
||||
|
||||
#endif
|
||||
|
||||
#endif //PEBBLISP_PLFUNC_H
|
|
@ -57,9 +57,9 @@ check() {
|
|||
|
||||
if $VALGRIND; then
|
||||
echo -ne "\n $1\r "
|
||||
local output="$($VALCOM ./pl "(loadfile \"examples/lib.pbl\") $2")"
|
||||
local output="$($VALCOM ./pl "(loadfile \"examples/lib.pbl\") $2" | grep -v PLT)"
|
||||
else
|
||||
local output="$(./pl "(loadfile \"examples/lib.pbl\") $2")"
|
||||
local output="$(./pl "(loadfile \"examples/lib.pbl\") $2" | grep -v PLT)"
|
||||
fi
|
||||
|
||||
if [ "$output" == "$3" ]; then
|
||||
|
@ -230,7 +230,7 @@ title "Environment"
|
|||
check "EnvStressTestEarly" '(def a 1)(def b 20)(def c "yee")(def d "yeehunnid")(def e 3) (a)' "( 1 )"
|
||||
check "EnvStressTestLate" "(def a 1)(def b 2)(def c 3)(def d 4)(def e 5)(def g 6)(def n 40) n" "40"
|
||||
hard_test_string="(def n 1000)"
|
||||
for c in {0..200}; do hard_test_string="(def a$c 1)$hard_test_string"; done
|
||||
for c in {0..50}; do hard_test_string="(def a$c 1)$hard_test_string"; done
|
||||
check "HardEnvStressTest" "$hard_test_string n" "1000"
|
||||
|
||||
echo ""
|
||||
|
|
46
src/web.c
46
src/web.c
|
@ -13,7 +13,6 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include "web.h"
|
||||
#include "pebblisp.h"
|
||||
#include "tokens.h"
|
||||
|
||||
#ifdef _MHD_FLAGS_ENUM
|
||||
|
@ -141,3 +140,48 @@ int start(int port)
|
|||
// MHD_stop_daemon(daemon);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Object print(Object p, Object ignore, struct Environment* env)
|
||||
{
|
||||
Object c = cloneObject(p);
|
||||
Object e = eval(&c, env);
|
||||
_printObj(&e, 0);
|
||||
cleanObject(&c);
|
||||
cleanObject(&e);
|
||||
return numberObject(0);
|
||||
}
|
||||
|
||||
void addRouteO(Object path, Object textFunc, struct Environment* env, enum RouteType type)
|
||||
{
|
||||
char* p = malloc(sizeof(char) * strlen(path.string) + 1);
|
||||
strcpy(p, path.string);
|
||||
|
||||
struct Route r;
|
||||
r.path = p;
|
||||
r.routeAction = cloneObject(textFunc);
|
||||
r.env = env;
|
||||
r.type = type;
|
||||
env->refs += 1;
|
||||
addRoute(r);
|
||||
}
|
||||
|
||||
Object addGetRoute(Object path, Object textFunc, struct Environment* env)
|
||||
{
|
||||
addRouteO(path, textFunc, env, GET);
|
||||
return numberObject(1);
|
||||
}
|
||||
|
||||
Object addPostRoute(Object path, Object textFunc, struct Environment* env)
|
||||
{
|
||||
addRouteO(path, textFunc, env, POST);
|
||||
return numberObject(1);
|
||||
}
|
||||
|
||||
Object startServer(Object portObject, Object ignored, struct Environment* env)
|
||||
{
|
||||
int port = 8888;
|
||||
if (portObject.type == TYPE_NUMBER) {
|
||||
port = portObject.number;
|
||||
}
|
||||
return numberObject(start(port));
|
||||
}
|
23
src/web.h
23
src/web.h
|
@ -1,4 +1,4 @@
|
|||
#include "object.h"
|
||||
#include "pebblisp.h"
|
||||
|
||||
enum RouteType {
|
||||
GET,
|
||||
|
@ -15,3 +15,24 @@ struct Route {
|
|||
int addRoute(struct Route route);
|
||||
|
||||
int start(int port);
|
||||
|
||||
F(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,
|
||||
"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,
|
||||
"Note: Implementation bugs currently prevent using an inline lambda.\n"
|
||||
" (def homepage (fn () (\"Hello, world!\")));(post \"/\" homepage)\n"
|
||||
" (serve)\n"
|
||||
)(Object path, Object textFunc, struct Environment* env);
|
||||
|
||||
|
|
Loading…
Reference in New Issue