First Attempt


Our builtin functions should have the same interface as builtin_op. That means the arguments should be bundled into an S-Expression which the function must use and then delete. They should return a new lval* as a result of the evaluation.

The actual functionality of taking the head or tail of an Q-Expression shouldn’t be too hard for us. We can make use of the existing functions we’ve defined for S-Expressions such as lval_take and lval_pop. But like builtin_op we also need to check that the inputs we get are valid.

Let’s take a look at head and tail first. These functions have a number of conditions under which they can’t act. First of all we must ensure they are only passed a single argument, and that that argument is a Q-Expression. Then we need to ensure that this Q-Expression isn’t empty and actually has some elements.

The head function can repeatedly pop and delete the item at index 1 until there is nothing else left in the list.

The tail function is even more simple. It can pop and delete the item at index 0, leaving the tail remaining. An initial attempt at these functions might look like this.

  1. lval* builtin_head(lval* a) {
  2. /* Check Error Conditions */
  3. if (a->count != 1) {
  4. lval_del(a);
  5. return lval_err("Function 'head' passed too many arguments!");
  6. }
  7. if (a->cell[0]->type != LVAL_QEXPR) {
  8. lval_del(a);
  9. return lval_err("Function 'head' passed incorrect types!");
  10. }
  11. if (a->cell[0]->count == 0) {
  12. lval_del(a);
  13. return lval_err("Function 'head' passed {}!");
  14. }
  15. /* Otherwise take first argument */
  16. lval* v = lval_take(a, 0);
  17. /* Delete all elements that are not head and return */
  18. while (v->count > 1) { lval_del(lval_pop(v, 1)); }
  19. return v;
  20. }
  1. lval* builtin_tail(lval* a) {
  2. /* Check Error Conditions */
  3. if (a->count != 1) {
  4. lval_del(a);
  5. return lval_err("Function 'tail' passed too many arguments!");
  6. }
  7. if (a->cell[0]->type != LVAL_QEXPR) {
  8. lval_del(a);
  9. return lval_err("Function 'tail' passed incorrect types!");
  10. }
  11. if (a->cell[0]->count == 0) {
  12. lval_del(a);
  13. return lval_err("Function 'tail' passed {}!");
  14. }
  15. /* Take first argument */
  16. lval* v = lval_take(a, 0);
  17. /* Delete first element and return */
  18. lval_del(lval_pop(v, 0));
  19. return v;
  20. }