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
108 stars 9 forks source link

Minimal extension for ,. syntax #79

Open yitzchak opened 11 months ago

yitzchak commented 11 months ago

We have just added specializations of the wrap-in-quote... generics to Clasp's eclector-client. Clasp does have destructive splicing (as rare as that is) but ,. gets turned into ,@ by Eclector,

This PR is an idea for a minimal extension to enable destructive splicing without changing the signature of wrap-in-unquote-splicing and making the default for wrap-in-unquote-nsplicing be the appropriate specialization of wrap-in-unquote-splicing.

Obviously, error messages, tests, etc. could be updated.

FYI @Bike

scymtym commented 11 months ago

I'm not opposed to adding this for now.

However, in the long run, I would like to turn several groups of related functions into more extensible protocols. For example something like (make-{structure-instance,…} client …)(make-literal client :structure-instance …), (make-literal client 'float :type 'double-float :sign …), (make-literal client 'hash-table …) and (wrap-in-{function,quote,unquote,unquote-splicing} client …)(wrap-in client :unquote … :splicing t :destructive t)`.

yitzchak commented 11 months ago

I understand either way.

I do like the make-* pattern a lot more. Also, using keys as arguments like (wrap-in client :unquote … :splicing t :destructive t) prevents specialization on those values. I would suggest something like (make-form client :unquote-nsplicing form)

scymtym commented 11 months ago

I do like the make-* pattern a lot more.

Can you please clarify? Do yo prefer separate functions make-structure-instance, … over a single function make-literal or do you prefer the change make-structure-instance, … → make-literal over the change wrap-in-quote, … → wrap-in

Also, using keys as arguments like (wrap-in client :unquote … :splicing t :destructive t) prevents specialization on those values. I would suggest something like (make-form client :unquote-nsplicing form)

I haven't thought about the design at this level of detail.

In any case, one additional possibility would be something like

(defclass any-wrapping () ())
(defclass any-unquote (any-wrapping) ())
(defclass any-unquote-splicing (any-unquote) ())
(defclass unquote-nsplicing (any-unquote-splicing) ())
(defvar *unquote-nsplicing* (make-instance 'unquote-nsplicing))

with calls of the form (wrap-in client *unquote-nsplicing* form). This would allow the client to specialize to both all unquote variants (or even all wrapping variants) or specific ones.

yitzchak commented 11 months ago

I meant that I find the "wrap-in-*" naming to be a bit strange. I prefer "make-*" since it doesn't create implications as to how the thing is created. For example, SBCL creates a structure for unquote, whereas ECL, CLASP, CLISP and Mezzano all create something like (unquote bla).

I don't personally have a preference about multiple functions. I do really like your idea about using a class hierarchy for things like unquote. That's pretty clever.