Start switch to array-based functions.
No more mandatory two-params, though several things are still busted.
This commit is contained in:
parent
e00d706522
commit
0a649095ab
|
@ -179,7 +179,7 @@ void printEnv(struct Environment* env)
|
|||
}
|
||||
|
||||
void addFunc(const char* name,
|
||||
Object (* func)(Object, Object, struct Environment*),
|
||||
Object (* func)(Object*, int, struct Environment*),
|
||||
struct Environment* env)
|
||||
{
|
||||
Object o = newObject(TYPE_FUNC);
|
||||
|
@ -223,7 +223,7 @@ void deleteEnv(struct Environment* e)
|
|||
struct symFunc {
|
||||
const char* sym;
|
||||
|
||||
Object (* func)(Object, Object, struct Environment*);
|
||||
Object (* func)(Object*, int, struct Environment*);
|
||||
};
|
||||
|
||||
struct Environment* globalEnv;
|
||||
|
@ -252,7 +252,7 @@ struct helpText helpTexts[100];
|
|||
|
||||
int helpInitialized = 0;
|
||||
|
||||
struct symFunc buildFuncSym(const char* symbol, Object (* func)(Object, Object, struct Environment*), const char* help,
|
||||
struct symFunc buildFuncSym(const char* symbol, Object (* func)(Object*, int, struct Environment*), const char* help,
|
||||
const char* const* tests, size_t testLength)
|
||||
{
|
||||
if (!helpInitialized) {
|
||||
|
@ -324,7 +324,6 @@ char* getHelp(const char* symbol)
|
|||
}
|
||||
|
||||
fnn(segfault, "seg", "Induces a segfault.")
|
||||
(Object ignore1, Object ignore2, struct Environment* env)
|
||||
{
|
||||
int* p = NULL;
|
||||
return numberObject(*p);
|
||||
|
@ -434,6 +433,7 @@ struct Environment defaultEnv()
|
|||
pf("sys", systemCall),
|
||||
pf("loadfile", loadFile),
|
||||
pf("inp", takeInput),
|
||||
pf("rf", readFileToObject),
|
||||
pf("?", help)
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -32,7 +32,7 @@ void addToEnv(struct Environment* env, const char* name, Object obj);
|
|||
void printEnv(struct Environment* env);
|
||||
|
||||
void addFunc(const char* name,
|
||||
Object (* func)(Object, Object, struct Environment*),
|
||||
Object (* func)(Object*, int, struct Environment*),
|
||||
struct Environment* env);
|
||||
|
||||
void deleteEnv(struct Environment* e);
|
||||
|
|
|
@ -100,7 +100,7 @@ struct Object {
|
|||
Object* list;
|
||||
char* string;
|
||||
|
||||
Object (* func)(Object, Object, struct Environment*);
|
||||
Object (* func)(Object*, int, struct Environment*);
|
||||
|
||||
struct StructObject* structObject;
|
||||
struct Lambda* lambda;
|
||||
|
|
|
@ -247,40 +247,26 @@ Object simpleFuncEval(const Object func, Object arg1, Object arg2, struct Enviro
|
|||
Object listEvalFunc(const Object* list, const Object* function,
|
||||
const int length, struct Environment* env)
|
||||
{
|
||||
if (length == 0) {
|
||||
return function->func(boolObject(0), boolObject(0), env);
|
||||
}
|
||||
//printf("Using new funcEval.\n");
|
||||
|
||||
//printf("list: ");
|
||||
//printObj(list);
|
||||
//printf("\nfunction:");
|
||||
//printObj(function);
|
||||
//printf("\n");
|
||||
Object rest[length];
|
||||
evalForms(rest, list->list->forward, env);
|
||||
// for (int i = 0; i < length; i++) {
|
||||
// printf("rest[%d]: ", i);
|
||||
// printObj(&rest[i]);
|
||||
// printf("\n");
|
||||
// }
|
||||
|
||||
Object func_result = rest[0];
|
||||
if (length == 1) {
|
||||
Object oneArg = errorObject(ONLY_ONE_ARGUMENT);
|
||||
func_result = function->func(func_result, oneArg, env);
|
||||
// Return a partial function if more parameters are required
|
||||
// Otherwise, return the function result
|
||||
cleanObject(&rest[0]);
|
||||
if (isError(func_result, ONLY_ONE_ARGUMENT)) {
|
||||
// These functions modify their second argument,
|
||||
// so we don't clean oneArg here
|
||||
cleanObject(&func_result);
|
||||
return cloneObject(*list);
|
||||
} else {
|
||||
cleanObject(&oneArg);
|
||||
return func_result;
|
||||
}
|
||||
} else {
|
||||
// With two args, will apply function once
|
||||
// With more than two args, apply the function repeatedly
|
||||
for (int i = 1; i < length; i++) {
|
||||
Object toClean = func_result;
|
||||
func_result = function->func(func_result, rest[i], env);
|
||||
cleanObject(&toClean);
|
||||
cleanObject(&rest[i]);
|
||||
}
|
||||
return func_result;
|
||||
Object result = function->func(rest, length, env);
|
||||
for (int i = 0; i < length; i++) {
|
||||
cleanObject(&rest[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -370,7 +356,7 @@ Object evalList(const Object* obj, struct Environment* env)
|
|||
Object first_eval = eval(first_form, env);
|
||||
switch (first_eval.type) {
|
||||
case TYPE_FUNC:
|
||||
// Passes evalLength - 1, because we skip the first form
|
||||
// Uses evalLength - 1 because we skip the first form
|
||||
return listEvalFunc(obj, &first_eval, evalLength - 1, env);
|
||||
|
||||
case TYPE_LAMBDA:
|
||||
|
@ -445,8 +431,11 @@ void debugSlice(struct Slice* s)
|
|||
#endif
|
||||
}
|
||||
|
||||
Object possessive(Object structo, Object field, struct Environment* env)
|
||||
Object possessive(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object structo = params[0];
|
||||
Object field = params[1];
|
||||
|
||||
if (structo.type != TYPE_STRUCT) {
|
||||
printf("`'s` must be used on a struct!\n");
|
||||
return errorObject(NULL_PARSE);
|
||||
|
|
|
@ -13,14 +13,14 @@
|
|||
#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
|
||||
Object _name(Object* params, int length, struct Environment* env)
|
||||
|
||||
#define fnn(_name, _symbol, _docs, ...)\
|
||||
static const char * const _name ## Doc = _docs;\
|
||||
static const char * const _name ## Symbol = _symbol;\
|
||||
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
|
||||
Object _name(Object* params, int length, struct Environment* env)
|
||||
|
||||
struct Slice {
|
||||
const char* text;
|
||||
|
|
161
src/plfunc.c
161
src/plfunc.c
|
@ -6,8 +6,11 @@
|
|||
/**
|
||||
* (reduce (list, initial) (fn (prev total) (+ prev total)))
|
||||
*/
|
||||
Object reduce(const Object listInitial, const Object func, struct Environment* env)
|
||||
Object reduce(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
const Object listInitial = params[0];
|
||||
const Object func = params[1];
|
||||
|
||||
Object* list = itemAt(&listInitial, 0);
|
||||
Object total = cloneObject(*list->forward); // From given initial value
|
||||
|
||||
|
@ -22,8 +25,11 @@ Object reduce(const Object listInitial, const Object func, struct Environment* e
|
|||
return total;
|
||||
}
|
||||
|
||||
Object charAt(Object string, Object at, struct Environment* ignore)
|
||||
Object charAt(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object string = params[0];
|
||||
Object at = params[1];
|
||||
|
||||
char* c = malloc(sizeof(char) * 2);
|
||||
c[0] = string.string[at.number];
|
||||
c[1] = '\0';
|
||||
|
@ -31,8 +37,11 @@ Object charAt(Object string, Object at, struct Environment* ignore)
|
|||
return string;
|
||||
}
|
||||
|
||||
Object filter(Object condition, Object list, struct Environment* env)
|
||||
Object filter(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object condition = params[0];
|
||||
Object list = params[1];
|
||||
|
||||
Object filteredList = listObject();
|
||||
FOR_POINTER_IN_LIST(&list) {
|
||||
Object conditional = cloneObject(condition);
|
||||
|
@ -46,23 +55,32 @@ Object filter(Object condition, Object list, struct Environment* env)
|
|||
return filteredList;
|
||||
}
|
||||
|
||||
Object append(Object list, Object newElement, struct Environment* env)
|
||||
Object append(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object list = params[0];
|
||||
Object newElement = params[1];
|
||||
|
||||
Object newList = cloneObject(list);
|
||||
nf_addToList(&newList, cloneObject(newElement));
|
||||
return newList;
|
||||
}
|
||||
|
||||
Object prepend(Object list, Object newElement, struct Environment* env)
|
||||
Object prepend(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object list = params[0];
|
||||
Object newElement = params[1];
|
||||
|
||||
Object newList = listObject();
|
||||
nf_addToList(&newList, cloneObject(newElement));
|
||||
appendList(&newList, &list);
|
||||
return newList;
|
||||
}
|
||||
|
||||
Object at(Object index, Object list, struct Environment* env)
|
||||
Object at(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object index = params[0];
|
||||
Object list = params[1];
|
||||
|
||||
const Object* found = itemAt(&list, index.number);
|
||||
if (found) {
|
||||
return cloneObject(*found);
|
||||
|
@ -71,8 +89,10 @@ Object at(Object index, Object list, struct Environment* env)
|
|||
}
|
||||
}
|
||||
|
||||
Object rest(Object list, Object ignore, struct Environment* env)
|
||||
Object rest(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object list = params[0];
|
||||
|
||||
Object ret = listObject();
|
||||
Object* l = &list;
|
||||
FOR_POINTER_IN_LIST(l) {
|
||||
|
@ -84,8 +104,10 @@ Object rest(Object list, Object ignore, struct Environment* env)
|
|||
return ret;
|
||||
}
|
||||
|
||||
Object reverse(Object _list, Object ignore, struct Environment* ignore2)
|
||||
Object reverse(Object* params, int length, struct Environment* ignore2)
|
||||
{
|
||||
Object _list = params[0];
|
||||
|
||||
if (!isListy(_list)) {
|
||||
return errorObject(NOT_A_LIST);
|
||||
}
|
||||
|
@ -105,43 +127,55 @@ Object reverse(Object _list, Object ignore, struct Environment* ignore2)
|
|||
return rev;
|
||||
}
|
||||
|
||||
Object isNum(Object test, Object ignore, struct Environment* ignore2)
|
||||
Object isNum(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object test = params[0];
|
||||
|
||||
return test.type == TYPE_NUMBER ? boolObject(1) : boolObject(0);
|
||||
}
|
||||
|
||||
Object isList(Object test, Object ignore, struct Environment* ignore2)
|
||||
Object isList(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object test = params[0];
|
||||
|
||||
return test.type == TYPE_LIST ? boolObject(1) : boolObject(0);
|
||||
}
|
||||
|
||||
Object isString(Object test, Object ignore, struct Environment* ignore2)
|
||||
Object isString(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object test = params[0];
|
||||
|
||||
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)
|
||||
Object charVal(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object test = params[0];
|
||||
|
||||
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)
|
||||
Object isErr(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object test = params[0];
|
||||
|
||||
return test.type == TYPE_ERROR ? boolObject(1) : boolObject(0);
|
||||
}
|
||||
|
||||
Object parseEvalO(Object text, Object ignore, struct Environment* env)
|
||||
Object parseEvalO(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object text = params[0];
|
||||
|
||||
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_SLIST) {
|
||||
return evalList(&text, env);
|
||||
return evalList(&text, env, 0);
|
||||
} else if (text.type != TYPE_STRING) {
|
||||
return errorObject(CAN_ONLY_EVAL_STRINGS);
|
||||
}
|
||||
|
@ -160,7 +194,7 @@ Object listEquality(const Object* list1, const Object* list2)
|
|||
|
||||
#define CAT_MAX 1024
|
||||
|
||||
Object catObjects(const Object obj1, const Object obj2, struct Environment* env)
|
||||
Object _catObjects(Object obj1, Object obj2, struct Environment* env)
|
||||
{
|
||||
Object evalObj1 = eval(&obj1, env);
|
||||
Object evalObj2 = eval(&obj2, env);
|
||||
|
@ -174,16 +208,30 @@ Object catObjects(const Object obj1, const Object obj2, struct Environment* env)
|
|||
stringObj(str2, &evalObj2);
|
||||
cleanObject(&evalObj1);
|
||||
cleanObject(&evalObj2);
|
||||
size_t length = strlen(str1) + strlen(str2) + 1;
|
||||
size_t strLength = strlen(str1) + strlen(str2) + 1;
|
||||
|
||||
Object o = newObject(TYPE_STRING);
|
||||
o.string = calloc(sizeof(char), length);
|
||||
o.string = calloc(sizeof(char), strLength);
|
||||
strcat(o.string, str1);
|
||||
strcat(o.string, str2);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
Object catObjects(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object string = stringFromSlice("", 0);
|
||||
if (length == 0) {
|
||||
return string;
|
||||
}
|
||||
for (int i = 0; i < length; i++) {
|
||||
Object newString = _catObjects(string, params[i], env);
|
||||
cleanObject(&string);
|
||||
string = newString;
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
Object _basicOp(const Object* obj1, const Object* obj2, const char op,
|
||||
struct Environment* env)
|
||||
{
|
||||
|
@ -193,7 +241,8 @@ Object _basicOp(const Object* obj1, const Object* obj2, const char op,
|
|||
switch (op) {
|
||||
case '+':
|
||||
if (eitherIsNot(TYPE_NUMBER, obj1, obj2)) {
|
||||
return catObjects(*obj1, *obj2, env);
|
||||
Object objects[2] = {*obj1, *obj2};
|
||||
return catObjects(objects, 2, env);
|
||||
}
|
||||
return numberObject(n1 + n2);
|
||||
case '-':
|
||||
|
@ -264,8 +313,10 @@ Object basicOp(const Object* obj1, const Object* obj2, const char op,
|
|||
}
|
||||
}
|
||||
|
||||
Object len(Object obj1, Object o_ignore, struct Environment* e_ignore)
|
||||
Object len(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object obj1 = params[0];
|
||||
|
||||
Object o = numberObject(listLength(&obj1));
|
||||
if (o.number < 0) {
|
||||
return errorObject(NOT_A_LIST);
|
||||
|
@ -274,20 +325,47 @@ Object len(Object obj1, Object o_ignore, struct Environment* e_ignore)
|
|||
}
|
||||
|
||||
#define BASIC_OP(_name, _char) \
|
||||
Object _name(Object obj1, Object obj2, struct Environment *env) \
|
||||
{ \
|
||||
return basicOp(&obj1, &obj2, _char, env); \
|
||||
Object _name(Object* params, int length, struct Environment* env) \
|
||||
{ \
|
||||
Object obj1 = params[0]; \
|
||||
Object obj2 = params[1]; \
|
||||
return basicOp(&obj1, &obj2, _char, env); \
|
||||
}
|
||||
|
||||
BASIC_OP(add, '+')
|
||||
|
||||
BASIC_OP(sub, '-')
|
||||
#define PLUS +
|
||||
|
||||
BASIC_OP(mul, '*')
|
||||
// Object add(Object* params, int length, struct Environment* env)
|
||||
// {
|
||||
// Object sum = numberObject(0);
|
||||
// for (int i = 0; i < length; i++) {
|
||||
// sum.number += params[i].number;
|
||||
// }
|
||||
// return sum;
|
||||
// }
|
||||
|
||||
BASIC_OP(dvi, '/')
|
||||
#define BASIC_MATH(_name, _op) \
|
||||
Object _name(Object* params, int length, struct Environment* env) \
|
||||
{ \
|
||||
if (length == 0) { \
|
||||
return numberObject(0); \
|
||||
} \
|
||||
Object sum = numberObject(params[0].number); \
|
||||
for (int i = 1; i < length; i++) { \
|
||||
sum.number _op params[i].number; \
|
||||
} \
|
||||
return sum; \
|
||||
}
|
||||
|
||||
BASIC_OP(mod, '%')
|
||||
BASIC_MATH(add, +=)
|
||||
|
||||
BASIC_MATH(sub, -=)
|
||||
|
||||
BASIC_MATH(mul, *=)
|
||||
|
||||
BASIC_MATH(dvi, /=)
|
||||
|
||||
BASIC_MATH(mod, %=)
|
||||
|
||||
BASIC_OP(equ, '=')
|
||||
|
||||
|
@ -303,8 +381,10 @@ BASIC_OP(or, '|')
|
|||
|
||||
#ifdef STANDALONE
|
||||
|
||||
Object pChar(Object c, Object i1, struct Environment* i2)
|
||||
Object pChar(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object c = params[0];
|
||||
|
||||
if (c.type != TYPE_NUMBER) {
|
||||
return errorObject(BAD_NUMBER);
|
||||
}
|
||||
|
@ -312,14 +392,15 @@ Object pChar(Object c, Object i1, struct Environment* i2)
|
|||
return numberObject(0);
|
||||
}
|
||||
|
||||
Object printEnvO(Object i1, Object i2, struct Environment* env)
|
||||
Object printEnvO(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
printEnv(global());
|
||||
return numberObject(0);
|
||||
}
|
||||
|
||||
Object takeInput(Object prompt, Object i2, struct Environment* i3)
|
||||
Object takeInput(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object prompt = params[0];
|
||||
if (prompt.type == TYPE_STRING) {
|
||||
printf("%s", prompt.string);
|
||||
}
|
||||
|
@ -328,8 +409,10 @@ Object takeInput(Object prompt, Object i2, struct Environment* i3)
|
|||
return stringFromSlice(input, strlen(input) - 1);
|
||||
}
|
||||
|
||||
Object loadFile(Object filename, Object _, struct Environment* env)
|
||||
Object loadFile(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object filename = params[0];
|
||||
|
||||
if (isStringy(filename)) {
|
||||
readFile(filename.string, env);
|
||||
return numberObject(0);
|
||||
|
@ -337,16 +420,20 @@ Object loadFile(Object filename, Object _, struct Environment* env)
|
|||
return numberObject(1);
|
||||
}
|
||||
|
||||
Object systemCall(Object process, Object _, struct Environment* env)
|
||||
Object systemCall(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object process = params[0];
|
||||
|
||||
if (isStringy(process)) {
|
||||
return numberObject(system(process.string));
|
||||
}
|
||||
return numberObject(255);
|
||||
}
|
||||
|
||||
Object help(Object symbol, Object ignore, struct Environment* ignore2)
|
||||
Object help(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object symbol = params[0];
|
||||
|
||||
char* help = getHelp(symbol.string);
|
||||
Object helpText = newObject(TYPE_STRING);
|
||||
helpText.string = help;
|
||||
|
@ -375,8 +462,10 @@ char* readFileToString(FILE* input)
|
|||
return string;
|
||||
}
|
||||
|
||||
Object readFileToObject(Object filename, Object ignore, struct Environment* ignore2)
|
||||
Object readFileToObject(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object filename = params[0];
|
||||
|
||||
if (filename.type != TYPE_STRING) {
|
||||
return errorObject(NULL_PARSE);
|
||||
}
|
||||
|
@ -391,4 +480,4 @@ Object readFileToObject(Object filename, Object ignore, struct Environment* igno
|
|||
return string;
|
||||
}
|
||||
|
||||
#endif // STANDALONE
|
||||
#endif // STANDALONE
|
||||
|
|
58
src/plfunc.h
58
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* params, int length, struct Environment* env)
|
||||
|
||||
BASIC_OP(add);
|
||||
|
||||
|
@ -31,29 +31,29 @@ BASIC_OP(or);
|
|||
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);
|
||||
); // (Object obj1, Object obj2, struct Environment* env);
|
||||
|
||||
fn(filter,
|
||||
"Filter a list based on the given condition.",
|
||||
"(fil (< 50) (25 60 100))", "( 60 100 )",
|
||||
)(Object condition, Object list, struct Environment* env);
|
||||
); // (Object condition, Object list, struct Environment* env);
|
||||
|
||||
fn(append,
|
||||
"Append the given element. Creates a new list.",
|
||||
"(ap (1 2) 3)", "( 1 2 3 )",
|
||||
)(Object list, Object newElement, struct Environment* env);
|
||||
); // (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);
|
||||
); // (Object list, Object newElement, struct Environment* env);
|
||||
|
||||
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);
|
||||
); // (Object obj1, Object o_ignore, struct Environment* e_ignore);
|
||||
|
||||
fn(reduce,
|
||||
"Performs a simple reduction. Does not currently work with lambdas.\n"
|
||||
|
@ -62,27 +62,27 @@ fn(reduce,
|
|||
" - A function to apply to each value.",
|
||||
"(reduce (5 6) +)", "11",
|
||||
"(reduce ((1 2 3) 0) +)", "6",
|
||||
)(Object listInitial, Object func, struct Environment* env);
|
||||
); // (Object listInitial, Object func, struct Environment* env);
|
||||
|
||||
fn(at,
|
||||
"Get item at the given index in the given list.",
|
||||
"(at 1 (1 2 3))", "2",
|
||||
"(at 99 (1 2 3))", "INDEX_PAST_END",
|
||||
"(at 99 \"string\")", "INDEX_PAST_END",
|
||||
)(Object index, Object list, struct Environment* env);
|
||||
); // (Object index, Object list, struct Environment* env);
|
||||
|
||||
fn(rest,
|
||||
"Get the tail of a list. All but the first element.",
|
||||
"(rest (1 2 3))", "( 2 3 )",
|
||||
"(rest ())", "( )",
|
||||
"(rest \"string\")", "( )",
|
||||
)(Object list, Object ignore, struct Environment* env);
|
||||
); // (Object list, Object ignore, struct Environment* env);
|
||||
|
||||
fn(reverse,
|
||||
"Reverse a list.",
|
||||
"(rev (1 2 3))", "( 3 2 1 )",
|
||||
"(rev \"string\")", "NOT_A_LIST",
|
||||
)(Object _list, Object ignore, struct Environment* ignore2);
|
||||
); // (Object _list, Object ignore, struct Environment* ignore2);
|
||||
|
||||
fn(isNum,
|
||||
"Returns `T` only if the argument evaluates to a number.",
|
||||
|
@ -90,14 +90,14 @@ fn(isNum,
|
|||
"(isnum (+ 5 5))", "T",
|
||||
"(isnum '(+ 5 5))", "F",
|
||||
"(isnum \"Hello\")", "F",
|
||||
)(Object test, Object ignore, struct Environment* ignore2);
|
||||
); // (Object test, Object ignore, struct Environment* ignore2);
|
||||
|
||||
fn(isList,
|
||||
"Returns `T` only if the argument is a list.",
|
||||
"(islist (1 2 3))", "T",
|
||||
"(islist ())", "T",
|
||||
"(islist \"Stringy\")", "F",
|
||||
)(Object test, Object ignore, struct Environment* ignore2);
|
||||
); // (Object test, Object ignore, struct Environment* ignore2);
|
||||
|
||||
fn(isString,
|
||||
"Returns `T` only if the argument is a string.",
|
||||
|
@ -105,56 +105,56 @@ fn(isString,
|
|||
"(isstr \"\")", "T",
|
||||
"(isstr (cat 5 5))", "T",
|
||||
"(isstr 10)", "F",
|
||||
)(Object test, Object ignore, struct Environment* ignore2);
|
||||
); // (Object test, Object ignore, struct Environment* ignore2);
|
||||
|
||||
fn(isErr,
|
||||
"Check if the argument is an error.",
|
||||
"(iserr (at 10 ()))", "T",
|
||||
"(iserr 5)", "F",
|
||||
)(Object test, Object ignore, struct Environment* ignore2);
|
||||
); // (Object test, Object ignore, struct Environment* ignore2);
|
||||
|
||||
fn(charAt,
|
||||
"Get the char in the given string at the given index.",
|
||||
"(chat \"Hello\" 1)", "e",
|
||||
"(chat \"Hello\" 10)", "",
|
||||
)(Object string, Object at, struct Environment* ignore);
|
||||
); // (Object string, Object at, struct Environment* ignore);
|
||||
|
||||
fn(charVal,
|
||||
"Get the ascii integer representaton of the given character.",
|
||||
"(char \"h\")", "104",
|
||||
"(char \"hello\")", "104",
|
||||
"(char \"\")", "0",
|
||||
)(Object test, Object ignore, struct Environment* ignore2);
|
||||
); // (Object test, Object ignore, struct Environment* ignore2);
|
||||
|
||||
fn(parseEvalO,
|
||||
"Evaluate the given string or quoted list.",
|
||||
"(eval \"(1 2 3)\")", "( 1 2 3 )",
|
||||
"(eval '(+ 5 5))", "10",
|
||||
)(Object text, Object ignore, struct Environment* env);
|
||||
); // (Object text, Object ignore, struct Environment* env);
|
||||
|
||||
fn(possessive,
|
||||
"(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
|
||||
|
||||
fn(print, "Prints the string representation of the given object to stdout.")
|
||||
(Object p, Object ignore, struct Environment* ignore2);
|
||||
fn(print, "Prints the string representation of the given object to stdout.");
|
||||
//(Object p, Object ignore, struct Environment* ignore2);
|
||||
|
||||
fn(pChar, "Prints the ascii character for the given number value.")
|
||||
(Object c, Object i1, struct Environment* i2);
|
||||
fn(pChar, "Prints the ascii character for the given number value.");
|
||||
//(Object c, Object i1, struct Environment* i2);
|
||||
|
||||
fn(printEnvO, "Prints out the current scoped environment.")
|
||||
(Object i1, Object i2, struct Environment* env);
|
||||
fn(printEnvO, "Prints out the current scoped environment.");
|
||||
//(Object i1, Object i2, struct Environment* env);
|
||||
|
||||
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);
|
||||
); // (Object process, Object _, struct Environment* env);
|
||||
|
||||
fn(loadFile,
|
||||
"Loads and parses the given file.\n"
|
||||
|
@ -162,24 +162,24 @@ fn(loadFile,
|
|||
"(loadfile \"printdate.pl\")\n"
|
||||
"Mon 21 Mar 2022 10:35:03 AM EDT\n"
|
||||
"=> 0"
|
||||
)(Object filename, Object _, struct Environment* env);
|
||||
); // (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);
|
||||
); // (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);
|
||||
); // (Object symbol, Object ignore, struct Environment* ignore2);
|
||||
|
||||
fn(readFileToObject,
|
||||
"Read a file into a string object."
|
||||
)(Object filename, Object ignore, struct Environment* ignore2);
|
||||
); // (Object filename, Object ignore, struct Environment* ignore2);
|
||||
|
||||
#endif // STANDALONE
|
||||
|
||||
|
|
16
src/web.c
16
src/web.c
|
@ -141,8 +141,10 @@ int start(int port)
|
|||
return 0;
|
||||
}
|
||||
|
||||
Object print(Object p, Object ignore, struct Environment* env)
|
||||
Object print(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object p = params[0];
|
||||
Object ignore = params[1];
|
||||
Object c = cloneObject(p);
|
||||
Object e = eval(&c, env);
|
||||
_printObj(&e, 0);
|
||||
|
@ -165,20 +167,26 @@ void addRouteO(Object path, Object textFunc, struct Environment* env, enum Route
|
|||
addRoute(r);
|
||||
}
|
||||
|
||||
Object addGetRoute(Object path, Object textFunc, struct Environment* env)
|
||||
Object addGetRoute(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object path = params[0];
|
||||
Object textFunc = params[1];
|
||||
addRouteO(path, textFunc, env, GET);
|
||||
return numberObject(1);
|
||||
}
|
||||
|
||||
Object addPostRoute(Object path, Object textFunc, struct Environment* env)
|
||||
Object addPostRoute(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object path = params[0];
|
||||
Object textFunc = params[1];
|
||||
addRouteO(path, textFunc, env, POST);
|
||||
return numberObject(1);
|
||||
}
|
||||
|
||||
Object startServer(Object portObject, Object ignored, struct Environment* env)
|
||||
Object startServer(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object portObject = params[0];
|
||||
|
||||
int port = 8888;
|
||||
if (portObject.type == TYPE_NUMBER) {
|
||||
port = portObject.number;
|
||||
|
|
|
@ -21,18 +21,18 @@ fn(startServer,
|
|||
"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);
|
||||
);
|
||||
|
||||
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);
|
||||
);
|
||||
|
||||
fn(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