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.
lval* builtin_head(lval* a) {
/* Check Error Conditions */
if (a->count != 1) {
lval_del(a);
return lval_err("Function 'head' passed too many arguments!");
}
if (a->cell[0]->type != LVAL_QEXPR) {
lval_del(a);
return lval_err("Function 'head' passed incorrect types!");
}
if (a->cell[0]->count == 0) {
lval_del(a);
return lval_err("Function 'head' passed {}!");
}
/* Otherwise take first argument */
lval* v = lval_take(a, 0);
/* Delete all elements that are not head and return */
while (v->count > 1) { lval_del(lval_pop(v, 1)); }
return v;
}
lval* builtin_tail(lval* a) {
/* Check Error Conditions */
if (a->count != 1) {
lval_del(a);
return lval_err("Function 'tail' passed too many arguments!");
}
if (a->cell[0]->type != LVAL_QEXPR) {
lval_del(a);
return lval_err("Function 'tail' passed incorrect types!");
}
if (a->cell[0]->count == 0) {
lval_del(a);
return lval_err("Function 'tail' passed {}!");
}
/* Take first argument */
lval* v = lval_take(a, 0);
/* Delete first element and return */
lval_del(lval_pop(v, 0));
return v;
}