pebblisp/src/plfunc/general.c

344 lines
8.6 KiB
C

#include <stdio.h>
#include <string.h>
#include <time.h>
#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 = &params[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(&params[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(&params[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(&params[i], &params[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;
}