The Lisp Library feature allows you to extend uLisp with your own library of function or variable definitions written in Lisp. They are stored as text in flash memory along with the uLisp code, and get loaded when you run uLisp.
As of Version 2.6 you can either load the entire Lisp Library when uLisp starts, or you can load individual function or variable definitions using require.
You can also list the functions and variables defined in the Lisp Library using list-library.
Note that this is separate from save-image and load-image, which use the processor's EEPROM or an SD card. The Lisp Library can be used even on platforms with no EEPROM or SD card, where save-image and load-image are not available. Where they are available you can still use them to save a snapshot of your workspace without affecting the Lisp Library.
Defining a Lisp Library
For example, suppose you would like your uLisp environment to include these square and cube functions:
(defun sq (x) (* x x)) (defun cub (x) (* x x x))
You can define these as a Lisp Library by editing the definition of LispLibrary at the start of your uLisp source to:
const char LispLibrary PROGMEM = "(defun sq (x) (* x x))" "(defun cub (x) (* x x x))";
Note: on the ESP8266 omit the PROGMEM.
Alternatively, you can keep your Lisp Library definitions separate from the uLisp source code by creating a separate LispLibrary.h file in the same Arduino project folder as the uLisp source file, and put the definition in that. You then need to add a reference to it in the main source file by uncommenting the line:
You can include a direct call to a function to run a program when the processor is reset.
For example, defining the following Lisp Library:
const char LispLibrary PROGMEM = "(defun b (x) (pinmode 13 t) (digitalwrite 13 x) (delay 1000) (b (not x)))" "(b t)";
will cause the program to run and blink the LED when the processor is reset.
Loading the Lisp Library
Loading the entire Lisp Library at startup
To load all the functions and variables defined in the Lisp Library at startup uncomment the #define:
Loading an individual function or variable definition
To load individual functions or variable definitions only when you need them, leave the #define commented:
// #define lisplibrary
and give a command such as:
Listing the contents of the Lisp Library:
To list the functions and variables defined in the Lisp Library give the command (list-library). For example:
> (list-library) sq cub
Creating a Lisp library
A convenient way to create a Lisp Library is as follows:
- Define the functions you want to include in the Lisp Library, and test them from the Serial Monitor.
- List the functions in the workspace with the command:
- Select the listings from the Serial Monitor window and paste them into the source window.
- Add the line:
const char LispLibrary PROGMEM =
- Add the double quotes at the start and end of each line, and a final semicolon.
- Escape double quotes in your source, where necessary, as described in the next section.
Quoting and escapes
Due to the string conventions in C each line must start and end with a double-quote, as in the above example.
Also, any double quotes in your Lisp source must be escaped with a backslash. So for example, to include the following function in the Lisp Library:
(defun error (string) (princ "Error:") (princ string) (terpri))
you would need to enter it as:
"(defun error (string) (princ \"Error:\") (princ string) (terpri))"
Backslashes in your uLisp program need to be escaped with an extra backslash, so to include the following program:
(defun wow () (print "She said \"Wow!\""))
it will need to be:
"(defun wow () (print \"She said \\\"Wow!\\\"\"))"