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,
|
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
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
161
src/plfunc.c
161
src/plfunc.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -391,4 +480,4 @@ Object readFileToObject(Object filename, Object ignore, struct Environment* igno
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // STANDALONE
|
#endif // STANDALONE
|
||||||
|
|
58
src/plfunc.h
58
src/plfunc.h
|
@ -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
|
||||||
|
|
||||||
|
|
16
src/web.c
16
src/web.c
|
@ -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;
|
||||||
|
|
|
@ -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);
|
);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue