Builtins Lookup


We’ve now got all of our builtin functions defined. We need to make a function that can call the correct one depending on what symbol it encounters in evaluation. We can do this using strcmp and strstr.

  1. lval* builtin(lval* a, char* func) {
  2. if (strcmp("list", func) == 0) { return builtin_list(a); }
  3. if (strcmp("head", func) == 0) { return builtin_head(a); }
  4. if (strcmp("tail", func) == 0) { return builtin_tail(a); }
  5. if (strcmp("join", func) == 0) { return builtin_join(a); }
  6. if (strcmp("eval", func) == 0) { return builtin_eval(a); }
  7. if (strstr("+-/*", func)) { return builtin_op(a, func); }
  8. lval_del(a);
  9. return lval_err("Unknown Function!");
  10. }

Then we can change our evaluation line in lval_eval_sexpr to call builtin rather than builtin_op.

  1. /* Call builtin with operator */
  2. lval* result = builtin(v, f->sym);
  3. lval_del(f);
  4. return result;

Finally Q-Expressions should be fully supported in our language. Compile and run the latest version and see what you can do with the new list operators. Try putting code and symbols into our lists and evaluating them in different ways. The ability to put S-Expressions inside a list using Q-Expressions is pretty awesome. It means we can treat code like data itself. This is a flagship feature of Lisps, and something that really cannot be done in languages such as C!

  1. lispy> list 1 2 3 4
  2. {1 2 3 4}
  3. lispy> {head (list 1 2 3 4)}
  4. {head (list 1 2 3 4)}
  5. lispy> eval {head (list 1 2 3 4)}
  6. {1}
  7. lispy> tail {tail tail tail}
  8. {tail tail}
  9. lispy> eval (tail {tail tail {5 6 7}})
  10. {6 7}
  11. lispy> eval (head {(+ 1 2) (+ 10 20)})
  12. 3