Greetings,
With SLIME CVS HEAD as of 2004-03-28T23:15Z, Emacs 21.3 and sbcl 0.8.9.6, I noticed that an attempt to slime-load-system portable hemlock results to
--------------------------------------------------------------- The value ", or \" is not of type LIST. [Condition of type TYPE-ERROR]
Restarts: 0: [RETRY] Retry performing #<ASDF:COMPILE-OP NIL {A203339}> on #<HEMLOCK-SYSTEM::HEMLOCK-CL-SOURCE-FILE "main" {98D2271}>. 1: [ACCEPT] Continue, treating #<ASDF:COMPILE-OP NIL {A203339}> on #<HEMLOCK-SYSTEM::HEMLOCK-CL-SOURCE-FILE "main" {98D2271}> as having been successful. 2: [ABORT] Return to SLIME toplevel. 3: [ABORT] Reduce debugger level (leaving debugger, returning to toplevel). 4: [TOPLEVEL] Restart at toplevel READ/EVAL/PRINT loop.
Backtrace: 0: (NTHCDR 2 2 ", or \")[:EXTERNAL] 1: (SWANK-BACKEND::SOURCE-PATH-SOURCE-POSITION (0 5 2 2) (NIL NIL (NIL NIL NIL (NIL NIL) (NIL (NIL "DISPLAY"))) "Invokes the editor, Hemlock. If X is supplied and is a symbol, the definition of X is put into a buffer, and that buffer is selected. If X is a pathname, the file specified by X is visited in a new buffer. If X is not supplied or Nil, the editor is entered in the same state as when last exited. When :init is supplied as t (the default), the file \" NIL ", or \" NIL " is loaded from the home directory, but the Lisp command line switch -hinit can be used to specify a different name. Any compiled version of the source is preferred when choosing the file to load. If the argument is non-nil and not t, then it should be a pathname that will be merged with the home directory." (NIL NIL (NIL "You are already in the editor, you bogon!")) (NIL ((NIL NIL) (NIL (NIL NIL (NIL NIL) (NIL NIL)))) (NIL (QUOTE NIL) (NIL (NIL NIL (NIL NIL) (NIL NIL NIL) (NIL (NIL NIL))) (NIL (QUOTE NIL) (NIL (QUOTE NIL) (NIL ((NIL NIL (NIL NIL)) (NIL ((NIL (NIL (NIL (QUOTE NIL) "Edit " (NIL NIL)))) (NIL (NIL (NIL NIL NIL) (NIL NIL))) (NIL NIL)) (NIL (NIL NIL)) (NIL (NIL (NIL NIL)) (NIL (QUOTE (NIL NIL))) (NIL) (NIL NIL) (NIL (NIL NIL))))) ((NIL (NIL NIL) (NIL NIL)) (NIL NIL NIL)) (NIL (NIL "~S is not a symbol or pathname. I can't edit it!" NIL)))) (NIL NIL) (NIL (NIL (NIL (QUOTE NIL) (NIL ((NIL (FUNCTION (NIL (NIL) (NIL NIL NIL))))) (NIL NIL) (NIL)))) (NIL NIL))))))) #<HASH-TABLE :TEST EQ :COUNT 85 {A9BC909}>) 2: (SWANK-BACKEND::SOURCE-PATH-STREAM-POSITION (20 5 2 2) #<FILE-STREAM for "file "/home/azure/projects/software/hemlock/src/main.lisp"" {AF82DA9}>) 3: (SWANK-BACKEND::SOURCE-PATH-FILE-POSITION (20 5 2 2) #P"/home/azure/projects/software/hemlock/src/main.lisp") 4: ((SWANK-BACKEND::RESOLVE-NOTE-LOCATION ((EQL NIL) PATHNAME T T T)) #<unused argument> #<unused argument> #<unused argument> #P"/home/azure/projects/software/hemlock/src/main.lisp" #<unused argument> (20 5 2 2) #<unused argument>) 5: (SWANK-BACKEND::COMPILER-NOTE-LOCATION #S(SB-C::COMPILER-ERROR-CONTEXT :ENCLOSING-SOURCE ("UNWIND-PROTECT" "FLET" "BLOCK" "MULTIPLE-VALUE-BIND" "MULTIPLE-VALUE-CALL" "BLOCK" "SB-C::%WITHIN-CLEANUP" "RETURN-FROM" "PROGN") :SOURCE (" (LET ((HEMLOCK-INTERNALS:*BEEP-FUNCTION* #'HEMLOCK-INTERNALS::HEMLOCK-BEEP) (HEMLOCK-INTERNALS::*GC-NOTIFY-BEFORE* #'HEMLOCK-INTERNALS::HEMLOCK-GC-NOTIFY-BEFORE) (HEMLOCK-INTERNALS::*GC-NOTIFY-AFTER* #'HEMLOCK-INTERNALS::HEMLOCK-GC-NOTIFY-AFTER) (*STANDARD-INPUT* HEMLOCK-INTERNALS::*ILLEGAL-READ-STREAM*) (*QUERY-IO* HEMLOCK-INTERNALS::*ILLEGAL-READ-STREAM*)) (COND ((NOT HEMLOCK-INTERNALS::*EDITOR-WINDOWED-INPUT*) (UNLESS HEMLOCK-INTERNALS::*EDITOR-HAS-BEEN-ENTERED* # # #) (CATCH 'HEMLOCK-INTERNALS::HEMLOCK-EXIT # # #)) (T (HEMLOCK-EXT:WITH-CLX-EVENT-HANDLING # # #))))") :ORIGINAL-SOURCE " (HEMLOCK-INTERNALS::SITE-WRAPPER-MACRO (UNLESS HEMLOCK-INTERNALS::*EDITOR-HAS-BEEN-ENTERED* (HEMLOCK-INTERNALS::%INIT-REDISPLAY HEMLOCK-INTERNALS::DISPLAY) (SETQ HEMLOCK-INTERNALS::*EDITOR-HAS-BEEN-ENTERED* T) (HEMLOCK-INTERFACE:INVOKE-HOOK (REVERSE HEMLOCK-INTERNALS::*AFTER-EDITOR-INITIALIZATIONS-FUNS*))) (CATCH 'HEMLOCK-INTERNALS::HEMLOCK-EXIT (CATCH 'HEMLOCK-INTERNALS::EDITOR-TOP-LEVEL-CATCHER (COND # # #)) (HEMLOCK-INTERFACE:INVOKE-HOOK HEMLOCK::ENTRY-HOOK) (UNWIND-PROTECT (LOOP #) (HEMLOCK-INTERFACE:INVOKE-HOOK HEMLOCK::EXIT-HOOK))))" :CONTEXT ((DEFUN HEMLOCK)) :FILE-NAME #P"/home/azure/projects/software/hemlock/src/main.lisp" :FILE-POSITION 9218 :ORIGINAL-SOURCE-PATH (2 2 5 20))) 6: (SWANK-BACKEND::SIGNAL-COMPILER-CONDITION #<SB-INT:SIMPLE-STYLE-WARNING {AF79091}> #S(SB-C::COMPILER-ERROR-CONTEXT :ENCLOSING-SOURCE ("UNWIND-PROTECT" "FLET" "BLOCK" "MULTIPLE-VALUE-BIND" "MULTIPLE-VALUE-CALL" "BLOCK" "SB-C::%WITHIN-CLEANUP" "RETURN-FROM" "PROGN") :SOURCE (" (LET ((HEMLOCK-INTERNALS:*BEEP-FUNCTION* #'HEMLOCK-INTERNALS::HEMLOCK-BEEP) (HEMLOCK-INTERNALS::*GC-NOTIFY-BEFORE* #'HEMLOCK-INTERNALS::HEMLOCK-GC-NOTIFY-BEFORE) (HEMLOCK-INTERNALS::*GC-NOTIFY-AFTER* #'HEMLOCK-INTERNALS::HEMLOCK-GC-NOTIFY-AFTER) (*STANDARD-INPUT* HEMLOCK-INTERNALS::*ILLEGAL-READ-STREAM*) (*QUERY-IO* HEMLOCK-INTERNALS::*ILLEGAL-READ-STREAM*)) (COND ((NOT HEMLOCK-INTERNALS::*EDITOR-WINDOWED-INPUT*) (UNLESS HEMLOCK-INTERNALS::*EDITOR-HAS-BEEN-ENTERED* # # #) (CATCH 'HEMLOCK-INTERNALS::HEMLOCK-EXIT # # #)) (T (HEMLOCK-EXT:WITH-CLX-EVENT-HANDLING # # #))))") :ORIGINAL-SOURCE " (HEMLOCK-INTERNALS::SITE-WRAPPER-MACRO (UNLESS HEMLOCK-INTERNALS::*EDITOR-HAS-BEEN-ENTERED* (HEMLOCK-INTERNALS::%INIT-REDISPLAY HEMLOCK-INTERNALS::DISPLAY) (SETQ HEMLOCK-INTERNALS::*EDITOR-HAS-BEEN-ENTERED* T) (HEMLOCK-INTERFACE:INVOKE-HOOK (REVERSE HEMLOCK-INTERNALS::*AFTER-EDITOR-INITIALIZATIONS-FUNS*))) (CATCH 'HEMLOCK-INTERNALS::HEMLOCK-EXIT (CATCH 'HEMLOCK-INTERNALS::EDITOR-TOP-LEVEL-CATCHER (COND # # #)) (HEMLOCK-INTERFACE:INVOKE-HOOK HEMLOCK::ENTRY-HOOK) (UNWIND-PROTECT (LOOP #) (HEMLOCK-INTERFACE:INVOKE-HOOK HEMLOCK::EXIT-HOOK))))" :CONTEXT ((DEFUN HEMLOCK)) :FILE-NAME #P"/home/azure/projects/software/hemlock/src/main.lisp" :FILE-POSITION 9218 :ORIGINAL-SOURCE-PATH (2 2 5 20))) 7: (SWANK-BACKEND::HANDLE-NOTIFICATION-CONDITION #<SB-INT:SIMPLE-STYLE-WARNING {AF79091}>) 8: (SIGNAL 1 #<SB-INT:SIMPLE-STYLE-WARNING {AF79091}>)[:EXTERNAL] 9: (SB-C::COMPILER-STYLE-WARNING-HANDLER 1 #<SB-INT:SIMPLE-STYLE-WARNING {AF79091}>)[:EXTERNAL] 10: (SIGNAL 1 #<SB-INT:SIMPLE-STYLE-WARNING {AF79091}>)[:EXTERNAL] 11: (WARN 5 SB-INT:SIMPLE-STYLE-WARNING)[:EXTERNAL] 12: (SB-C::NOTE-LEXICAL-BINDING 1 HEMLOCK-INTERNALS::*GC-NOTIFY-BEFORE*)[:EXTERNAL] . . . ---------------------------------------------------------------
It seems that SLIME has read the docstring as several forms even though it really is just one form. You can reproduce the problem by putting the following code to a file and then invoking slime-compile-and-load-file on it.
--------------------------------------------------------------- (defun cl-user::foo (&optional x &key (init t) (display "")) "Invokes the editor, Hemlock. If X is supplied and is a symbol, the definition of X is put into a buffer, and that buffer is selected. If X is a pathname, the file specified by X is visited in a new buffer. If X is not supplied or Nil, the editor is entered in the same state as when last exited. When :init is supplied as t (the default), the file "hemlock-init.lisp", or ".hemlock-init.lisp" is loaded from the home directory, but the Lisp command line switch -hinit can be used to specify a different name. Any compiled version of the source is preferred when choosing the file to load. If the argument is non-nil and not t, then it should be a pathname that will be merged with the home directory." (when *in-the-editor* (error "You are already in the editor, you bogon!")) (let ((*in-the-editor* t) (display (unless *editor-has-been-entered* (maybe-load-hemlock-init init) ;; Device dependent initializaiton. (init-raw-io display)))) (catch 'editor-top-level-catcher (site-wrapper-macro (unless *editor-has-been-entered* ;; Make an initial window, and set up redisplay's internal ;; data structures. (%init-redisplay display) (setq *editor-has-been-entered* t) ;; Pick up user initializations to be done after initialization. (invoke-hook (reverse *after-editor-initializations-funs*))) (catch 'hemlock-exit (catch 'editor-top-level-catcher (cond ((and x (symbolp x)) (let* ((name (nstring-capitalize (concatenate 'simple-string "Edit " (string x)))) (buffer (or (getstring name *buffer-names*) (make-buffer name))) (*print-case* :downcase)) (delete-region (buffer-region buffer)) (with-output-to-mark (*standard-output* (buffer-point buffer)) (eval `(grindef ,x)) ; hackish, I know... (terpri) (change-to-buffer buffer) (buffer-start (buffer-point buffer))))) ((or (stringp x) (pathnamep x)) (find-file-command () x)) (x (error "~S is not a symbol or pathname. I can't edit it!" x))))
(invoke-hook entry-hook) (unwind-protect (loop (catch 'editor-top-level-catcher (handler-bind ((error #'(lambda (condition) (lisp-error-error-handler condition :internal)))) (invoke-hook abort-hook) (%command-loop)))) (invoke-hook exit-hook))))))) ---------------------------------------------------------------
Hannu Koivisto wrote:
[...]
It seems that SLIME has read the docstring as several forms even though it really is just one form. You can reproduce the problem by putting the following code to a file and then invoking slime-compile-and-load-file on it.
The same problem can be seen with the following, slightly more minimal form:
(defun foo () ""foo"" (when *some-var* (do-some-thing)) (let ((some-thing (some-fn)))))
with: slime 2004-03-29 and SBCL 0.8.8.26
It appears that slime is over-eager in its quoting of backslashes in some places, but strips them in others. This may be a problem with the specialised readtable used for READ-AND-RECORD-SOURCE-MAP, although the above example works fine in CMUCL.
Hannu Koivisto azure@iki.fi writes:
It seems that SLIME has read the docstring as several forms even though it really is just one form. You can reproduce the problem by putting the following code to a file and then invoking slime-compile-and-load-file on it.
Thanks for the detailed bug report. It seems that this is caused by some bug/unspecified behavior in SBCL. See http://article.gmane.org/gmane.lisp.steel-bank.devel/2409/match=slime+broken
I committed a workaround that should fix it. Well, at least your example.
Helmut.
Helmut Eller e9626484@stud3.tuwien.ac.at writes:
Hannu Koivisto azure@iki.fi writes:
It seems that SLIME has read the docstring as several forms even though it really is just one form. You can reproduce the problem by putting the following code to a file and then invoking slime-compile-and-load-file on it.
Thanks for the detailed bug report. It seems that this is caused by some bug/unspecified behavior in SBCL. See http://article.gmane.org/gmane.lisp.steel-bank.devel/2409/match=slime+broken
I committed a workaround that should fix it. Well, at least your example.
SBCL's behaviour, in sbcl-0.8.12.3, has been altered to return NIL on (get-macro-character #\Space). I know that slime needs to keep workarounds for a while for those who are unwilling or unable to upgrade, but maybe it could be protected with a test against the compiling sbcl's behaviour? e.g.
#+sbcl (if (get-macro-character #\Space nil) (defun cmucl-style-get-macro-character ...) (defun cmucl-style-get-macro-character ...))
or something similar? It's not necessary, but it might be slightly more self-documenting.
Cheers,
Christophe
Christophe Rhodes csr21@cam.ac.uk writes:
SBCL's behaviour, in sbcl-0.8.12.3, has been altered to return NIL on (get-macro-character #\Space). I know that slime needs to keep workarounds for a while for those who are unwilling or unable to upgrade, but maybe it could be protected with a test against the compiling sbcl's behaviour? e.g.
#+sbcl (if (get-macro-character #\Space nil) (defun cmucl-style-get-macro-character ...) (defun cmucl-style-get-macro-character ...))
or something similar? It's not necessary, but it might be slightly more self-documenting.
Hmm, I can't remember the details, but I think there's also some problem with #\. Back then, I added some comments and tests; I think I was, um, not very excited about SBCL when I wrote it and didn't commit them. Do they make any sense to you?
--- swank-source-path-parser.lisp 2004-06-26 17:50:43.000000000 +0200 +++ local-swank-source-path-parser.lisp 2004-06-26 18:04:06.000000000 +0200 @@ -48,19 +48,64 @@ ;; Just copy CMUCL's implementation, to get identical behavior. The ;; SBCL implementation uses GET-RAW-CMT-ENTRY; we use ;; GET-COERCED-CMT-ENTRY, which seems to be what SET-MACRO-CHARACTER -;; expects. -- Helmut Eller +;; expects. -- Helmut Eller +;; +;; Well, actually it doesn't matter. See below. But GET-RAW-CMT-ENTRY +;; seems to be bootstrap magic and is not available at runtime. (defun cmucl-style-get-macro-character (char table) (let ((rt (or table sb-impl::*standard-readtable*))) (cond ((sb-impl::constituentp char) (values (sb-impl::get-coerced-cmt-entry char rt) t)) ((sb-impl::terminating-macrop char) (values (sb-impl::get-coerced-cmt-entry char rt) nil)) - (t nil)))) + (t + (values nil nil)))))
#+cmu (defun cmucl-style-get-macro-character (char table) (get-macro-character char table))
+;; Unlike CMUCL, SBCL stores NIL values into the character-macro-table +;; for constituent (in the CL sense) chars, and uses +;; get-coerced-cmt-entry to convert those NILs to #'read-token. In +;; CMUCL all constituents are also macro-chars. +;; +;; CMUCL and SBCL use a somewhat strange encoding for CL's Character +;; Syntax Types: +;; +;; CL Implementation +;; ---------------- -------------- +;; Constituent (constituentp x) i.e. (<= +char-attr-constituent+ x) +;; Macro Char (constituentp x) or +char-attr-terminating-macro+ +;; Single Escape +char-attr-escape+ +;; Invalid (constituentp x) with undefined-macro-char as fun +;; Multiple Escape +char-attr-multiple-escape+ +;; Whitespace +char-attr-whitespace+ +;; +;; One effect of this encoding is that invalid chars are not detected +;; inside tokens and it seems that there's no good way to distinguish +;; constituents from macro-chars. + +(defun dump-readtable (rt) + (dotimes (code char-code-limit) + (let ((char (code-char code))) + (multiple-value-bind (fn terminatingp) (get-macro-character char rt) + (format t "~S[~D]: ~12,1T~A ~A~%" + char code fn terminatingp))))) + +;; (dump-readtable *readtable*) + +(let ((rt (copy-readtable nil))) + ;; If #\space is a macro-char, it shouldn't terminate tokens. + (assert (or (not (cmucl-style-get-macro-character #\space rt)) + (nth-value 1 (cmucl-style-get-macro-character #\space rt)))) + ;; In SBCL (get-macro-character #\) returns #'read-token, t. And + ;; (set-macro-character #\ #'read-token t) confuses #'read-string, + ;; because it uses the attributes in the readtable for parsing + ;; decisions. Heck, the entire reader is written in a extremly + ;; confusing manner. No wonder that it is full of bugs. + (assert (not (cmucl-style-get-macro-character #\ rt)))) + (defun make-source-recording-readtable (readtable source-map) "Return a source position recording copy of READTABLE. The source locations are stored in SOURCE-MAP."