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));
|
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;
|
||||||
|
|
||||||
|
|
|
@ -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, "?",
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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, ¶m, 2, env);
|
Object e = funcyEval(&prompt, ¶m, 1, env);
|
||||||
cleanObject(&prompt);
|
cleanObject(&prompt);
|
||||||
cleanObject(¶m);
|
cleanObject(¶m);
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
26
src/object.c
26
src/object.c
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(¶ms[0], env);
|
Object lambda = eval(¶ms[0], env);
|
||||||
const Object* inputList = ¶ms[1];
|
const Object* inputList = ¶ms[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(¶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);
|
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 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,
|
||||||
|
|
|
@ -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?
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue