On 2026-06-16 04:26, C. Stroppel wrote:
I am currently investigating whether the relationship between LilyPond
syntax and its internal structures can be extracted automatically.
The question is: In which context can a LilyPond command be applied?
>
Pause. The subject is parsing, but you're using terms that could easily
be misunderstood because there are other areas of LilyPond apart from
parsing where those terms have specific meanings.
In a discussion of parsing, the natural meaning of "context" is
approximately "the surrounding syntax." For example, a command appears
within a \bookpart, a \score, a music expression, etc. There is also
the translation-time concept of context implemented in lily/context.cc,
which you also discuss a little later in your message.
In a discussion of parsing, the natural meaning of "can ... be applied"
is approximately "is syntactically valid"; however, there is a command
called \applyContext that "applies" a function in a "context" at
translation time.
Your messages have evidence of some confusion between parsing and
translation in LilyPond. Parsing constructs books, bookparts, scores,
output definitions, music expressions, etc. Translation walks those
structures, dynamically manages a hierarchy of contexts (Score, Staff,
Voice) and issues events that are handled by the translators (engravers,
performers) in those contexts.
>
> The question is: In which context can a LilyPond command be applied?
>
In a discussion of parsing, this might be interpreted as "in which
syntactic contexts is it valid for a command to appear"?
For example,
* it is valid for \key to appear inside sequential music ('{}')
* it is valid for sequential music to appear in \score
So I can infer the chain backwards:
\key-> key-change-event-> Key_engraver-> Staff (or specialized Staff
variants)
In short:
\key -> Staff
Your initial question was about where commands "can ... be applied" but
this investigation found where they are handled.
1. Parsing \key creates a music expression describing when to issue the
key-change-event relative to other things.
2. Parsing finishes.
3. Translation for layout walks the expression created by the parser,
creates whatever context hierarchy was specified by other parts of the
expression, and issues the key-change-event.
4. Translation for performance walks the expression ...
What you have traced is that a *built-in* *engraver* that *handles*
key-change events is *by default* instantiated in Staff context. There
are degrees of freedom in this.
* Users can define their own translators.
* Engravers and performers that handle the same event can reside in
different contexts. For example, Time_signature_engraver and
Time_signature_performer.
* Users can add translators to non-default contexts with \consists.
Important note: If a parser is parsing a file that will be distributed
to other users, the parser does not see the recipients' modifications.
I assume that VaticanaStaff, MensuralStaff, etc. are specialized Staff
contexts with different default settings.
They are defined in ly/engraver-init.ly.
The only thing that is not completely clear to me is why \key also works
in a Voice context. My current assumption is that this is related to the
context hierarchy: the Music event is not necessarily handled only by
the immediate context, but can be consumed by suitable translators in
parent contexts.
Have you seen
https://lilypond.org/doc/v2.27/Documentation/contributor/overview-of-lilypond-architecture
? It discusses the distinctions I've been trying to help you see here.
(Note, however, that iteration and translation are intertwined; I
wouldn't call them separate stages.)
My idea is that the steps I am currently doing manually could probably
be automated with existing introspection facilities.
After all that effort, what would your parser do with this syntactically
valid lilypond file?
\version "2.26.0"
defaultKey = \key a \major
Returning to the top, you seem to be including a lot more in the scope
of "parsing" than LilyPond's parser does. Echoing David,
> I think you need to work more with LilyPond: contexts,
> engravers, grobs and so on are backend mechanisms. By
> the time they come into play, the parser is finished.
--
Dan