Function Type
To store a function as an lval
we need to think exactly what it consists of.
Using the previous definition, a function should consists of three parts. First is the list of formal arguments, which we must bind before we can evaluate the function. The second part is a Q-Expression that represents the body of the function. Finally we require a location to store the values assigned to the formal arguments. Luckily we already have a structure for storing variables, an environment.
We will store our builtin functions and user defined functions under the same type LVAL_FUN
. This means we need a way internally to differentiate between them. To do this we can check if the lbuiltin
function pointer is NULL
or not. If it is not NULL
we know the lval
is some builtin function, otherwise we know it is a user function.
struct lval {
int type;
/* Basic */
long num;
char* err;
char* sym;
/* Function */
lbuiltin builtin;
lenv* env;
lval* formals;
lval* body;
/* Expression */
int count;
lval** cell;
};
We’ve renamed the lbuiltin
field from fun to builtin
. We should make sure to change this in all the places it is used in our code.
We also need to create a constructor for user defined lval
functions. Here we build a new environment for the function, and assign the formals
and body
values to those passed in.
lval* lval_lambda(lval* formals, lval* body) {
lval* v = malloc(sizeof(lval));
v->type = LVAL_FUN;
/* Set Builtin to Null */
v->builtin = NULL;
/* Build new environment */
v->env = lenv_new();
/* Set Formals and Body */
v->formals = formals;
v->body = body;
return v;
}
As with whenever we change our lval
type we need to update the functions for deletion, copying, and printing to deal with the changes. For evaluation we’ll need to look in greater depth.
For Deletion…
case LVAL_FUN:
if (!v->builtin) {
lenv_del(v->env);
lval_del(v->formals);
lval_del(v->body);
}
break;
For Copying…
case LVAL_FUN:
if (v->builtin) {
x->builtin = v->builtin;
} else {
x->builtin = NULL;
x->env = lenv_copy(v->env);
x->formals = lval_copy(v->formals);
x->body = lval_copy(v->body);
}
break;
For Printing…
case LVAL_FUN:
if (v->builtin) {
printf("<builtin>");
} else {
printf("(\\ "); lval_print(v->formals);
putchar(' '); lval_print(v->body); putchar(')');
}
break;