Start switch to array-based functions.

No more mandatory two-params, though several things are still busted.
This commit is contained in:
Sage Vaillancourt 2022-03-24 16:56:52 -04:00 committed by Sage Vaillancourt
parent e00d706522
commit 0a649095ab
9 changed files with 197 additions and 111 deletions

View File

@ -179,7 +179,7 @@ void printEnv(struct Environment* env)
} }
void addFunc(const char* name, void addFunc(const char* name,
Object (* func)(Object, Object, struct Environment*), Object (* func)(Object*, int, struct Environment*),
struct Environment* env) struct Environment* env)
{ {
Object o = newObject(TYPE_FUNC); Object o = newObject(TYPE_FUNC);
@ -223,7 +223,7 @@ void deleteEnv(struct Environment* e)
struct symFunc { struct symFunc {
const char* sym; const char* sym;
Object (* func)(Object, Object, struct Environment*); Object (* func)(Object*, int, struct Environment*);
}; };
struct Environment* globalEnv; struct Environment* globalEnv;
@ -252,7 +252,7 @@ struct helpText helpTexts[100];
int helpInitialized = 0; 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) const char* const* tests, size_t testLength)
{ {
if (!helpInitialized) { if (!helpInitialized) {
@ -324,7 +324,6 @@ char* getHelp(const char* symbol)
} }
fnn(segfault, "seg", "Induces a segfault.") fnn(segfault, "seg", "Induces a segfault.")
(Object ignore1, Object ignore2, struct Environment* env)
{ {
int* p = NULL; int* p = NULL;
return numberObject(*p); return numberObject(*p);
@ -434,6 +433,7 @@ struct Environment defaultEnv()
pf("sys", systemCall), pf("sys", systemCall),
pf("loadfile", loadFile), pf("loadfile", loadFile),
pf("inp", takeInput), pf("inp", takeInput),
pf("rf", readFileToObject),
pf("?", help) pf("?", help)
#endif #endif
}; };

View File

@ -32,7 +32,7 @@ void addToEnv(struct Environment* env, const char* name, Object obj);
void printEnv(struct Environment* env); void printEnv(struct Environment* env);
void addFunc(const char* name, void addFunc(const char* name,
Object (* func)(Object, Object, struct Environment*), Object (* func)(Object*, int, struct Environment*),
struct Environment* env); struct Environment* env);
void deleteEnv(struct Environment* e); void deleteEnv(struct Environment* e);

View File

@ -100,7 +100,7 @@ struct Object {
Object* list; Object* list;
char* string; char* string;
Object (* func)(Object, Object, struct Environment*); Object (* func)(Object*, int, struct Environment*);
struct StructObject* structObject; struct StructObject* structObject;
struct Lambda* lambda; struct Lambda* lambda;

View File

@ -247,40 +247,26 @@ Object simpleFuncEval(const Object func, Object arg1, Object arg2, struct Enviro
Object listEvalFunc(const Object* list, const Object* function, Object listEvalFunc(const Object* list, const Object* function,
const int length, struct Environment* env) const int length, struct Environment* env)
{ {
if (length == 0) { //printf("Using new funcEval.\n");
return function->func(boolObject(0), boolObject(0), env);
}
//printf("list: ");
//printObj(list);
//printf("\nfunction:");
//printObj(function);
//printf("\n");
Object rest[length]; Object rest[length];
evalForms(rest, list->list->forward, env); 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]; Object result = function->func(rest, length, env);
if (length == 1) { for (int i = 0; i < length; i++) {
Object oneArg = errorObject(ONLY_ONE_ARGUMENT); cleanObject(&rest[i]);
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;
} }
return result;
} }
/** /**
@ -370,7 +356,7 @@ Object evalList(const Object* obj, struct Environment* env)
Object first_eval = eval(first_form, env); Object first_eval = eval(first_form, env);
switch (first_eval.type) { switch (first_eval.type) {
case TYPE_FUNC: 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); return listEvalFunc(obj, &first_eval, evalLength - 1, env);
case TYPE_LAMBDA: case TYPE_LAMBDA:
@ -445,8 +431,11 @@ void debugSlice(struct Slice* s)
#endif #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) { if (structo.type != TYPE_STRUCT) {
printf("`'s` must be used on a struct!\n"); printf("`'s` must be used on a struct!\n");
return errorObject(NULL_PARSE); return errorObject(NULL_PARSE);

View File

@ -13,14 +13,14 @@
#define fn(_name, _docs, ...) static const char * const _name ## Doc = _docs; \ #define fn(_name, _docs, ...) static const char * const _name ## Doc = _docs; \
static const char * const _name ## Tests[] = {__VA_ARGS__}; \ 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."); \ 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, ...)\ #define fnn(_name, _symbol, _docs, ...)\
static const char * const _name ## Doc = _docs;\ static const char * const _name ## Doc = _docs;\
static const char * const _name ## Symbol = _symbol;\ static const char * const _name ## Symbol = _symbol;\
static const char * const _name ## Tests[] = {__VA_ARGS__}; \ 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."); \ 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 { struct Slice {
const char* text; const char* text;

View File

@ -6,8 +6,11 @@
/** /**
* (reduce (list, initial) (fn (prev total) (+ prev total))) * (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* list = itemAt(&listInitial, 0);
Object total = cloneObject(*list->forward); // From given initial value 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; 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); char* c = malloc(sizeof(char) * 2);
c[0] = string.string[at.number]; c[0] = string.string[at.number];
c[1] = '\0'; c[1] = '\0';
@ -31,8 +37,11 @@ Object charAt(Object string, Object at, struct Environment* ignore)
return string; 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(); Object filteredList = listObject();
FOR_POINTER_IN_LIST(&list) { FOR_POINTER_IN_LIST(&list) {
Object conditional = cloneObject(condition); Object conditional = cloneObject(condition);
@ -46,23 +55,32 @@ Object filter(Object condition, Object list, struct Environment* env)
return filteredList; 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); Object newList = cloneObject(list);
nf_addToList(&newList, cloneObject(newElement)); nf_addToList(&newList, cloneObject(newElement));
return newList; 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(); Object newList = listObject();
nf_addToList(&newList, cloneObject(newElement)); nf_addToList(&newList, cloneObject(newElement));
appendList(&newList, &list); appendList(&newList, &list);
return newList; 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); const Object* found = itemAt(&list, index.number);
if (found) { if (found) {
return cloneObject(*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 ret = listObject();
Object* l = &list; Object* l = &list;
FOR_POINTER_IN_LIST(l) { FOR_POINTER_IN_LIST(l) {
@ -84,8 +104,10 @@ Object rest(Object list, Object ignore, struct Environment* env)
return ret; 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)) { if (!isListy(_list)) {
return errorObject(NOT_A_LIST); return errorObject(NOT_A_LIST);
} }
@ -105,43 +127,55 @@ Object reverse(Object _list, Object ignore, struct Environment* ignore2)
return rev; 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); 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); 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); return test.type == TYPE_STRING ? boolObject(1) : boolObject(0);
} }
// Get the int value of a string's first character // 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 numberObject(test.string[0]);
// return test.type == TYPE_STRING && test.string[0] == '\0' ? // return test.type == TYPE_STRING && test.string[0] == '\0' ?
// boolObject(1) : boolObject(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); 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) { if (text.type == TYPE_SYMBOL) {
Object string = eval(&text, env); Object string = eval(&text, env);
Object parsed = parseEval(string.string, env); Object parsed = parseEval(string.string, env);
cleanObject(&string); cleanObject(&string);
return parsed; return parsed;
} else if (text.type == TYPE_SLIST) { } else if (text.type == TYPE_SLIST) {
return evalList(&text, env); return evalList(&text, env, 0);
} else if (text.type != TYPE_STRING) { } else if (text.type != TYPE_STRING) {
return errorObject(CAN_ONLY_EVAL_STRINGS); return errorObject(CAN_ONLY_EVAL_STRINGS);
} }
@ -160,7 +194,7 @@ Object listEquality(const Object* list1, const Object* list2)
#define CAT_MAX 1024 #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 evalObj1 = eval(&obj1, env);
Object evalObj2 = eval(&obj2, env); Object evalObj2 = eval(&obj2, env);
@ -174,16 +208,30 @@ Object catObjects(const Object obj1, const Object obj2, struct Environment* env)
stringObj(str2, &evalObj2); stringObj(str2, &evalObj2);
cleanObject(&evalObj1); cleanObject(&evalObj1);
cleanObject(&evalObj2); cleanObject(&evalObj2);
size_t length = strlen(str1) + strlen(str2) + 1; size_t strLength = strlen(str1) + strlen(str2) + 1;
Object o = newObject(TYPE_STRING); Object o = newObject(TYPE_STRING);
o.string = calloc(sizeof(char), length); o.string = calloc(sizeof(char), strLength);
strcat(o.string, str1); strcat(o.string, str1);
strcat(o.string, str2); strcat(o.string, str2);
return o; 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, Object _basicOp(const Object* obj1, const Object* obj2, const char op,
struct Environment* env) struct Environment* env)
{ {
@ -193,7 +241,8 @@ Object _basicOp(const Object* obj1, const Object* obj2, const char op,
switch (op) { switch (op) {
case '+': case '+':
if (eitherIsNot(TYPE_NUMBER, obj1, obj2)) { 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); return numberObject(n1 + n2);
case '-': 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)); Object o = numberObject(listLength(&obj1));
if (o.number < 0) { if (o.number < 0) {
return errorObject(NOT_A_LIST); 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) \ #define BASIC_OP(_name, _char) \
Object _name(Object obj1, Object obj2, struct Environment *env) \ Object _name(Object* params, int length, struct Environment* env) \
{ \ { \
return basicOp(&obj1, &obj2, _char, 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, '=') BASIC_OP(equ, '=')
@ -303,8 +381,10 @@ BASIC_OP(or, '|')
#ifdef STANDALONE #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) { if (c.type != TYPE_NUMBER) {
return errorObject(BAD_NUMBER); return errorObject(BAD_NUMBER);
} }
@ -312,14 +392,15 @@ Object pChar(Object c, Object i1, struct Environment* i2)
return numberObject(0); return numberObject(0);
} }
Object printEnvO(Object i1, Object i2, struct Environment* env) Object printEnvO(Object* params, int length, struct Environment* env)
{ {
printEnv(global()); printEnv(global());
return numberObject(0); 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) { if (prompt.type == TYPE_STRING) {
printf("%s", prompt.string); printf("%s", prompt.string);
} }
@ -328,8 +409,10 @@ Object takeInput(Object prompt, Object i2, struct Environment* i3)
return stringFromSlice(input, strlen(input) - 1); 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)) { if (isStringy(filename)) {
readFile(filename.string, env); readFile(filename.string, env);
return numberObject(0); return numberObject(0);
@ -337,16 +420,20 @@ Object loadFile(Object filename, Object _, struct Environment* env)
return numberObject(1); 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)) { if (isStringy(process)) {
return numberObject(system(process.string)); return numberObject(system(process.string));
} }
return numberObject(255); 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); char* help = getHelp(symbol.string);
Object helpText = newObject(TYPE_STRING); Object helpText = newObject(TYPE_STRING);
helpText.string = help; helpText.string = help;
@ -375,8 +462,10 @@ char* readFileToString(FILE* input)
return string; 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) { if (filename.type != TYPE_STRING) {
return errorObject(NULL_PARSE); return errorObject(NULL_PARSE);
} }

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* params, int length, struct Environment* env)
BASIC_OP(add); BASIC_OP(add);
@ -31,29 +31,29 @@ BASIC_OP(or);
fn(catObjects, fn(catObjects,
"Concatenate string versions of the given objects.", "Concatenate string versions of the given objects.",
"(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);
fn(filter, fn(filter,
"Filter a list based on the given condition.", "Filter a list based on the given condition.",
"(fil (< 50) (25 60 100))", "( 60 100 )", "(fil (< 50) (25 60 100))", "( 60 100 )",
)(Object condition, Object list, struct Environment* env); ); // (Object condition, Object list, struct Environment* env);
fn(append, fn(append,
"Append the given element. Creates a new list.", "Append the given element. Creates a new list.",
"(ap (1 2) 3)", "( 1 2 3 )", "(ap (1 2) 3)", "( 1 2 3 )",
)(Object list, Object newElement, struct Environment* env); ); // (Object list, Object newElement, struct Environment* env);
fn(prepend, fn(prepend,
"Prepend the given element. Creates a new list", "Prepend the given element. Creates a new list",
"(pre (2 3) 1)", "( 1 2 3 )", "(pre (2 3) 1)", "( 1 2 3 )",
)(Object list, Object newElement, struct Environment* env); ); // (Object list, Object newElement, struct Environment* env);
fn(len, fn(len,
"Returns the length of the given list, or a NOT_A_LIST error if the expression is not a list.", "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 (2 3))", "2",
"(len ())", "0", "(len ())", "0",
"(len \"string\")", "NOT_A_LIST", "(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, fn(reduce,
"Performs a simple reduction. Does not currently work with lambdas.\n" "Performs a simple reduction. Does not currently work with lambdas.\n"
@ -62,27 +62,27 @@ fn(reduce,
" - A function to apply to each value.", " - A function to apply to each value.",
"(reduce (5 6) +)", "11", "(reduce (5 6) +)", "11",
"(reduce ((1 2 3) 0) +)", "6", "(reduce ((1 2 3) 0) +)", "6",
)(Object listInitial, Object func, struct Environment* env); ); // (Object listInitial, Object func, struct Environment* env);
fn(at, fn(at,
"Get item at the given index in the given list.", "Get item at the given index in the given list.",
"(at 1 (1 2 3))", "2", "(at 1 (1 2 3))", "2",
"(at 99 (1 2 3))", "INDEX_PAST_END", "(at 99 (1 2 3))", "INDEX_PAST_END",
"(at 99 \"string\")", "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, fn(rest,
"Get the tail of a list. All but the first element.", "Get the tail of a list. All but the first element.",
"(rest (1 2 3))", "( 2 3 )", "(rest (1 2 3))", "( 2 3 )",
"(rest ())", "( )", "(rest ())", "( )",
"(rest \"string\")", "( )", "(rest \"string\")", "( )",
)(Object list, Object ignore, struct Environment* env); ); // (Object list, Object ignore, struct Environment* env);
fn(reverse, fn(reverse,
"Reverse a list.", "Reverse a list.",
"(rev (1 2 3))", "( 3 2 1 )", "(rev (1 2 3))", "( 3 2 1 )",
"(rev \"string\")", "NOT_A_LIST", "(rev \"string\")", "NOT_A_LIST",
)(Object _list, Object ignore, struct Environment* ignore2); ); // (Object _list, Object ignore, struct Environment* ignore2);
fn(isNum, fn(isNum,
"Returns `T` only if the argument evaluates to a number.", "Returns `T` only if the argument evaluates to a number.",
@ -90,14 +90,14 @@ fn(isNum,
"(isnum (+ 5 5))", "T", "(isnum (+ 5 5))", "T",
"(isnum '(+ 5 5))", "F", "(isnum '(+ 5 5))", "F",
"(isnum \"Hello\")", "F", "(isnum \"Hello\")", "F",
)(Object test, Object ignore, struct Environment* ignore2); ); // (Object test, Object ignore, struct Environment* ignore2);
fn(isList, fn(isList,
"Returns `T` only if the argument is a list.", "Returns `T` only if the argument is a list.",
"(islist (1 2 3))", "T", "(islist (1 2 3))", "T",
"(islist ())", "T", "(islist ())", "T",
"(islist \"Stringy\")", "F", "(islist \"Stringy\")", "F",
)(Object test, Object ignore, struct Environment* ignore2); ); // (Object test, Object ignore, struct Environment* ignore2);
fn(isString, fn(isString,
"Returns `T` only if the argument is a string.", "Returns `T` only if the argument is a string.",
@ -105,56 +105,56 @@ fn(isString,
"(isstr \"\")", "T", "(isstr \"\")", "T",
"(isstr (cat 5 5))", "T", "(isstr (cat 5 5))", "T",
"(isstr 10)", "F", "(isstr 10)", "F",
)(Object test, Object ignore, struct Environment* ignore2); ); // (Object test, Object ignore, struct Environment* ignore2);
fn(isErr, fn(isErr,
"Check if the argument is an error.", "Check if the argument is an error.",
"(iserr (at 10 ()))", "T", "(iserr (at 10 ()))", "T",
"(iserr 5)", "F", "(iserr 5)", "F",
)(Object test, Object ignore, struct Environment* ignore2); ); // (Object test, Object ignore, struct Environment* ignore2);
fn(charAt, fn(charAt,
"Get the char in the given string at the given index.", "Get the char in the given string at the given index.",
"(chat \"Hello\" 1)", "e", "(chat \"Hello\" 1)", "e",
"(chat \"Hello\" 10)", "", "(chat \"Hello\" 10)", "",
)(Object string, Object at, struct Environment* ignore); ); // (Object string, Object at, struct Environment* ignore);
fn(charVal, fn(charVal,
"Get the ascii integer representaton of the given character.", "Get the ascii integer representaton of the given character.",
"(char \"h\")", "104", "(char \"h\")", "104",
"(char \"hello\")", "104", "(char \"hello\")", "104",
"(char \"\")", "0", "(char \"\")", "0",
)(Object test, Object ignore, struct Environment* ignore2); ); // (Object test, Object ignore, struct Environment* ignore2);
fn(parseEvalO, fn(parseEvalO,
"Evaluate the given string or quoted list.", "Evaluate the given string or quoted list.",
"(eval \"(1 2 3)\")", "( 1 2 3 )", "(eval \"(1 2 3)\")", "( 1 2 3 )",
"(eval '(+ 5 5))", "10", "(eval '(+ 5 5))", "10",
)(Object text, Object ignore, struct Environment* env); ); // (Object text, Object ignore, struct Environment* env);
fn(possessive, fn(possessive,
"(struct Post (title body))\n" "(struct Post (title body))\n"
"(def p (Post \"TI\" \"BO\"))\n" "(def p (Post \"TI\" \"BO\"))\n"
"p's title => TI" "p's title => TI"
)(Object structo, Object field, struct Environment* env); ); // (Object structo, Object field, struct Environment* env);
#ifdef STANDALONE #ifdef STANDALONE
fn(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);
fn(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);
fn(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);
fn(systemCall, fn(systemCall,
"Opens a shell and runs the given command, returning the command's exit code.\n" "Opens a shell and runs the given command, returning the command's exit code.\n"
"(sys \"echo yee\")\n" "(sys \"echo yee\")\n"
"yee\n" "yee\n"
"=> 0" "=> 0"
)(Object process, Object _, struct Environment* env); ); // (Object process, Object _, struct Environment* env);
fn(loadFile, fn(loadFile,
"Loads and parses the given file.\n" "Loads and parses the given file.\n"
@ -162,24 +162,24 @@ fn(loadFile,
"(loadfile \"printdate.pl\")\n" "(loadfile \"printdate.pl\")\n"
"Mon 21 Mar 2022 10:35:03 AM EDT\n" "Mon 21 Mar 2022 10:35:03 AM EDT\n"
"=> 0" "=> 0"
)(Object filename, Object _, struct Environment* env); ); // (Object filename, Object _, struct Environment* env);
fn(takeInput, fn(takeInput,
"Take console input with an optional prompt. For example:\n" "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))` will wait for user input with no prompt.\n"
"`(def x (input \">> \"))` wait for input, but prompt the user with '>> '.\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, fn(help,
"Displays help text for the given function.\n" "Displays help text for the given function.\n"
"Currently requires the function name as a string, but future syntactic sugar may\n" "Currently requires the function name as a string, but future syntactic sugar may\n"
"loosen this requirement.\n" "loosen this requirement.\n"
"(? \"+\") => \"(+ 1 2) => 3\"" "(? \"+\") => \"(+ 1 2) => 3\""
)(Object symbol, Object ignore, struct Environment* ignore2); ); // (Object symbol, Object ignore, struct Environment* ignore2);
fn(readFileToObject, fn(readFileToObject,
"Read a file into a string object." "Read a file into a string object."
)(Object filename, Object ignore, struct Environment* ignore2); ); // (Object filename, Object ignore, struct Environment* ignore2);
#endif // STANDALONE #endif // STANDALONE

View File

@ -141,8 +141,10 @@ int start(int port)
return 0; 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 c = cloneObject(p);
Object e = eval(&c, env); Object e = eval(&c, env);
_printObj(&e, 0); _printObj(&e, 0);
@ -165,20 +167,26 @@ void addRouteO(Object path, Object textFunc, struct Environment* env, enum Route
addRoute(r); 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); addRouteO(path, textFunc, env, GET);
return numberObject(1); 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); addRouteO(path, textFunc, env, POST);
return numberObject(1); 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; int port = 8888;
if (portObject.type == TYPE_NUMBER) { if (portObject.type == TYPE_NUMBER) {
port = portObject.number; port = portObject.number;

View File

@ -21,18 +21,18 @@ fn(startServer,
"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); );
fn(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); );
fn(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"
)(Object path, Object textFunc, struct Environment* env); );