Break up evalList() and document the new functions
This commit is contained in:
parent
a39c6b2c53
commit
d8d8231f0d
158
src/pebblisp.c
158
src/pebblisp.c
|
@ -110,15 +110,116 @@ Object evalBuiltIns(const Object *first, const Object *rest,
|
||||||
return errorObject(BUILT_IN_NOT_FOUND);
|
return errorObject(BUILT_IN_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
void evalForms(Object *destList, const Object *src, struct Environment *env)
|
/**
|
||||||
|
* Bulk evaluator of Objects in a given list. Puts the results in a given array
|
||||||
|
*
|
||||||
|
* Note that `destArr` is a raw array, not an Object list, and that `start` is
|
||||||
|
* not itself a list, but the first element *in* a list to be evaluated. This
|
||||||
|
* allows more speed and flexibility in what should be evaluated.
|
||||||
|
*
|
||||||
|
* @param destArr The raw array to put the results into. Not an Object list!
|
||||||
|
* @param start The Object element to start with
|
||||||
|
* @param env The environment to use while evaluating
|
||||||
|
*/
|
||||||
|
void evalForms(Object *destArr, const Object *start, struct Environment *env)
|
||||||
{
|
{
|
||||||
int length = listLength(src) - 1; // Not counting first_form
|
int i = 0;
|
||||||
for(int i = 0; i < length; i++) { // Evaluates all in list
|
while(start) {
|
||||||
Object *ptr = itemAt(src, i + 1); // Skip the first
|
destArr[i] = eval(start, env);
|
||||||
destList[i] = eval(ptr, env);
|
start = start->forward;
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates a list whose first element is a function, applying that function
|
||||||
|
*
|
||||||
|
* Tries to either apply the function to its parameters, or create a partial
|
||||||
|
* function, if not enough parameters were passed.
|
||||||
|
*
|
||||||
|
* @param list The list being evaluated
|
||||||
|
* @param function First element of the list, already evaluated to be a function
|
||||||
|
* @param length Length of `list` - 1, to exclude the already-evaluated element
|
||||||
|
* @param env The environment to evaluate in
|
||||||
|
*/
|
||||||
|
Object listEvalFunc(
|
||||||
|
const Object *list,
|
||||||
|
const Object *function,
|
||||||
|
const int length,
|
||||||
|
struct Environment *env)
|
||||||
|
{
|
||||||
|
Object rest[length];
|
||||||
|
evalForms(rest, list->list->forward, env);
|
||||||
|
|
||||||
|
Object func_result = rest[0];
|
||||||
|
if(length == 1) {
|
||||||
|
func_result = function->func(
|
||||||
|
func_result, errorObject(ONLY_ONE_ARGUMENT), env);
|
||||||
|
// Return a partial function if more parameters are required
|
||||||
|
// Otherwise, return the function result
|
||||||
|
return isError(func_result, ONLY_ONE_ARGUMENT) ?
|
||||||
|
cloneObject(*list) :
|
||||||
|
func_result;
|
||||||
|
} else {
|
||||||
|
// With two args, will apply function once
|
||||||
|
// With more than two args, apply the function repeatedly
|
||||||
|
for(int i = 1; i < length; i++) {
|
||||||
|
Object toClean = func_result;
|
||||||
|
func_result = function->func(func_result, rest[i], env);
|
||||||
|
cleanObject(&toClean);
|
||||||
|
cleanObject(&rest[i]);
|
||||||
|
}
|
||||||
|
return func_result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates a list whose first element is a lambda, applying that lambda
|
||||||
|
*
|
||||||
|
* 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 env The environment to evaluate in
|
||||||
|
*/
|
||||||
|
Object listEvalLambda(
|
||||||
|
Object *lambda,
|
||||||
|
const Object *remaining,
|
||||||
|
struct Environment *env)
|
||||||
|
{
|
||||||
|
struct Environment newEnv = envForLambda(
|
||||||
|
&lambda->lambda->params,
|
||||||
|
remaining,
|
||||||
|
env
|
||||||
|
);
|
||||||
|
Object ret = eval(&lambda->lambda->body, &newEnv);
|
||||||
|
deleteEnv(&newEnv);
|
||||||
|
cleanObject(lambda);
|
||||||
|
|
||||||
|
Object *t = tail(&ret);
|
||||||
|
if(t) {
|
||||||
|
// cleanObject(&ret);
|
||||||
|
return cloneObject(*t);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates a given list, including the application of functions and lambdas
|
||||||
|
*
|
||||||
|
* Engages in several behaviors, depending on list contents:
|
||||||
|
* - () => ()
|
||||||
|
* - (1item) => eval_1item // Questionable behavior!
|
||||||
|
* - (function x y) => evaluated function(x, y)
|
||||||
|
* - (function ...) => evaluated function(...) applied to each arg
|
||||||
|
* - (function x) => functionx() partial function
|
||||||
|
* - (lambda x) => evaluated lambda(x)
|
||||||
|
* - (x y z) => (eval_x eval_y eval_z)
|
||||||
|
*
|
||||||
|
* @param obj The list to be evaluated
|
||||||
|
* @param env The environment to evaluate in
|
||||||
|
*/
|
||||||
Object evalList(const Object *obj, struct Environment *env)
|
Object evalList(const Object *obj, struct Environment *env)
|
||||||
{
|
{
|
||||||
const int evalLength = listLength(obj);
|
const int evalLength = listLength(obj);
|
||||||
|
@ -144,53 +245,24 @@ Object evalList(const Object *obj, struct Environment *env)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Evaluate the list based on the first element's type
|
||||||
Object first_eval = eval(first_form, env);
|
Object first_eval = eval(first_form, env);
|
||||||
if(first_eval.type == TYPE_FUNC) {
|
switch(first_eval.type) {
|
||||||
int length = evalLength - 1; // Not counting first_form
|
case TYPE_FUNC:
|
||||||
Object rest[length];
|
// Passes evalLength - 1, because we skip the first form
|
||||||
evalForms(rest, obj, env);
|
return listEvalFunc(obj, &first_eval, evalLength - 1, env);
|
||||||
|
|
||||||
Object func_eval = rest[0];
|
case TYPE_LAMBDA:
|
||||||
if(length == 1) {
|
return listEvalLambda(&first_eval, first_form->forward, env);
|
||||||
func_eval = first_eval.func(
|
|
||||||
func_eval, errorObject(ONLY_ONE_ARGUMENT), env);
|
|
||||||
// Consider it a partial function if only one arg
|
|
||||||
if(isError(func_eval, ONLY_ONE_ARGUMENT))
|
|
||||||
return cloneObject(*obj);
|
|
||||||
} else {
|
|
||||||
for(int i = 1; i < length; i++) {
|
|
||||||
Object toClean = func_eval;
|
|
||||||
func_eval = first_eval.func(func_eval, rest[i], env);
|
|
||||||
cleanObject(&toClean);
|
|
||||||
cleanObject(&rest[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return func_eval;
|
default: { // Return list with each element evaluated
|
||||||
|
|
||||||
} else if (first_eval.type == TYPE_LAMBDA) {
|
|
||||||
struct Environment newEnv = envForLambda(
|
|
||||||
&first_eval.lambda->params,
|
|
||||||
first_form->forward,
|
|
||||||
env
|
|
||||||
);
|
|
||||||
Object ret = eval(&first_eval.lambda->body, &newEnv);
|
|
||||||
deleteEnv(&newEnv);
|
|
||||||
cleanObject(&first_eval);
|
|
||||||
Object *t = tail(&ret);
|
|
||||||
if(t) {
|
|
||||||
// cleanObject(&ret);
|
|
||||||
return cloneObject(*t);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Object list = listObject();
|
Object list = listObject();
|
||||||
FOR_POINTER_IN_LIST(obj) {
|
FOR_POINTER_IN_LIST(obj) {
|
||||||
nf_addToList(&list, eval(POINTER, env));
|
nf_addToList(&list, eval(POINTER, env));
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object eval(const Object *obj, struct Environment *env)
|
Object eval(const Object *obj, struct Environment *env)
|
||||||
|
|
Loading…
Reference in New Issue