Add funcyEval() for equivalent Func/Lambda eval.

Still a bit buggy.
Some general renaming for clarification.
This commit is contained in:
Sage Vaillancourt 2022-04-07 01:20:59 -04:00
parent 4baf7e011b
commit 7a0433aa68
11 changed files with 85 additions and 62 deletions

View File

@ -91,7 +91,15 @@ void addToEnv(struct Environment* env, const char* name, const Object obj)
addToTable(&env->table, symbol, cloneObject(obj));
}
struct Environment envForLambda(const Object* params, const Object* arg_forms, int paramCount,
/**
* Build the local Environment for a given lambda
* @param params List of symbol objects with the names of lambda params
* @param paramCount Length of params list
* @param arguments Arguments being passed into the lambda where ->forward is the next arg
* @param outer The parent scope
* @return The constructed environment
*/
struct Environment envForLambda(const Object* params, const Object* arguments, int paramCount,
struct Environment* outer)
{
if (outer) {
@ -104,14 +112,14 @@ struct Environment envForLambda(const Object* params, const Object* arg_forms, i
.refs = 1,
};
const Object* march = arg_forms;
const Object* argument = arguments;
for (int i = 0; i < paramCount; i++) {
const char* newObjName = itemAt(params, i)->string;
// Eval the `march` list
Object newEnvObj = march ? eval(march, outer) : errorWithContext(NOT_ENOUGH_ARGUMENTS, newObjName);
addToEnv(&env, newObjName, newEnvObj); // Could use eval_forms?
const char* paramName = itemAt(params, i)->string;
// Eval the `argument` list
Object newEnvObj = argument ? eval(argument, outer) : errorWithContext(NOT_ENOUGH_ARGUMENTS, paramName);
addToEnv(&env, paramName, newEnvObj); // Could use eval_forms?
cleanObject(&newEnvObj);
march = march ? march->forward : NULL;
argument = argument ? argument->forward : NULL;
}
env.outer = outer;

View File

@ -25,7 +25,7 @@ void setGlobal(struct Environment* env);
Object fetchFromEnvironment(const char* name, struct Environment* env);
struct Environment envForLambda(const Object* params, const Object* arg_forms, int paramCount,
struct Environment envForLambda(const Object* params, const Object* arguments, int paramCount,
struct Environment* outer);
void addToEnv(struct Environment* env, const char* name, Object obj);
@ -56,6 +56,7 @@ void printColored(const char* code);
int runTests(int detailed);
int getTotalSearchDepth();
int getTotalSearches();
#define unused __attribute__((unused))
@ -73,7 +74,7 @@ static const char * const _name ## Symbol = _symbol; \
fnn(_name, _docs, __VA_ARGS__)
fn(segfault, "seg",
"Induces a segfault."
"Induces a segfault."
);
fn(help, "?",

View File

@ -85,6 +85,7 @@ void extendTable(struct ObjectTable* table)
for (size_t i = oldCapacity; i < table->capacity; i++) {
table->elements[i].symbol = NULL;
}
free(oldElements);
}
}

View File

@ -16,7 +16,7 @@ Object getPrompt(struct Environment* env)
return prompt;
}
Object param = stringFromSlice("", 1);
Object e = listEvalLambda(&prompt, &param, 2, env);
Object e = funcyEval(&prompt, &param, 1, env);
cleanObject(&prompt);
cleanObject(&param);
return e;
@ -34,7 +34,7 @@ char* preprocess(char* buf, struct Environment* env)
{
Object lambda = fetchFromEnvironment("preprocess", env);
Object buffer = nullTerminated(buf);
Object s = listEvalLambda(&lambda, &buffer, 2, env);
Object s = funcyEval(&lambda, &buffer, 1, env);
size_t length;
return stringObj(&s, &length);
}

View File

@ -277,7 +277,7 @@ int stringNObj(struct string* s, const Object* obj)
inflate(s, 128);
if (obj->error->context && obj->error->context[0] != '\0') {
s->cursor += sprintf(s->cursor, "%s: %s", errorText[code],
obj->error->context);
obj->error->context);
} else if (code >= 0 && code <= INDEX_PAST_END) {
s->cursor += sprintf(s->cursor, "%s", errorText[code]);
} else {
@ -744,19 +744,17 @@ inline Object constructLambda(const Object* params, const Object* body, struct E
o.lambda->body = copyList(body);
o.lambda->refs = 1;
if (env) {
Object* dest = &o.lambda->body;
FOR_POINTER_IN_LIST(dest) {
if (POINTER->type == TYPE_SYMBOL) {
Object fetched = fetchFromEnvironment(POINTER->string, env);
// TODO: Figure out why lambdas in particular break when doing this.
if (!isError(fetched, DID_NOT_FIND_SYMBOL) && fetched.type != TYPE_LAMBDA) {
fetched.forward = POINTER->forward;
cleanObject(POINTER);
*POINTER = fetched;
} else {
cleanObject(&fetched);
}
Object* dest = &o.lambda->body;
FOR_POINTER_IN_LIST(dest) {
if (POINTER->type == TYPE_SYMBOL) {
Object fetched = fetchFromEnvironment(POINTER->string, env);
// TODO: Figure out why lambdas in particular break when doing this.
if (!isError(fetched, DID_NOT_FIND_SYMBOL) && fetched.type != TYPE_LAMBDA) {
fetched.forward = POINTER->forward;
cleanObject(POINTER);
*POINTER = fetched;
} else {
cleanObject(&fetched);
}
}
}

View File

@ -48,13 +48,14 @@ Object evalStructArgs(const Object* symbol, const Object* fields, unused struct
return errorObject(NOT_A_LIST);
}
struct StructDef def;
def.name = malloc(sizeof(char) * (strlen(name) + 1));
int fieldCount = listLength(fields);
struct StructDef def = {
.name = malloc(sizeof(char) * (strlen(name) + 1)),
.fieldCount = fieldCount,
.names = malloc(sizeof(char*) * fieldCount),
};
strcpy(def.name, name);
def.fieldCount = listLength(fields);
def.names = malloc(sizeof(char*) * def.fieldCount);
int i = 0;
FOR_POINTER_IN_LIST(fields) {
def.names[i] = malloc(sizeof(char) * (strlen(POINTER->string) + 1));
@ -88,7 +89,7 @@ Object mapO(Object* params, int length, struct Environment* env)
Object lambda = eval(&params[0], env);
const Object* inputList = &params[1];
if (lambda.type != TYPE_LAMBDA) {
if (!isFuncy(lambda)) {
return errorObject(BAD_TYPE);
}
@ -118,8 +119,8 @@ Object mapO(Object* params, int length, struct Environment* env)
* Tries to either apply the function to its parameters, or create a partial
* function, if not enough parameters were passed.
*
* @param function First element of the paramList, already evaluated to be a function
* @param paramList The parameters to the function
* @param function The object evaluated to be TYPE_FUNC
* @param paramList Ongoing (forward->forward) list of parameters to the function
* @param length Length of `paramList` - 1, to exclude the already-evaluated element
* @param env The environment to evaluate in
*/
@ -145,7 +146,7 @@ Object simpleFuncEval(const Object func, Object arg1, Object arg2, struct Enviro
arg2 = cloneObject(arg2);
arg1.forward = &arg2;
Object first_eval = eval(&func, env);
Object ret = listEvalFunc(&first_eval, &arg1, 2, env);
Object ret = funcyEval(&first_eval, &arg1, 2, env);
cleanObject(&first_eval);
cleanObject(&arg2);
return ret;
@ -157,15 +158,15 @@ Object simpleFuncEval(const Object func, Object arg1, Object arg2, struct Enviro
* Tries to apply the lambda to its parameters. Doesn't attempt partial
* application.
*
* @param lambda First element of the list, already evaluated to be a lambda
* @param remaining The first element after `lambda`
* @param lambda The object evaluated to be TYPE_LAMBDA
* @param passedArguments Ongoing (forward->forward) list of parameters to the lambda
* @param env The environment to evaluate in
*/
Object listEvalLambda(Object* lambda, const Object* remaining, int evalLength,
Object listEvalLambda(Object* lambda, const Object* passedArguments, int evalLength,
struct Environment* env)
{
struct Environment newEnv =
envForLambda(&lambda->lambda->params, remaining, evalLength - 1, env);
envForLambda(&lambda->lambda->params, passedArguments, evalLength, env);
Object ret = eval(&lambda->lambda->body, &newEnv);
deleteEnv(&newEnv);
cleanObject(lambda);
@ -179,6 +180,24 @@ Object listEvalLambda(Object* lambda, const Object* remaining, int evalLength,
return ret;
}
Object funcyEval(Object* funcy, const Object* passedArguments, int evalLength,
struct Environment* env)
{
if (!funcy) {
eprintf("HIGHLY ILLEGAL NULL FUNCY!!!\n");
return errorObject(BAD_TYPE);
}
switch (funcy->type) {
case TYPE_LAMBDA:
return listEvalLambda(funcy, passedArguments, evalLength, env);
case TYPE_FUNC:
return listEvalFunc(funcy, passedArguments, evalLength, env);
default:
eprintf("HIGHLY ILLEGAL NOT-FUNCY IN funcyEval()!!!\n");
return errorObject(BAD_TYPE);
}
}
/**
* Evaluates a given list, including the application of functions and lambdas
*
@ -232,10 +251,10 @@ Object evalList(const Object* obj, struct Environment* env)
switch (first_eval.type) {
case TYPE_FUNC:
// Uses evalLength - 1 because we skip the first form (the function itself)
return listEvalFunc(&first_eval, obj->list->forward, evalLength - 1, env);
return listEvalFunc(&first_eval, first_form->forward, evalLength - 1, env);
case TYPE_LAMBDA:
return listEvalLambda(&first_eval, first_form->forward, evalLength, env);
return listEvalLambda(&first_eval, first_form->forward, evalLength - 1, env);
default: { // Return list with each element evaluated
Object list = listObject();
@ -253,19 +272,6 @@ Object evalList(const Object* obj, struct Environment* env)
}
}
#include <stdarg.h>
Object funcyWithArgs(Object funcy, int count, ...)
{
va_list ptr;
va_start(ptr, count);
Object args[count];
for (int i = 0; i < count; i++) {
args[i] = va_arg(ptr, Object);
}
va_end(ptr);
}
Object eval(const Object* obj, struct Environment* env)
{
switch (obj->type) {
@ -321,9 +327,8 @@ Result parse(struct Slice* slices)
}
return r;
} else if (token->text[0] == '(') {
// todo check for null rest
return readSeq(rest);
} else { // todo error on missing close paren
} else {
Result r = parseAtom(token);
r.slices = &r.slices[1];
return r;
@ -363,7 +368,7 @@ Result readSeq(struct Slice* tokens)
tokens = r.slices;
cleanObject(&r.obj);
forceString = next->text[0] == '?'
|| (strncmp(next->text, "def", 3) == 0);
|| (strncmp(next->text, "def", 3) == 0);
}
}
@ -521,7 +526,8 @@ Object typeCheck(const char* funcName, Object* params, int length,
for (int i = 0; i < typeLength - 1; i++) {
if (typeChecks[i].checkFunc && !typeChecks[i].checkFunc(params[i])) {
char context[128];
sprintf(context, "When calling (%s), expected %s, but received %s.", funcName, typeChecks[i].name, getTypeName(&params[i]));
sprintf(context, "When calling (%s), expected %s, but received %s.", funcName, typeChecks[i].name,
getTypeName(&params[i]));
return errorWithContextLineNo(BAD_PARAMS, context, 0, NULL);
}
}

View File

@ -77,9 +77,12 @@ Object parseEval(const char* input, struct Environment* env);
Object evalList(const Object* obj, struct Environment* env);
Object listEvalLambda(Object* lambda, const Object* remaining, int evalLength,
Object listEvalLambda(Object* lambda, const Object* passedArguments, int evalLength,
struct Environment* env);
Object funcyEval(Object* funcy, const Object* passedArguments, int evalLength,
struct Environment* env);
Object simpleFuncEval(Object func, Object arg1, Object arg2, struct Environment* env);
Object typeCheck(const char* funcName, Object* params, int length,

View File

@ -15,8 +15,14 @@ Object reduce(Object* params, unused int length, struct Environment* env)
return simpleFuncEval(func, total, list, env);
}
int isFirst = 1;
FOR_POINTER_IN_LIST(&list) {
Object oldTotal = total;
total = simpleFuncEval(func, total, *POINTER, env);
if (!isFirst) {
cleanObject(&oldTotal);
}
isFirst = 0;
}
return total;
@ -53,7 +59,7 @@ Object filter(Object* params, unused int length, struct Environment* env)
Object cloned = cloneObject(condition);
Object first_eval = eval(&cloned, env);
Object testee = cloneObject(*POINTER);
Object e = listEvalLambda(&first_eval, &testee, 2, env);
Object e = funcyEval(&first_eval, &testee, 1, env);
if (e.number) {
nf_addToList(&filtered, testee); // May need to re-clone testee?
}

View File

@ -102,7 +102,7 @@ tfn(len, "len",
tfn(reduce, "reduce",
({ anyType, expect(isFuncy), anyType, anyType }),
"Performs a simple reduction. Does not currently work with lambdas.\n"
"Performs a simple reduction. Does not currently work with lambdas.\n" // TODO: Still not working
"Takes three arguments:\n"
" - Values\n"
" - A function to apply to each value\n"

View File

@ -55,7 +55,7 @@ void* doAsync(void* args)
Object cloned = cloneObject(promise->object);
Object first_eval = eval(&cloned, promise->env);
Object e = listEvalLambda(&first_eval, NULL, 1, promise->env);
Object e = funcyEval(&first_eval, NULL, 0, promise->env);
promise->object = e;
promise->done = 1;

View File

@ -101,7 +101,7 @@ answer_to_connection(void* cls, struct MHD_Connection* connection,
res.structObject->fields[2] = passwordO;
Object route = cloneObject(routes[i].routeAction);
Object result = listEvalLambda(&route, &res, 2, routes[i].env);
Object result = funcyEval(&route, &res, 1, routes[i].env);
cleanObject(&res);
page = result.string;
break;