The enclosed updated patch: unified-main-2.patch addresses all defects I am aware of in its predecessor.

On Dec 17, 2008, at 6:10 PM, Stephen C. Gilardi wrote:

On Dec 17, 2008, at 2:27 PM, Rich Hickey wrote:

In what way is that the right thing to do?


The idea was that the sequence of top level forms may each depend on the success of the previous one. It can easily be changed to consider them all independent and I'll be happy to do that.

Top level forms are now independently evaluated. As always, only the most recent exception is saved in *e so stack trace information can be lost in the case of multiple exceptions on the same input line. I think that's ok.

I'm quite concerned about compatibility, especially with all the read-line stuff. I remember some nightmares:

I know you're talking about unexpected nightmares. I think testing by others would be wise and I welcome it. These specific ones came up in my own testing I believe the patched code handles them well.


[details]


(read-line) now works in an unsurprising, easy to explain way. All kinds of reading from the input stream during eval are now supported and they no longer interfere with prompting.

The behavior is that after reading a top level form and before evaluating it, if the input stream is pointing at a newline character, the repl will consume that newline before evaluating the form. If the top level form doesn't end the input line, any reading done by the code being eval'd begins right after the form and all subsequent characters including whitespace and newlines will be seen.

Without this special handling, (read-line) from the repl would always return "".

(Alternative special handling would skip whitespace after the top level form rather than only a single newline character. I think the latter is preferable, but it would be easy to change to the other option.)

Here are some examples with notes below:

        Clojure
1       user=> (read-line)
2       123
3       "123"
4       user=> (read-line)123
5       "123"
6       user=> (read-line) 1 2 3
7       " 1 2 3"
8       user=> [(.read *in*)(.read *in*)(.read *in*)(.read *in*)]
9       1234
10      [49 50 51 52]
11      user=> [(.read *in*)(.read *in*)(.read *in*)(.read *in*)]
12      12
13      34
14      [49 50 10 51]
15      4
16      user=> [(.read *in*)(.read *in*)(.read *in*)(.read *in*)]1
17      23456
18      [49 10 50 51]
19      456
20      user=> (.read *in*)
21      1 2 3
22      49
23      2
24      3
25      user=>

Notes:

1. The newline the user entered after ")" is eaten. The repl blocks on the next line waiting for input. A string containing the entire line of input is returned as the value of the (read-line). 4. There is no newline immediately after ")", so the rest of the line is returned by (read-line) 6. Same situation here. Note that the returned value begins with whitespace. 8. Reading 4 character codes into a vector. They are the codes for 1, 2, 3, and 4. 11. Reading 4 character codes into a vector. They are the codes for 1, 2, newline, and 3. The subsequent 4 remains on the input stream and is read/eval/printed. 16. Reading 4 character codes into a vector. The first comes from after the top level form. Then newline, 2, and 3. Then 456 is read/ eval/printed.
20. One character code is read, then 2 and 3 are read/eval/printed.


Are these changes compatible with the interactions done via, say, emacs inferior lisp mode? It's important to consider the fact that the repl can be interacted with by programs, not just people.

In those I've tested, it has worked fine. The "prompt only when there's nothing left to read/eval/print from the most recent user input" behavior is now configurable via a ":need-prompt" (function) argument to the repl. There is an opportunity to prompt after each top level read/eval/print is complete. If (need-prompt) returns true, the prompt will be printed. The default need-prompt function cooperates with LineNumberingPushbackReader to determine when we're about to wait for the user to type on a new blank line and prompts only then. If some software requires prompting for every top level read/eval/print, code that launches the associated repl can pass in #(identity true) for need-prompt.

Could someone please try it with Gorilla?

It appears nobody has tried this.

Has anyone tried this patch under Windows?

I tried it on Windows and it works fine. I learned something important here. LineNumberingPushbackReader wraps a LineNumberReader stream. The latter collapses all three supported line terminators: CR, LF, and CRLF into a single \n character. We've been running with that all along. I've taken advantage of that to simplify clojure.main and my modifications to LineNumberingPushbackReader and noted that I'm using that behavior in comments and doc strings.

There also seems to be a difference in behavior between clojure.main and Repl regarding shutdown:

http://groups.google.com/group/clojure/msg/eea16032c5b6b591

is that difference in the patch?

clojure.main/main now calls (flush) and (System/exit 0) to address the reported shutdown issues.

I guess I'm looking for recommendations about how best to test this short of a push-it-and-(briefly)-break-all-svn-users.

I'm open to any ideas along those lines. Are there volunteers to test? to review the code? to suggest a better way to fix read-line?

I think there won't be much if any breakage and I'll be quick to respond if there is. In this thread, we've given folks the opportunity to give it a try and give feedback. Unfortunately there hasn't been any. I would encourage interested folks to give this patch a try, review the code, and speak up.

I'll be happy to fix any problems anyone finds with this.

--Steve

Attachment: unified-main-2.patch
Description: Binary data


Attachment: smime.p7s
Description: S/MIME cryptographic signature

Reply via email to