pebblisp/src/plfunc.c

351 lines
9.0 KiB
C

#include <stdio.h>
#include <string.h>
#include "plfunc.h"
/**
* (reduce (list, initial) (fn (prev total) (+ prev total)))
*/
Object reduce(const Object listInitial, const Object func, struct Environment* env)
{
Object* list = itemAt(&listInitial, 0);
Object total = cloneObject(*list->forward); // From given initial value
if (list->type != TYPE_LIST) {
return simpleFuncEval(func, total, *list, env);
}
FOR_POINTER_IN_LIST(list) {
total = simpleFuncEval(func, total, *POINTER, env);
}
return total;
}
Object charAt(Object string, Object at, struct Environment* ignore)
{
char* c = malloc(sizeof(char) * 2);
c[0] = string.string[at.number];
c[1] = '\0';
string.string = c;
return string;
}
Object filter(Object condition, Object list, struct Environment* env)
{
Object filteredList = listObject();
FOR_POINTER_IN_LIST(&list) {
Object conditional = cloneObject(condition);
nf_addToList(&conditional, *POINTER);
Object result = eval(&conditional, env);
cleanObject(&conditional);
if (result.number == 1) {
nf_addToList(&filteredList, *POINTER);
}
}
return filteredList;
}
Object append(Object list, Object newElement, struct Environment* env)
{
Object newList = cloneObject(list);
nf_addToList(&newList, cloneObject(newElement));
return newList;
}
Object prepend(Object list, Object newElement, struct Environment* env)
{
Object newList = listObject();
nf_addToList(&newList, cloneObject(newElement));
appendList(&newList, &list);
return newList;
}
Object at(Object index, Object list, struct Environment* env)
{
const Object* found = itemAt(&list, index.number);
if (found) {
return cloneObject(*found);
} else {
return errorObject(INDEX_PAST_END);
}
}
Object rest(Object list, Object ignore, struct Environment* env)
{
Object ret = listObject();
Object* l = &list;
FOR_POINTER_IN_LIST(l) {
if (POINTER == l->list) {
continue;
}
nf_addToList(&ret, cloneObject(*POINTER));
}
return ret;
}
Object reverse(Object _list, Object ignore, struct Environment* ignore2)
{
const Object* list = &_list;
Object rev = listObject();
Object* tail = NULL;
FOR_POINTER_IN_LIST(list) {
Object* oldTail = tail;
allocObject(&tail, cloneObject(*POINTER));
if (oldTail) {
tail->forward = oldTail;
}
}
rev.list = tail;
return rev;
}
Object isNum(Object test, Object ignore, struct Environment* ignore2)
{
return test.type == TYPE_NUMBER ? boolObject(1) : boolObject(0);
}
Object isList(Object test, Object ignore, struct Environment* ignore2)
{
return test.type == TYPE_LIST ? boolObject(1) : boolObject(0);
}
Object isString(Object test, Object ignore, struct Environment* ignore2)
{
return test.type == TYPE_STRING ? boolObject(1) : boolObject(0);
}
// Get the int value of a string's first character
Object charVal(Object test, Object ignore, struct Environment* ignore2)
{
return numberObject(test.string[0]);
// return test.type == TYPE_STRING && test.string[0] == '\0' ?
// boolObject(1) : boolObject(0);
}
Object isErr(Object test, Object ignore, struct Environment* ignore2)
{
return test.type == TYPE_ERROR ? boolObject(1) : boolObject(0);
}
Object parseEvalO(Object text, Object ignore, struct Environment* env)
{
if (text.type == TYPE_SYMBOL) {
Object string = eval(&text, env);
Object parsed = parseEval(string.string, env);
cleanObject(&string);
return parsed;
} else if (text.type != TYPE_STRING) {
return errorObject(CAN_ONLY_EVAL_STRINGS);
}
return parseEval(text.string, env);
}
Object listEquality(const Object* list1, const Object* list2)
{
FOR_POINTERS_IN_LISTS(list1, list2) {
if (P1->type != P2->type || P1->number != P2->number) {
return boolObject(0);
}
}
return boolObject(1);
}
#define CAT_MAX 1024
Object catObjects(const Object obj1, const Object obj2, struct Environment* env)
{
Object evalObj1 = eval(&obj1, env);
Object evalObj2 = eval(&obj2, env);
if (isError(evalObj2, ONLY_ONE_ARGUMENT)) {
return evalObj1;
}
char str1[CAT_MAX] = "";
char str2[CAT_MAX] = "";
stringObj(str1, &evalObj1);
stringObj(str2, &evalObj2);
cleanObject(&evalObj1);
cleanObject(&evalObj2);
size_t length = strlen(str1) + strlen(str2) + 1;
Object o = newObject(TYPE_STRING);
o.string = calloc(sizeof(char), length);
strcat(o.string, str1);
strcat(o.string, str2);
return o;
}
Object _basicOp(const Object* obj1, const Object* obj2, const char op,
struct Environment* env)
{
const int n1 = obj1->number;
const int n2 = obj2->number;
switch (op) {
case '+':
if (eitherIs(TYPE_STRING, obj1, obj2)) {
return catObjects(*obj1, *obj2, env);
}
return numberObject(n1 + n2);
case '-':
return numberObject(n1 - n2);
case '*':
return numberObject(n1 * n2);
case '/':
return numberObject(n1 / n2);
case '%':
return numberObject(n1 % n2);
case '&':
return boolObject(n1 != 0 && n2 != 0);
case '|':
return boolObject(n1 != 0 || n2 != 0);
case '=':
if (bothAre(TYPE_STRING, obj1, obj2)) {
return boolObject(!strcmp(obj1->string, obj2->string));
}
if (bothAre(TYPE_LIST, obj1, obj2)) {
return listEquality(obj1, obj2);
}
return boolObject(n1 == n2 && areSameType(obj1, obj2));
case '>':
return boolObject(n1 > n2);
case '<':
return boolObject(n1 < n2);
default:
return *obj1;
}
}
Object basicOp(const Object* obj1, const Object* obj2, const char op,
struct Environment* env)
{
if (isError(*obj2, ONLY_ONE_ARGUMENT)) {
return *obj2;
}
int lists = (obj1->type == TYPE_LIST) + (obj2->type == TYPE_LIST);
if (lists == 0) {
return _basicOp(obj1, obj2, op, env);
} else if (lists == 1) { // Single operand is applied to each element in list
const Object* listObj = (obj1->type == TYPE_LIST) ? obj1 : obj2;
const Object* singleObj = (obj1->type == TYPE_LIST) ? obj2 : obj1;
Object newList = listObject();
FOR_POINTER_IN_LIST(listObj) {
Object adding = eval(POINTER, env);
nf_addToList(&newList, _basicOp(&adding, singleObj, op, env));
}
return newList;
} else { // 2 lists with the op applied to matching indices of both lists
if (listLength(obj1) == listLength(obj2)) {
Object newList = listObject();
FOR_POINTERS_IN_LISTS(obj1, obj2) {
const Object ev1 = eval(P1, env);
const Object ev2 = eval(P2, env);
nf_addToList(&newList, _basicOp(&ev1, &ev2, op, env));
}
return newList;
} else {
return errorObject(LISTS_NOT_SAME_SIZE);
}
}
}
Object len(Object obj1, Object o_ignore, struct Environment* e_ignore)
{
Object o = numberObject(listLength(&obj1));
if (o.number < 0) {
return errorObject(NOT_A_LIST);
}
return o;
}
#define BASIC_OP(_name, _char) \
Object _name(Object obj1, Object obj2, struct Environment *env) \
{ \
return basicOp(&obj1, &obj2, _char, env); \
}
BASIC_OP(add, '+')
BASIC_OP(sub, '-')
BASIC_OP(mul, '*')
BASIC_OP(dvi, '/')
BASIC_OP(mod, '%')
BASIC_OP(equ, '=')
BASIC_OP(gth, '>')
BASIC_OP(lth, '<')
BASIC_OP(and, '&')
BASIC_OP(or, '|')
#undef BASIC_OP
#ifdef STANDALONE
Object pChar(Object c, Object i1, struct Environment* i2)
{
if (c.type != TYPE_NUMBER) {
return errorObject(BAD_NUMBER);
}
printf("%c", c.number % 256);
return numberObject(0);
}
Object printEnvO(Object i1, Object i2, struct Environment* env)
{
printEnv(global());
return numberObject(0);
}
Object takeInput(Object prompt, Object i2, struct Environment* i3)
{
if (prompt.type == TYPE_STRING) {
printf("%s", prompt.string);
}
char input[256] = "";
fgets(input, 256, stdin);
return stringFromSlice(input, strlen(input) - 1);
}
Object loadFile(Object filename, Object _, struct Environment* env)
{
if (isStringy(filename)) {
readFile(filename.string, env);
return numberObject(0);
}
return numberObject(1);
}
Object systemCall(Object process, Object _, struct Environment* env)
{
if (isStringy(process)) {
return numberObject(system(process.string));
}
return numberObject(255);
}
Object help(Object symbol, Object ignore, struct Environment* ignore2)
{
char* help = getHelp(symbol.string);
Object helpText = newObject(TYPE_STRING);
helpText.string = help;
return helpText;
}
#endif // STANDALONE