Define Function

We’ve managed to register our builtins as variables but we still don’t have a way for users to define their own variables.

This is actually a bit awkward. We need to get the user to pass in a symbol to name, as well as the value to assign to it. But symbols can’t appear on their own. Otherwise the evaluation function will attempt to retrieve a value for them from the environment.

The only way we can pass around symbols without them being evaluated is to put them between {} in a quoted expression. So we’re going to use this technique for our define function. It will take as input a list of symbols, and a number of other values. It will then assign each of the values to each of the symbols.

This function should act like any other builtin. It first checks for error conditions and then performs some command and returns a value. In this case it first checks that the input arguments are the correct types. It then iterates over each symbol and value and puts them into the environment. If there is an error we can return it, but on success we will return the empty expression ().

  1. lval* builtin_def(lenv* e, lval* a) {
  2. LASSERT(a, a->cell[0]->type == LVAL_QEXPR,
  3. "Function 'def' passed incorrect type!");
  4. /* First argument is symbol list */
  5. lval* syms = a->cell[0];
  6. /* Ensure all elements of first list are symbols */
  7. for (int i = 0; i < syms->count; i++) {
  8. LASSERT(a, syms->cell[i]->type == LVAL_SYM,
  9. "Function 'def' cannot define non-symbol");
  10. }
  11. /* Check correct number of symbols and values */
  12. LASSERT(a, syms->count == a->count-1,
  13. "Function 'def' cannot define incorrect "
  14. "number of values to symbols");
  15. /* Assign copies of values to symbols */
  16. for (int i = 0; i < syms->count; i++) {
  17. lenv_put(e, syms->cell[i], a->cell[i+1]);
  18. }
  19. lval_del(a);
  20. return lval_sexpr();
  21. }

We need to register this new builtin using our builtin function lenv_add_builtins.

  1. /* Variable Functions */
  2. lenv_add_builtin(e, "def", builtin_def);

Now we should be able to support user defined variables. Because our def function takes in a list of symbols we can do some cool things storing and manipulating symbols in lists before passing them to be defined. Have a play around in the prompt and ensure everything is working correctly. You should get behaviour as follows. Explore what other complex methods are possible for the definition and evaluation of variables. Once we get to defining functions we’ll really see some of the useful things that can be done with this approach.

  1. lispy> def {x} 100
  2. ()
  3. lispy> def {y} 200
  4. ()
  5. lispy> x
  6. 100
  7. lispy> y
  8. 200
  9. lispy> + x y
  10. 300
  11. lispy> def {a b} 5 6
  12. ()
  13. lispy> + a b
  14. 11
  15. lispy> def {arglist} {a b x y}
  16. ()
  17. lispy> arglist
  18. {a b x y}
  19. lispy> def arglist 1 2 3 4
  20. ()
  21. lispy> list a b x y
  22. {1 2 3 4}
  23. lispy>