Add funcyEval() for equivalent Func/Lambda eval.
Still a bit buggy. Some general renaming for clarification.
This commit is contained in:
parent
4baf7e011b
commit
7a0433aa68
22
src/env.c
22
src/env.c
|
@ -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;
|
||||
|
||||
|
|
|
@ -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, "?",
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ Object getPrompt(struct Environment* env)
|
|||
return prompt;
|
||||
}
|
||||
Object param = stringFromSlice("", 1);
|
||||
Object e = listEvalLambda(&prompt, ¶m, 2, env);
|
||||
Object e = funcyEval(&prompt, ¶m, 1, env);
|
||||
cleanObject(&prompt);
|
||||
cleanObject(¶m);
|
||||
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);
|
||||
}
|
||||
|
|
26
src/object.c
26
src/object.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(¶ms[0], env);
|
||||
const Object* inputList = ¶ms[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(¶ms[i]));
|
||||
sprintf(context, "When calling (%s), expected %s, but received %s.", funcName, typeChecks[i].name,
|
||||
getTypeName(¶ms[i]));
|
||||
return errorWithContextLineNo(BAD_PARAMS, context, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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?
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue