A better IDE for uLisp?


#4

I’ll prototype a version of uLisp with a line editor and make it available for feedback. Which platform would be most useful for the prototype?


#5

I vote ARM (particularly runnable on Arduino Due): sort of EVERYBODY should be acquainted with it by now… ☺️ And it is neither too powerful, nor too weak.


#6

I suspect ARM is more broadly available than AVRs that have the memory capacity for it.


#7

It would be nice to include parenthesis matching, at least as an option. Do terminals provide codes for cursor left, cursor right, and highlight character?


#8

After a fashion. There is a standard for terminal control codes, Ecma-48, which are commonly known as ANSI codes. Those include cursor position reporting, cursor movement commands (in 2D) and various appearance changes. They’re supported by just about every Unix-like terminal, but can get really hairy if you go beyond the very basics.


#9

Thanks! I’ll try it.


#10

Ad parenthesis matching: I learned recently a trick from a C64-Lisp:

A [ can stand in the place of any (, but a ] closes ALL parens up to the previous preceding ]. This is particularly useful for “larger subclauses” in cond-statements or thelike:

(defun f (x) (cond [(>= x 0) (cond ((> x 0) 1) (t 0] (t -1)))

would be a (somewhat ridiculous) example.

While it is not exactly “paren matching”, it is a form of “checkpoint matching”, and in practice feels rather nice. I read, too, that some other Lisps in the 70s or 80s provided similar “mass closing” facilities.

Another way would be to provide a “counter” as soon as the user types “(” or “)”, i.e. printing ({1}defun g ({2}x){1} ({2}+ 1 x){1}){0} when the user types (defun g (x) (+ 1 x)), but I simply fear this will be too visually cluttered.


#11

As to backspace: I recently tried something, and it works WELL: many 70s OSes typed the last erased letter. Like if you write “lips” instead of “lisp” and correct the last two letters using two backspaces, it would look like “lipsspsp”. This looks stupid when you “read” it, but while you actually USE it, it feels just OK. Early Unix did that, too.


#12

This is where you can start running into weirdness with terminals. Backspace doesn’t always mean the same thing. Sometimes it sends, well, backspace (BS, #x08) and sometimes it sends delete (DEL, #x7F). There is also cancel character (CCH, #x94 or the two-byte sequence #x1B #x54 - ESC T).

Incidentally, the convention of using C’s '\n' character to represent a newline doesn’t work when you’re writing to a terminal. That’s just the line feed (LF, #x0A). You also need to send the carriage return (CR, #x0D) to move the cursor to the start of the line. Pressing return, incidentally, (the big key now often marked ‘enter’) inputs a carriage return. Which you can also input to the terminal using Ctrl+m.

Oh, and you can send an ASCII NUL down the terminal using Ctrl+Space. I haven’t actively tried to mess up uLisp that way, but C programs that don’t expect to see NULs have a tendency to freak out when they do. :)


#13

The Lisp Badge highlights matching parentheses as you type, which is nice:


#14

Emacs with inferior-lisp capable enough. Just add this code to your init file, edit port and board info to suit your needs, then you are good to go. When you connect to board, call elisp function (sb-open) from scratch buffer. That’s it.

(defvar port "/dev/ttyUSB0" "esp32doit-devkit-v1")

(defvar bauds 9600 "Bps")

(defun sb-open()
  (let ((serial-buffer (serial-term port bauds)))
  (with-current-buffer
      (rename-buffer "*inferior-lisp*")
    (term-line-mode)
    (setq inferior-lisp-buffer serial-buffer))))

Slime support for uLisp
#15

I’d like to set this up to try it out, but I’m a bit confused about where PlatformIO fits in, and where Emacs fits in.

What’s the application running in your video? What’s emacs@prolog-desktop?

Would it be possible to give a simple step-by-step getting started sequence?

Thanks! David


#16

PlatformIO is orthogonal to the emacs setup. You can use one without the other. The program seen on the left of the demo is emacs; the window title includes the hostname.

The main question for a step-by-step guide is going to be how familiar people are with emacs.


#17

Before I did install ulisp to my Mac with Arduino, and I did test k210 support, it worked like a charm. All graphic examples were great.

Then I installed PlatformIO because Arduino esp32 and maixduino libraries do not support arm64, and I’m using Jetson Nano Dev Kit as my daily Linux machine - which is an Arm machine like Rapsberry Pi, but 64 bit one. Strangely I like this machine more than my Mac Mini, and I usually first try to work with it. There for I needed to install. As odin said; it’s independent from Emacs. It has cli interface. Also PlatformIO has a standart file structure that I followed. I used cli to install esp32 project, then converted ulisp esp32 ino file to two independent files, one header(ulisp.h - in include directory), one cpp - main.cc - in src directory. I used cproto (apt install or brew install) for retrieving function prototypes from ulisp.ino file, then followed compiler error messages, and fixed one by one. Like I moved some functions and definitions to the top of the file.

It works mostly better than Arduino, uploads more quick, and project becomes C++ project. You can use any editor - ide. Official IDE VSCode that I hate. It also has fantastic documentation,

Installation instructions is here : https://docs.platformio.org/en/latest/core/installation.html

and Quick Start Guide : https://docs.platformio.org/en/latest/core/quickstart.html

I explained above and in my videos Emacs part, I think…

I still did not be able to install k210 Arduino libraries or platformio project to my Jetson Nano. I’ll look closely that at weekend. This is the plan.

Sorry for my English, never been good, hope I can be able to explain a bit.


#18

Having uLisp as a simple inferior-lisp is a decided improvement on the previous experience, but I wonder if it’s possible to go further by making changes on the uLisp side and a bit more code in emacs. You see, ASCII contains control characters that are no longer really used, but which can be extremely useful if correctly used.

What if we use them to define a protocol that can send clearly delimited code for execution, possibly including some header information? emacs can munge the line before it’s sent, adding the header and encapsulation. It can also do something similar in the reverse direction.

The disadvantage is that this requires more emacs lisp code, but the advantages are that it would be relatively easy to extend to the point where we have completion of symbols from the running image and other such niceties. I’d at least be interested in exploring the possibilities.


#19

Good ideas, but there is a swank port for that in here which I did not be able to setup and use, so, basically what you are asking is slime for ulisp. As I said my previous reply, I’m not a Common-Lisp Library writer, I never needed Slime. Emacs and simple inferior-lisp mode, yasnippets which is rich for elisp and common lisp and company-mode usually enough to me. I also use Dash for documentation on Mac - it has Common Lisp Docs, and Zeal for Linux - same. Last additions are Lisp extra font-lock - which its job is coloring base Common-Lisp - Elisp macros, and Rainbow Delimiters modes which can be found on Melpa. Dash and Zeal modes also on Melpa too.

With these modes and necessary configuration of init file, Emacs becomes very good Lisp IDE. If you use Semantic, you can navigate to local and other reference symbols - functions.

C and C++ on Emacs is completely different story, but it is also doable and once you accomplish setup these things, joyful.


#20

What can be easily done is symbol - function reference display with eldoc. If it is in source code, I can parse with elisp. Also we can write a parser for flycheck - flymake. Or dedicated ulisp mode. It can be done. But differences will worth the trouble, I’m not sure.


#21

Actually, if we have ulisp mode, we can use dedicated python libraries for MicroPython - CircuitPython, interfacing them and flashing devices - uploading our code to MCU’s. But save-image and load-image already do that in some extent.

It will make sense if ulisp compiles for MCU’s. Until then, I’m not sure is it worth to do that.


#22

I’ve just be trying out uLisp for a couple of days and figuring out a nice way to interact with it on my Maxiduino. In the end I settled on what I’ve done for Lisp in the past, namely Emacs with lisp-mode and inferior-lisp. Below is an outline of how to dup what I have:

For interacting with uLisp in a terminal window ‘cu’ is in the repos,
run the command in a terminal (adjusting the dev and speed if needed):

cu -l /dev/ttyUSB0 -s 9600

For emacs interaction add the following 2 lines to the ~/.emacs file:

(setq inferior-lisp-program "cu -l /dev/ttyUSB0 -s 9600")
(setq comint-process-echoes t))

In Emacs start an inferior Lisp buffer with the command:

meta-x inferior-lisp

The inferior-lisp has basic Lisp support (paren matching), and return
sends the sexpr to uLisp and prints the result in the window.

To edit uLisp files use lisp-mode by finding a file with a .lisp
extension. This will have Lisp editing support such as paren
matching, syntax highlighting, etc.

In lisp mode you can send regions or sexprs to uLisp with:

meta-x lisp-eval-region
control-x control-e

The later sends the sexpr before the cursor to the inferior Lisp.
There is a lot of other support, but those are the basics.

For editing large uLisp programs you can use tag tables, for example
to browse the assembler, assuming it is called assembler.lisp:

etags assembler.lisp

Then in Emacs edit the assembler.lisp file and use the command:

 meta-.

After loading the TAGS this will jump to the definition under the
cursor or the definition you enter.

Once you have this setup there is more support you can explore, but I think that is most of what you need.


#23

Forgot to mention 2 things in my last note:

  1. I increased the RingBuffer as described in the uLisp docs , but set it to 4k. This is enough to eval the entire assembler; and

  2. If you are running the ‘cu’ command in a terminal, you can’t also run it in an Emacs buffer, there is only one user of the device.