3
votes

I'd like to be able to get my SBCL 1.4.5 (Linux x86_64) Emacs 'inferior-lisp-process' to evaluate a S-Expression (sexp) in some Emacs buffer that is not the 'slime' buffer - I have latest quicklisp and slime-2.20 .

I thought this was exactly the same issue as in : How to run Common Lisp code with Slime in Emacs Lisp but it is not - my issue is that when I try to run 'slime-eval' or any slime 'run in inferior-lisp-process' method ALL symbols seem to be being looked up in ONLY in the SWANK-IO-PACKAGE namespace :

 In my Emacs '*scratch*' buffer:

    (slime-eval '(symbolp '+) "CL-USER")

Produces a backtrace error:

   The function SWANK-IO-PACKAGE::SYMBOLP is undefined.
   [Condition of type UNDEFINED-FUNCTION]

   Restarts:
   0: [CONTINUE] Retry calling SWANK-IO-PACKAGE::SYMBOLP.
   1: [USE-VALUE] Call specified function.
   2: [RETURN-VALUE] Return specified values.
   3: [RETURN-NOTHING] Return zero values.
   4: [*ABORT] Return to SLIME's top level.
   5: [ABORT] abort thread (#<THREAD "worker" RUNNING {100262C8E3}>)

   Backtrace:
   0: ("undefined function" SWANK-IO-PACKAGE::+)
   1: (SB-INT:SIMPLE-EVAL-IN-LEXENV \
   (SWANK-IO-PACKAGE::SYMBOLP (QUOTE SWANK-IO-PACKAGE::+)) \
    #<NULL-LEXENV>)
   2: (EVAL (SWANK-IO-PACKAGE::SYMBOLP (QUOTE SWANK-IO-PACKAGE::+)))

It makes no difference whether I do :

    (slime-eval '(symbolp :+) "CL-USER")

OR

    (slime-eval '(symbolp '+))

I still get the same error because '+ and :+ are always looked up only in the SWANK-IO-PACKAGE namespace.

I found this by simply trying to run, for my first test:

     (slime-eval '(+ 2 2) "CL-USER")

which prints in the output buffer another backtrace

     The function SWANK-IO-PACKAGE::+ is undefined.
     [Condition of type UNDEFINED-FUNCTION]

I did try the code snippet from Question #22456086 :

    (require 'slime)
    (defun slrepl (str)
     "Eval STR as Common Lisp code."
    (unless (slime-current-connection)
      (let ((wnd (current-window-configuration)))
        (slime)
        (while (not (and (slime-current-connection)
                   (get-buffer-window (slime-output-buffer))))
        (sit-for 0.2))
    (set-window-configuration wnd)))
    (let (deactivate-mark)
    (cadr (slime-eval `(swank:eval-and-grab-output ,str)))))

So doing:

    (slrepl '(symbol-function '+))^X^E

Still results in :

    The function SWANK-IO-PACKAGE::SYMBOL-FUNCTION is undefined.
    [Condition of type UNDEFINED-FUNCTION]

Access to the default SB_INT namespace seems to be denied .

How to enable it for such cases ?

I'd like to be able to send forms to and read results from the same emacs inferior-lisp-process (sbcl) from any buffer, not just from the slime 'slime repl sbcl' buffer . Is there any way to do this?

Obviously, I can write an Emacs Lisp function to switch-to the slime repl buffer and evaluate in that buffer. Of course, all the above examples, eg. (eval '(symbolp '+)) , work fine in the slime-repl buffer. I guess there is no way around switching-to the slime-repl buffer?

This might clarify:

In 'scratch' :

     (slime-eval '(SB-INT:symbolp 'SB-INT:+) "CL-USER")^X^E

In slime output buffer:

    Invalid protocol message:
    The symbol "SYMBOLP" is not external in the SB-INT package.

            Line: 1, Column: 26, File-Position: 26

            Stream: #<SB-IMPL::STRING-INPUT-STREAM {1002A1CD63}>

    (:emacs-rex (SB-INT:symbolp (quote SB-INT:+)) "CL-USER" t 78)

So, in the slime-repl buffer, I can do:

    CL-USER> (PROGN (IN-PACKAGE "COMMON-LISP-USER") (+ 2 2))
    4
    CL-USER> (PROGN (IN-PACKAGE "SB-IMPL") (symbol-function '+))
    #<FUNCTION +>
    CL-USER> (PROGN (IN-PACKAGE "SB-IMPL") (symbol-function '+))
    #<FUNCTION +>
    SB-IMPL> (PROGN (IN-PACKAGE "SB-INT") (symbol-function '+))
    #<FUNCTION +>

But if I try to run the same 'slime-eval' function in any other buffer, eg. 'scratch' :

    (slime-eval '(PROGN (COMMON-LISP-USER:IN-PACKAGE "COMMON-LISP-USER") 
                        (symbol-function '+)) :COMMON-LISP-USER)

    Invalid protocol message:
    The symbol "IN-PACKAGE" is not external in the 
    COMMON-LISP-USER package.

    Line: 1, Column: 46, File-Position: 46

I have tried ALL the likely PACKAGE names listed above in the slime-eval with same results. The same thing happens whether I use the 'slrepl' code snippet or just plain slime-eval - no lisp standard syntax symbols are available. Do I need to load the lisp syntax table or something ?

RE: can I switch to slime repl buffer and do it ? : NO ! :

    (require 'slime)
    (let ((slbuf (get-buffer "*slime-repl sbcl*")))
     (if (eq nil slbuf)
      (error "please start slime (M-x slime)")
      (progn (set-buffer slbuf)(slime-eval '(+ 2 2) "COMMON-LISP-USER"))
     )
    )^X^E

Still results in :

    The function SWANK-IO-PACKAGE::+ is undefined.
    [Condition of type UNDEFINED-FUNCTION]

I am a rusty / returning LISP user and new to SBCL and slime . I'd really like to integrate Emacs' great Editing and File management & interacation facilitties with external CL XML & HTML generation & parsing tools. But to start, I'd just like to get to the root of this problem...

2
Looking at the source code, you might have a found a bug. Messages are always read in the swank-io-package, i.e. (emacs-rex (swank-io-package::symbolp swank-io-package::+) "CL-USER")), and then the inner form is passed down to eval-for-emacs while the package is being bound, but at this point the symbols are already interned in swank-io-package. This is different from the approach taken by C-x C-e, which roughly runs (slime-eval-print "(symbolp +)"). I may investigate a little bit further before trying to give a definitive answer (but not now...)coredump

2 Answers

2
votes

Common Lisp symbols like + and symbolp are in the COMMON-LISP package. Short name CL. These symbols are usually not exported from package CL-USER. Thus symbolp can be referenced as cl:symbolp. These symbols are accessible in package CL-USER, but not exported from there. Thus you can also reference cl:symbolp as cl-user::symbolp -> note the two colons.

CALLING IN-PACKAGE in a form does not have an effect on the form itself, since the form is already read. Though it has an effect calling reader functions or functions like find-symbol.

CL-USER 5 > (defpackage "FOO" (:use))
#<The FOO package, 0/16 internal, 0/16 external>

CL-USER 6 > (progn (in-package "FOO")
              (list 'bar (read-from-string "BAR")))
(COMMON-LISP-USER::BAR BAR)    ; we now print from package "FOO"

Using SLIME-EVAL in Emacs Lisp

Best use it with a form, that reads the expression on the Common Lisp side and does not involve the Emacs Lisp reader/printer:

ELISP> (slime-eval '(cl:eval (cl:read-from-string "(+ 1 2)")) "CL-USER")
3 (#o3, #x3, ?\C-c)
ELISP> (slime-eval '(cl:eval (cl:read-from-string "'foo")) "CL-USER")
common-lisp-user::foo

But here you see that the result is brought back into Emacs Lisp via the Emacs Lisp reader - where packages don't exist.

Thus SLIME-EVAL makes very little sense as a simple remote execution interface...

1
votes

This now works! Thanks !

    (require 'slime)
    (defun CL$ (str)
      (let ((slbuf (get-buffer "*slime-repl sbcl*")))
        (if (eq nil slbuf)
            (error "Please start slime (M-x slime).")
            (progn
             (set-buffer slbuf)
             (slime-eval str "CL")
            )
         )
      )
   )
   (CL$ '(cl:+ 2 2))
   => 4

But I don't fully understand why I have to prepend all symbols with CL or why this still does not work:

    (slime-eval '(+ 2 2) "CL")

but this does: (slime-eval '(cl:+ 2 2) "CL")

I thought the third parameter was meant to be made into the current package? So why do I have to append 'cl' to every symbol . But thanks for the help, and an otherwise great slime + sbcl .