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)); 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) struct Environment* outer)
{ {
if (outer) { if (outer) {
@ -104,14 +112,14 @@ struct Environment envForLambda(const Object* params, const Object* arg_forms, i
.refs = 1, .refs = 1,
}; };
const Object* march = arg_forms; const Object* argument = arguments;
for (int i = 0; i < paramCount; i++) { for (int i = 0; i < paramCount; i++) {
const char* newObjName = itemAt(params, i)->string; const char* paramName = itemAt(params, i)->string;
// Eval the `march` list // Eval the `argument` list
Object newEnvObj = march ? eval(march, outer) : errorWithContext(NOT_ENOUGH_ARGUMENTS, newObjName); Object newEnvObj = argument ? eval(argument, outer) : errorWithContext(NOT_ENOUGH_ARGUMENTS, paramName);
addToEnv(&env, newObjName, newEnvObj); // Could use eval_forms? addToEnv(&env, paramName, newEnvObj); // Could use eval_forms?
cleanObject(&newEnvObj); cleanObject(&newEnvObj);
march = march ? march->forward : NULL; argument = argument ? argument->forward : NULL;
} }
env.outer = outer; env.outer = outer;

View File

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

View File

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

View File

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

View File

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

View File

@ -48,13 +48,14 @@ Object evalStructArgs(const Object* symbol, const Object* fields, unused struct
return errorObject(NOT_A_LIST); return errorObject(NOT_A_LIST);
} }
struct StructDef def; int fieldCount = listLength(fields);
def.name = malloc(sizeof(char) * (strlen(name) + 1)); struct StructDef def = {
.name = malloc(sizeof(char) * (strlen(name) + 1)),
.fieldCount = fieldCount,
.names = malloc(sizeof(char*) * fieldCount),
};
strcpy(def.name, name); strcpy(def.name, name);
def.fieldCount = listLength(fields);
def.names = malloc(sizeof(char*) * def.fieldCount);
int i = 0; int i = 0;
FOR_POINTER_IN_LIST(fields) { FOR_POINTER_IN_LIST(fields) {
def.names[i] = malloc(sizeof(char) * (strlen(POINTER->string) + 1)); 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); Object lambda = eval(&params[0], env);
const Object* inputList = &params[1]; const Object* inputList = &params[1];
if (lambda.type != TYPE_LAMBDA) { if (!isFuncy(lambda)) {
return errorObject(BAD_TYPE); 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 * Tries to either apply the function to its parameters, or create a partial
* function, if not enough parameters were passed. * function, if not enough parameters were passed.
* *
* @param function First element of the paramList, already evaluated to be a function * @param function The object evaluated to be TYPE_FUNC
* @param paramList The parameters to the function * @param paramList Ongoing (forward->forward) list of parameters to the function
* @param length Length of `paramList` - 1, to exclude the already-evaluated element * @param length Length of `paramList` - 1, to exclude the already-evaluated element
* @param env The environment to evaluate in * @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); arg2 = cloneObject(arg2);
arg1.forward = &arg2; arg1.forward = &arg2;
Object first_eval = eval(&func, env); 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(&first_eval);
cleanObject(&arg2); cleanObject(&arg2);
return ret; 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 * Tries to apply the lambda to its parameters. Doesn't attempt partial
* application. * application.
* *
* @param lambda First element of the list, already evaluated to be a lambda * @param lambda The object evaluated to be TYPE_LAMBDA
* @param remaining The first element after `lambda` * @param passedArguments Ongoing (forward->forward) list of parameters to the lambda
* @param env The environment to evaluate in * @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* env)
{ {
struct Environment newEnv = 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); Object ret = eval(&lambda->lambda->body, &newEnv);
deleteEnv(&newEnv); deleteEnv(&newEnv);
cleanObject(lambda); cleanObject(lambda);
@ -179,6 +180,24 @@ Object listEvalLambda(Object* lambda, const Object* remaining, int evalLength,
return ret; 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 * 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) { switch (first_eval.type) {
case TYPE_FUNC: case TYPE_FUNC:
// Uses evalLength - 1 because we skip the first form (the function itself) // 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: 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 default: { // Return list with each element evaluated
Object list = listObject(); 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) Object eval(const Object* obj, struct Environment* env)
{ {
switch (obj->type) { switch (obj->type) {
@ -321,9 +327,8 @@ Result parse(struct Slice* slices)
} }
return r; return r;
} else if (token->text[0] == '(') { } else if (token->text[0] == '(') {
// todo check for null rest
return readSeq(rest); return readSeq(rest);
} else { // todo error on missing close paren } else {
Result r = parseAtom(token); Result r = parseAtom(token);
r.slices = &r.slices[1]; r.slices = &r.slices[1];
return r; return r;
@ -363,7 +368,7 @@ Result readSeq(struct Slice* tokens)
tokens = r.slices; tokens = r.slices;
cleanObject(&r.obj); cleanObject(&r.obj);
forceString = next->text[0] == '?' 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++) { for (int i = 0; i < typeLength - 1; i++) {
if (typeChecks[i].checkFunc && !typeChecks[i].checkFunc(params[i])) { if (typeChecks[i].checkFunc && !typeChecks[i].checkFunc(params[i])) {
char context[128]; 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); 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 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); 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 simpleFuncEval(Object func, Object arg1, Object arg2, struct Environment* env);
Object typeCheck(const char* funcName, Object* params, int length, 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); return simpleFuncEval(func, total, list, env);
} }
int isFirst = 1;
FOR_POINTER_IN_LIST(&list) { FOR_POINTER_IN_LIST(&list) {
Object oldTotal = total;
total = simpleFuncEval(func, total, *POINTER, env); total = simpleFuncEval(func, total, *POINTER, env);
if (!isFirst) {
cleanObject(&oldTotal);
}
isFirst = 0;
} }
return total; return total;
@ -53,7 +59,7 @@ Object filter(Object* params, unused int length, struct Environment* env)
Object cloned = cloneObject(condition); Object cloned = cloneObject(condition);
Object first_eval = eval(&cloned, env); Object first_eval = eval(&cloned, env);
Object testee = cloneObject(*POINTER); Object testee = cloneObject(*POINTER);
Object e = listEvalLambda(&first_eval, &testee, 2, env); Object e = funcyEval(&first_eval, &testee, 1, env);
if (e.number) { if (e.number) {
nf_addToList(&filtered, testee); // May need to re-clone testee? nf_addToList(&filtered, testee); // May need to re-clone testee?
} }

View File

@ -102,7 +102,7 @@ tfn(len, "len",
tfn(reduce, "reduce", tfn(reduce, "reduce",
({ anyType, expect(isFuncy), anyType, anyType }), ({ 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" "Takes three arguments:\n"
" - Values\n" " - Values\n"
" - A function to apply to each value\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 cloned = cloneObject(promise->object);
Object first_eval = eval(&cloned, promise->env); 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->object = e;
promise->done = 1; promise->done = 1;

View File

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