#include #include #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