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);
|
||||
}
|
||||
|
||||
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
|
||||
for(int i = 0; i < length; i++) { // Evaluates all in list
|
||||
Object *ptr = itemAt(src, i + 1); // Skip the first
|
||||
destList[i] = eval(ptr, env);
|
||||
int i = 0;
|
||||
while(start) {
|
||||
destArr[i] = eval(start, 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)
|
||||
{
|
||||
const int evalLength = listLength(obj);
|
||||
|
@ -144,47 +245,17 @@ 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);
|
||||
if(first_eval.type == TYPE_FUNC) {
|
||||
int length = evalLength - 1; // Not counting first_form
|
||||
Object rest[length];
|
||||
evalForms(rest, obj, env);
|
||||
switch(first_eval.type) {
|
||||
case TYPE_FUNC:
|
||||
// Passes evalLength - 1, because we skip the first form
|
||||
return listEvalFunc(obj, &first_eval, evalLength - 1, env);
|
||||
|
||||
Object func_eval = rest[0];
|
||||
if(length == 1) {
|
||||
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]);
|
||||
}
|
||||
}
|
||||
case TYPE_LAMBDA:
|
||||
return listEvalLambda(&first_eval, first_form->forward, env);
|
||||
|
||||
return func_eval;
|
||||
|
||||
} 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 {
|
||||
default: { // Return list with each element evaluated
|
||||
Object list = listObject();
|
||||
FOR_POINTER_IN_LIST(obj) {
|
||||
nf_addToList(&list, eval(POINTER, env));
|
||||
|
@ -192,6 +263,7 @@ Object evalList(const Object *obj, struct Environment *env)
|
|||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Object eval(const Object *obj, struct Environment *env)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue