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.

  1. struct lval {
  2. int type;
  3. /* Basic */
  4. long num;
  5. char* err;
  6. char* sym;
  7. /* Function */
  8. lbuiltin builtin;
  9. lenv* env;
  10. lval* formals;
  11. lval* body;
  12. /* Expression */
  13. int count;
  14. lval** cell;
  15. };

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.

  1. lval* lval_lambda(lval* formals, lval* body) {
  2. lval* v = malloc(sizeof(lval));
  3. v->type = LVAL_FUN;
  4. /* Set Builtin to Null */
  5. v->builtin = NULL;
  6. /* Build new environment */
  7. v->env = lenv_new();
  8. /* Set Formals and Body */
  9. v->formals = formals;
  10. v->body = body;
  11. return v;
  12. }

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

  1. case LVAL_FUN:
  2. if (!v->builtin) {
  3. lenv_del(v->env);
  4. lval_del(v->formals);
  5. lval_del(v->body);
  6. }
  7. break;

For Copying

  1. case LVAL_FUN:
  2. if (v->builtin) {
  3. x->builtin = v->builtin;
  4. } else {
  5. x->builtin = NULL;
  6. x->env = lenv_copy(v->env);
  7. x->formals = lval_copy(v->formals);
  8. x->body = lval_copy(v->body);
  9. }
  10. break;

For Printing

  1. case LVAL_FUN:
  2. if (v->builtin) {
  3. printf("<builtin>");
  4. } else {
  5. printf("(\\ "); lval_print(v->formals);
  6. putchar(' '); lval_print(v->body); putchar(')');
  7. }
  8. break;