#include #include #include #include "general.h" Object reduce(Object* params, unused int length, struct Environment* env) { checkTypes(reduce); Object list = params[0]; Object func = params[1]; Object total = params[2]; if (list.type != TYPE_LIST) { func = cloneObject(func); list.forward = &total; return funcyEval(&func, &list, 2, env); } Object* first = list.list; FOR_POINTER_IN_LIST(&list) { func = cloneObject(func); Object oldTotal = total; total.forward = POINTER; total = funcyEval(&func, &total, 2, env); if (POINTER != first) { cleanObject(&oldTotal); } } return total; } Object filter(Object* params, unused int length, struct Environment* env) { checkTypes(filter); Object condition = params[0]; Object list = params[1]; Object BuildListNamed(filtered); FOR_POINTER_IN_LIST(&list) { Object cloned = cloneObject(condition); Object first_eval = eval(&cloned, env); Object testee = cloneObject(*POINTER); Object e = funcyEval(&first_eval, &testee, 1, env); if (e.number) { addToList(filtered, testee); // May need to re-clone testee? } cleanObject(&e); cleanObject(&cloned); } return filtered; } Object append(Object* params, unused int length, unused struct Environment* env) { checkTypes(append); Object list = params[0]; Object newElement = params[1]; Object newList = cloneObject(list); nf_addToList(&newList, cloneObject(newElement)); return newList; } Object prepend(Object* params, unused int length, unused struct Environment* env) { checkTypes(prepend); Object list = cloneObject(params[0]); Object newElement = cloneObject(params[1]); Object* previousFirst = list.list; allocObject(&list.list, newElement); list.list->forward = previousFirst; return list; } Object at(Object* params, unused int length, unused struct Environment* env) { checkTypes(at); Object index = params[0]; Object list = params[1]; int n = index.number; FOR_POINTER_IN_LIST(&list) { if (n-- == 0) { return cloneObject(*POINTER); } } throw(INDEX_PAST_END, "Tried to access index %ld from list of len %d", index.number, listLength(&list)); } Object rest(Object* params, unused int length, unused struct Environment* env) { checkTypes(rest); Object list = params[0]; Object BuildListNamed(ret); if (list.list) { for (Object* _element = list.list->forward; _element != NULL; _element = _element->forward) { addToList(ret, cloneObject(*POINTER)); } } return ret; } Object reverse(Object* params, unused int length, unused struct Environment* ignore2) { checkTypes(reverse); const Object* list = ¶ms[0]; 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* params, unused int length, unused struct Environment* env) { checkTypes(isNum); Object test = params[0]; return boolObject(test.type == TYPE_NUMBER); } Object isList(Object* params, unused int length, unused struct Environment* env) { checkTypes(isList); Object test = params[0]; return boolObject(test.type == TYPE_LIST); } Object isString(Object* params, unused int length, unused struct Environment* env) { checkTypes(isString); Object test = params[0]; return boolObject(test.type == TYPE_STRING); } Object isErr(Object* params, unused int length, unused struct Environment* env) { checkTypes(isErr); Object test = params[0]; return boolObject(test.type == TYPE_ERROR); } Object printEnvO(Object* params, int length, unused struct Environment* env) { int printPointers = 0; if (length > 0 && params[0].type == TYPE_BOOL) { printPointers = params[0].number; } printEnv(global(), printPointers); return numberObject(0); } Object parseEvalO(Object* params, unused int length, struct Environment* env) { Object text = params[0]; env = global(); switch (text.type) { case TYPE_SYMBOL: { Object string = eval(&text, env); Object parsed = parseEval(string.string, "(eval)", env); cleanObject(&string); return parsed; } case TYPE_SLIST: return evalList(&text, env); case TYPE_STRING: return parseEval(text.string, "(eval)", env); default: throw(CAN_ONLY_EVAL_STRINGS, "Tried to (eval) a %s, instead of a string or symbol list", getTypeName(&text)); } } Object catObjects(Object* params, int length, unused struct Environment* env) { checkTypes(catObjects); if (length == 0) { return stringFromSlice("", 0); } char* strings[length]; size_t totalLength = 0; for (int i = 0; i < length; i++) { strings[i] = stringObj(¶ms[i], &totalLength); } Object string = withLen(totalLength, TYPE_STRING); string.string[0] = '\0'; for (int i = 0; i < length; i++) { strcat(string.string, strings[i]); free(strings[i]); } return string; } Object len(Object* params, unused int length, unused struct Environment* env) { checkTypes(len); return numberObject(listLength(¶ms[0])); } #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_MATH(add, +=) BASIC_MATH(sub, -=) BASIC_MATH(mul, *=) BASIC_MATH(dvi, /=) BASIC_MATH(mod, %=) int areEqual(const Object* obj1, const Object* obj2); int listEquality(const Object* list1, const Object* list2) { Object* element1, * element2; for (element1 = (list1)->list, element2 = (list2)->list; element1 != ((void*) 0) && element2 != ((void*) 0); element1 = element1->forward, element2 = element2->forward) { if (!areEqual(element1, element2)) { return 0; } } return (element1 == NULL && element2 == NULL); } int areEqual(const Object* obj1, const Object* obj2) { const long n1 = obj1->number; const long n2 = obj2->number; if (bothAre(TYPE_STRING, obj1, obj2)) { return obj1->string == obj2->string || strcmp(obj1->string, obj2->string) == 0; } if (bothAre(TYPE_LIST, obj1, obj2)) { return listEquality(obj1, obj2); } return n1 == n2 && areSameType(obj1, obj2); } Object equ(Object* params, int length, unused struct Environment* env) { if (length < 2) { throw(NOT_ENOUGH_ARGUMENTS, "expected at least 2"); } for (int i = 0; i < length - 1; i++) { if (!areEqual(¶ms[i], ¶ms[i + 1])) { return falseObject(); } } return trueObject(); } Object or(Object* params, int length, unused struct Environment* env) { if (length < 2) { throw(NOT_ENOUGH_ARGUMENTS, "`|` requires at least two arguments"); } for (int i = 0; i < length - 1; i++) { if (params[i].number || params[i + 1].number) { return trueObject(); } } return falseObject(); } #define BASIC_COMPARISON(NAME, OP)\ Object NAME(Object* params, int length, struct Environment* env) \ { \ if (length < 2) { \ throw(NOT_ENOUGH_ARGUMENTS, "`" # OP "` requires at least two arguments"); \ } \ \ for (int i = 0; i < length - 1; i++) { \ if (!(params[i].number OP params[i + 1].number)) { \ return falseObject(); \ } \ } \ return trueObject(); \ } BASIC_COMPARISON(greaterThan, >) BASIC_COMPARISON(lessThan, <) BASIC_COMPARISON(and, &&) int timeStructDefinition = -1; Object getTime(unused Object* params, unused int length, struct Environment* env) { if (timeStructDefinition == -1) { parseEval("(struct Time (minute hour sec))", "[INTERNAL]", env); timeStructDefinition = getStructIndex("Time"); } time_t t = time(NULL); struct tm tm = *localtime(&t); Object o = structObject(timeStructDefinition); o.structObject->fields[0] = numberObject(tm.tm_min); o.structObject->fields[1] = numberObject(tm.tm_hour); o.structObject->fields[2] = numberObject(tm.tm_sec); return o; }