s-expressionists / Eclector

A portable Common Lisp reader that is highly customizable, can recover from errors and can return concrete syntax trees
https://s-expressionists.github.io/Eclector/
BSD 2-Clause "Simplified" License
109 stars 9 forks source link

`#',a -> ECLECTOR.READER:UNQUOTE-IN-INVALID-CONTEXT #59

Closed kpoeck closed 3 years ago

kpoeck commented 5 years ago

e.g. in sbcl

(ql:quickload :eclector)
(eclector.reader:read-from-string "`#',a")

debugger invoked on a ECLECTOR.READER:UNQUOTE-IN-INVALID-CONTEXT in thread
#<THREAD "main thread" RUNNING {10004F04C3}>:
  Unquote is illegal in the function reader macro.

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [RECOVER] Read the following form as if it were not unquoted.
  1: [ABORT  ] Exit debugger, returning to top level.

(ECLECTOR.BASE:%READER-ERROR #<SB-IMPL::STRING-INPUT-STREAM {10048DDCB3}> ECLECTOR.READER:UNQUOTE-IN-INVALID-CONTEXT :SPLICING-P NIL :CONTEXT ECLECTOR.READER::SHARPSIGN-SINGLE-QUOTE)
   source: (APPLY #'ERROR DATUM :STREAM STREAM :STREAM-POSITION STREAM-POSITION
                  (ALEXANDRIA.0.DEV:REMOVE-FROM-PLIST ARGUMENTS
                                                      :STREAM-POSITION))
kpoeck commented 5 years ago

This idiom is widely used. I claso I found until now 13 files. While I can change that in clasp, it also happens in other libraries in the quicklisp universe and it seems not possible to change all exiing libraries.

First example https://gitlab.common-lisp.net/alexandria/alexandria/blob/master/functions.lisp#L157

See also in the discussion - you were part - in #clasp

kpoeck commented 4 years ago

I believe the workaround posted by scymtym is:

(defun sharpsign-single-quote (stream char parameter)
  (declare (ignore char))
  (unless (null parameter)
    (numeric-parameter-ignored stream 'sharpsign-single-quote parameter))
  (let ((name (with-forbidden-quasiquotation ('sharpsign-single-quote :keep :keep #+(or) t)
                (read stream t nil t))))
    (if *read-suppress*
        nil
        `(function ,name))))
kpoeck commented 4 years ago

@scymtym what about making this configurable if you don't want to change that globally?

scymtym commented 4 years ago

Maybe by having a "relaxed" version of the reader macro function?

The best way forward would be deriving the correct behavior from the specification, of course.

kpoeck commented 4 years ago

How would I use the relaxed version?

scymtym commented 4 years ago

How would I use the relaxed version?

You would install the relaxed version of the reader macro function into your readtable object.

Under the current circumstances, I can't promise that I will be able to work on this anytime soon. I suggest carrying on with the workaround in https://github.com/s-expressionists/Eclector/issues/59#issuecomment-601390652 for now.

kpoeck commented 4 years ago

There is no short term pressure to do this, so whenver you have time. I think now I understood what you are saying and could even do a PR implementing what you said.

Installing in the read-table seems easy enough, that I can do in clasp by myself