(archive 'newLISPer)

February 10, 2009

On my command

Filed under: newLISP — newlisper @ 19:46

I don’t use the newLISP terminal very much. Most of the time, I use an editor such as BBEdit to write and run newLISP scripts. The terminal interface to newLISP is certainly useful, for testing commands and for debugging, but I don’t find it a comfortable environment for writing scripts.

In BBEdit I can define a key combination (such as Command + Return) that evaluates the current selection and inserts the result into the text. I have all the convenience of a handy newLISP terminal in addition to the comforts of a text editor, such as code completion, syntax colouring, parenthesis-balancing, and so on.

Of course, the newLISP terminal isn’t meant to be an editor or development environment – you certainly don’t want to load one of those every time you want to run a script.

But the terminal is cool in its own way. And, because the philosophy of Lisp is that you can adapt the language to suit your purposes, it’s no surprise that the newLISP terminal is adaptable too.

Here’s an extract from a editing session using the newLISP terminal to show the sort of thing I mean:

newLISP v.10.0.0 on OSX IPv4 UTF-8, execute 'newlisp -h' for more info.

OK    (define (fred a b c)
1       (if (> a 0)
2            (println (* b c))
2            (println (/ b c))
2        )
1      )

(lambda (a b c)
 (if (> a 0)
  (println (* b c))
  (println (/ b c))))


First thing to notice are the prompts. The initial OK prompt (makes a change from the “>”) changes after the first line of typing to indicate the current nesting level. Also, the [CMD] and [/CMD] tags that you normally have to use to enclose multi-line text input aren’t necessary (and don’t currently work in this set-up!).

OK    (fred
1     1 2
1     3
1     )


Just as the if statement was spread over four lines, the (fred 1 2 3) expression sprawls over more lines than necessary.

It’s quite easy to make newLISP do this. (It’s much harder to make it robust and reliable – I’m not that sort of programmer.) You need to use two built-in newLISP functions: command-event and prompt-event.

Of the two, command-event is the more powerful. You assign a function to command-event, and that function handles all incoming text from the user. You can do what you want with that text, so it’s not too difficult to make it build up a multi-line buffer, delaying evaluation until some later stage. And by keeping track of how many parentheses have been typed, and only evaluating the buffer when the nesting level returns to 0, you can get primitive multi-line editing support.

The code to make this happen is this:

(context 'Multiline)

(set 'buffer "" 'nest 0 'indent "    ")

(define (Multiline:Multiline c)
  (dolist (i (explode c))
      (push i buffer -1)
        ((= i "(") (inc nest))
        ((= i ")") (dec nest))
        ((= i "§") (set 'buffer "" 'nest 0))))
  (push " " buffer -1)
  (when (= nest 0)
        (unless (catch (println (eval-string buffer) "\n") 'error)
                (println "! " error))
        (set 'buffer "" 'nest 0))

(define (prompt-event-function)
   (if (> nest 0) (string nest (dup " " nest) indent) (string "OK" indent)))

(context MAIN)

(command-event 'Multiline)
(prompt-event  'Multiline:prompt-event-function)

One obvious problem with this simplistic parsing is that parentheses inside strings have to balance:

OK    (set 'x "(
2      this is a string)
1     "
1     )

otherwise you would have to write code that recognises the different types of string and stops counting parentheses while inside them.

The current nesting level is output by the function that prompt-event function calls whenever a prompt is required.

You might have noticed the action in the cond clause on encountering a § character, the section sign. Well, this code was tricky to debug, because every mistake I made meant that I could no longer enter any newLISP commands… I thought an escape hatch would be a useful addition.

Improvements will be most welcome!


Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: