What new features would you like to see in a future version of uLisp? Here are some things I have been thinking about, in no particular order. For each item I’ve rated them according to how hard I think they will be to implement:
* is easy, ** is moderate, and *** is hard.
Let me know how useful you think these would be, or suggest any additional features I haven’t included on the list:
Simple one-dimensional arrays, which would use make-array to create an array; for example:
(defvar data (make-array 1000 :initial-element 0))
You could then read array entries with aref, and assign values to array elements using aref with the in-place functions such as setf, incf, and decf to change array elements. This would provide a more efficient alternative to using nth with a list, and would be useful for data logging, or mathematical operations.
It may be possible to extend the implementation to include two-dimensional arrays.
Hash tables ***
Hash tables, using make-hashtable to create a hash table, gethash to read entries, and gethash with the in-place functions such as setf, incf, and decf to add or change entries. This would be useful for processing strings, and sparse arrays.
A simplified version of Common Lisp’s format command, for printing or outputting information in a formatted way.
Currently if you want to print out a series of values you have to do something like:
(princ "Time = ") (princ time) (princ ", Value = ") (princ value) (terpri)
The format function would let you write:
(format t "Time = ~a, Value = ~a ~%" time value)
It would probably be feasible to include a field-width parameter, but not to offer a range of floating-point format options.
Stack overflow ***
Better trapping of a stack overflow, with a uLisp error, rather than possibly causing uLisp to hang. I’ve already managed to implement this in the ARM version of uLisp, but it would require a bit more work to add it to the other versions; it may not even be possible.
For example, you can trigger this condition intentionally by doing:
(defun fill () (fill) nil) (fill)
The nil stops uLisp optimising the recursive call to (fill) into a simple loop. The latest ARM version of uLisp will stop with a Stack overflow error, from which you can recover and continue using uLisp, but other versions will just hang up, requiring a reset
Allow errors to give a backtrace, for better debugging, so you can see where the error occurred and how the program got there. Also, it would allow you to examine variables, etc.
Add unwind-protect, so that program execution can continue after an error, without returning to the REPL. This was suggested by Philipp Marek, but would be difficult to implement.
Outputting to a string *
Add the ability to write output to a string, rather than to a stream, using with-output-to-string.
Some time ago I tested an interrupt facility with uLisp, to allow you to detect events independently of the execution of your Lisp program. It would avoid the need to sit in a loop repeatedly testing the input from a pushbutton, for example.
It would use an attach-interrupt function, which would allow you to assign a Lisp function to be called when the interrupt occurs. For example, to count the number of interrupts on INT0 on an AVR processor:
(defvar c 0) (defun inc (n) (incf c n)) (attach-interrupt 0 inc)
The function you supply to attach-interrupt would take one parameter, the number of interrupts that have occurred since the function was last called.
A time function *
It’s currently possible to test how long a benchmark takes to run by using the for-millis form. For example:
(for-millis () (print (tak 18 12 6)))
A time function would have two advantages; it could print execution times longer than 32767 milliseconds on 8/16-bit versions of uLisp, and it could include information about the number of garbage collections that have occurred.
The ARM and RISC-V versions of uLisp allow you to generate machine-code functions, and execute them like Lisp functions. An assembler written in Lisp lets you write these machine-code functions using assembler mnemonics.
It should be relatively easy to add this facility to the ESP and STM32 versions of uLisp. It may be possible to add it to the AVR and MSP430 versions of uLisp.
Look forward to your feedback!