emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Reader macros


From: David Kastrup
Subject: Re: Reader macros
Date: Fri, 23 Jan 2015 13:27:52 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/25.0.50 (gnu/linux)

Daniel Colascione <address@hidden> writes:

> On 01/23/2015 01:33 AM, David Kastrup wrote:
>> Daniel Colascione <address@hidden> writes:
>> 
>>> On 01/22/2015 03:36 PM, Stefan Monnier wrote:
>>>> Maybe we could introduce a more limited form of reader macros.
>>>> E.g. allow #<letter><sexp> and make the reader return
>>>>
>>>>    (funcall (cdr (assq <letter> reader-macro-alist)) <sexp>)
>>>
>>>
>>> That's an excellent idea.
>> 
>> Doesn't work well where <letter> is an unmatched delimiter like ( or [.
>
> So? The point isn't to support every conceivable syntax, but to cover
> the most common use cases without fundamentally changing the lexical
> structure of the source. Requiring #f() instead of #() is no great crime.
>
>> Also would not work with #r"xxx" raw strings.
>
> Arguably a feature, not a bug.
>
>> I think it makes more
>> sense (like Guile does it) to make this kind of funcall not with <sexp>
>> but rather with <port>.  If indeed a sexp is wanted, calling `read' is
>> trivial.
>
> Sure, it's possible to do it that way, but then reader macros can break
> the lexical structure of the program.

Shrug.  That's LilyPond's way of embedding LilyPond code in Scheme.

Here is one arbitrary example: One escapes from LilyPond to Scheme
writing #<sexp> or $<sexp> (with slightly different semantics) and from
Scheme to LilyPond writing #{ code... #}, with arbitrary nesting and
full lexical closure:

incipit =
#(define-music-function (parser location incipit-music) (ly:music?)
  #{
    \once \override Staff.InstrumentName.stencil =
      #(lambda (grob)
        (let* ((instrument-name (ly:grob-property grob 'long-text))
               (align-x (ly:grob-property grob 'self-alignment-X 0))
               (align-y (ly:grob-property grob 'self-alignment-Y 0)))
        (set! (ly:grob-property grob 'long-text)
          #{ \markup {
            \score
            {
              \new MensuralStaff \with {
                \override InstrumentName.self-alignment-X = #align-x
                \override InstrumentName.self-alignment-Y = #align-y
                instrumentName = #instrument-name
              }
              {
                $incipit-music
              }
              \layout {
                $(ly:grob-layout grob)
                indent-incipit-default = 15\mm
                line-width = #(primitive-eval
                  '(or (false-if-exception indent)
                    indent-incipit-default))
                indent = #(primitive-eval
                           '(or (false-if-exception (- line-width 
incipit-width))
                            (* 0.5 line-width)))
                ragged-right = ##f
                ragged-last = ##f
                system-count = 1
                \context {
                  \Score
                  \remove "Default_bar_line_engraver"
                }
              }
            }
            }
          #})
          (set! (ly:grob-property grob 'self-alignment-Y) #f)
          (set! (ly:grob-property grob 'self-alignment-X) RIGHT)
          (system-start-text::print grob)))
  #}
)

As you can see, it is one merry back-and-forth.  The implementation of
the LilyPond-within-Scheme embedding indeed uses a GUILE reader macro by
registering #{ and, upon being called, reading the string delimited by
#} from the port for later interpretation and registering each #<sexp>
or $<sexp> combination for potential lexical closure.

Now GUILE is touted more as a language-building tool than Elisp, of
course.  However, being able to adapt the Lisp reader to the task of
reading Scheme and even LilyPond/Scheme would make several parsing tasks
for LilyPond-mode easier, not just #{ ... #}.  For example, there is
#:xxx for keywords, and #(a b c d) for vectors and #\x for characters.
Being able to nudge the Elisp reader into dealing with this kind of sexp
would make for more robust detection of LilyPond vs Scheme code.

> The only legitimate use case Stefan's idea doesn't cover is

So reading Scheme or Scheme/LilyPond code is illegitimate?  Who gets to
decide this?

> raw strings (and maybe here docs), for which I would be willing to add
> a special case to the reader if we decided we wanted them.

-- 
David Kastrup



reply via email to

[Prev in Thread] Current Thread [Next in Thread]