wish i could enter multiline expressions by default

Started by wfatp, December 26, 2012, 08:27:09 PM

Previous topic - Next topic

wfatp

This is with regards to the interactive prompt.



Like sure if I want to enter a multiline expression for evaluation I could press enter. The I enter the forms first line. Then I enter subsequent ones. If I want to skip a line for clarity or some other reason I can't. Sure there is the simple workaround of inserting the ; comment symbol on that line and that's it. However that whole dynamic still feels cumbersome.



NewLISP absolutely kicks ass and is a pleasure to work with compared to Common LISP and Scheme. I think the interactive prompt should also reflect the ease of use and quality of the rest of the language. Like Common LISP is bloated and has a horrible syntax but when run in interactive mode it's a pleasure to work with. Whatever expression I enter be it an atom or list if it takes several lines so be it. Common LISP does that without complaining:



[georgiy@PANTHER ~]$ clisp -q

[1]> (+

1



1

)

2

[2]> "Hello

Lispers"

"Hello

Lispers"

[3]>

[georgiy@PANTHER ~]$



NewLISP on the other hand while workable with the clunky multiline awkwardness just isn't as pleasant as it could be to deal with:



[georgiy@PANTHER ~]$ newlisp

newLISP v.10.4.3 64-bit on Linux IPv4/6 UTF-8, execute 'newlisp -h' for more info.



> "Hello



ERR: string token too long : "Hello"

>

"Hello

Lispers"



"HellonLispers"

> (



ERR: missing parenthesis : "...(                                   "

>

(

+

1

1

)



2

> [georgiy@PANTHER ~]$





I'm wondering can the interactive NewLISP REPL be made to be as convenient to use as a Common LISP REPL if not by default then maybe via a command line switch? Is there a reason for the current behaviour that I don't see currently?

William James

#1
Here's a REPL that I cobbled together.  It probably has bugs, but it works pretty well for me.



(println "Quit with (exit).")

(define (input__complete? str)
  (if (or (find "^s*$" str 0)
          (find "^s*;[^n]*$" str 0))
    true
    (let (error-message ""
          scanned 0)
      (if
        (catch
          (begin
            (read-expr str)
            (setq scanned $0))
          'error-message)
        (input__complete? (slice str scanned))

        (when (find {^ERR: symbol expected}
               error-message 0)
          (replace "(?s:^ERR: |[rn].*$)" error-message "" 0)
          (throw-error error-message)
        )

        false))))


(let ((repl__line "")
      (repl__accum '())
      (repl__expression ""))
  (do-while true
    (unless
      (catch
        (begin
          (when (empty? repl__accum)
            (unless (= 'MAIN (context)) (print (context)))
            (print ": "))
          (setq repl__line (read-line))
          (push repl__line repl__accum)
          (setq repl__expression
            (join (reverse (copy repl__accum)) "n"))
          (if (input__complete? repl__expression)
            (begin
              (setq repl__accum '())
              (setq repl__expression
                (read-expr (string "(begin " repl__expression ")")))
              (println (eval repl__expression)))))
        'error-message)
      (setq repl__accum '())
      (println error-message))))


cormullion

#2
Thanks! Seems to work well.

jopython

#3
But it broke readline capabilities.

Things i take for granted , Ctrl-A, Ctrl-E, Ctrl-P stopped working.

There should be a way to retain those features.

rickyboy

#4
Readline can work with that REPL if you do the following.



1.  Put William's REPL code in a file.  Call it, say, wj-repl.lsp.



2.  Invoke the REPL from the command line like this:
$ rlwrap newlisp wj-repl.lsp
Readline commands (command line editing) should now work at the : prompt.  Worked for me.
(λx. x x) (λx. x x)

jopython

#5
Rickyboy,

Thanks for the hack.

Lutz

#6
On LINUX and BSD when compiled with GNU libreadline support a matching paren will blink on the simple or multiple newLISP command line (on same line). For this the following line:
set blink-matching-paren on
should be put into Bash .inputrc in your $HOME directory and using a future newLISP version:



http://www.newlisp.org/downloads/development/inprogress/">http://www.newlisp.org/downloads/develo ... nprogress/">http://www.newlisp.org/downloads/development/inprogress/



Ps: will not work on OSX, only on systems with newer GNU readline libs.



Ps: if you use rlwrap, this will also enable paren matching in rlwrap, regardless of the newLISP version.

steloflute

#7
I find it hard to use in the current requirement (Multiline expressions can be entered by entering an empty line first. http://www.newlisp.org/downloads/newlisp_manual.html#multiline">http://www.newlisp.org/downloads/newlis ... #multiline">http://www.newlisp.org/downloads/newlisp_manual.html#multiline).



I suggest a new method: Wait evaluation until all parentheses and quotes are matched.



Almost all modern Lisps (Racket, Clojure, etc.) use this method.

Racket:

> (displayln
3)
3
>

Also in Paren (My Lisp implementation): https://bitbucket.org/ktg/paren">https://bitbucket.org/ktg/paren

Paren:

> (prn
  3)
3
 : nil
>


You can see how it works. https://bitbucket.org/ktg/paren/src/50406c0226d1bd728620a90b0c7a2d1bedb73be8/libparen.cpp?at=master#cl-906">https://bitbucket.org/ktg/paren/src/504 ... ter#cl-906">https://bitbucket.org/ktg/paren/src/50406c0226d1bd728620a90b0c7a2d1bedb73be8/libparen.cpp?at=master#cl-906

   // read-eval-print loop
    void paren::repl() {
        string code;
        while (true) {
            if (code.length() == 0) prompt(); else prompt2();
            string line;
            if (!getline(cin, line)) { // EOF
                eval_print(code);
                return;
            }
            code += 'n' + line;
            tokenizer t(code);
            t.tokenize();
            if (t.unclosed <= 0) { // no unmatched parenthesis nor quotation
                eval_print(code);
                code = "";
            }
        }
    }

jopython

#8
William, the repl code broke with version 10.5.0.




Quit with (exit).
: (exit)
ERR: value expected in function slice : scanned
called from user defined function input__complete?
called from user defined function input__complete?

rickyboy

#9
From http://www.newlisp.org/downloads/newLISP-10.5.0-Release.html">http://www.newlisp.org/downloads/newLIS ... lease.html">http://www.newlisp.org/downloads/newLISP-10.5.0-Release.html: "read-expr now uses $count instead of $0 for the number of characters processed."



Hence, William code fix(?) = change (setq scanned $0) to (setq scanned $count).



(? == That's probably the fix, but I haven't tested it.)
(λx. x x) (λx. x x)

jopython

#10
You are spot on rickyboy!