X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=Documentation%2Fextending%2Fscheme-tutorial.itely;h=24865121692f8eb705d2d670cebbb71897b72823;hb=42984d05239a3c3be1ea859ba5214ce140448afc;hp=c9be04076bff5fa67be6cc47498e8b04baa4f095;hpb=fe2cae0fa47ec4ec0184e6b3d15572fbcba881cf;p=lilypond.git diff --git a/Documentation/extending/scheme-tutorial.itely b/Documentation/extending/scheme-tutorial.itely index c9be04076b..2486512169 100644 --- a/Documentation/extending/scheme-tutorial.itely +++ b/Documentation/extending/scheme-tutorial.itely @@ -8,12 +8,11 @@ Guide, node Updating translation committishes.. @end ignore -@c \version "2.12.0" +@c \version "2.15.20" @node Scheme tutorial @chapter Scheme tutorial -@funindex # @cindex Scheme @cindex GUILE @cindex Scheme, in-line code @@ -73,7 +72,14 @@ see @rlearning{Other sources of information}. Alternatively, Windows users may simply choose @q{Run} from the Start menu and enter @q{guile}. -Once the guile sandbox is running, you will receive a guile prompt: +However, a hands-on Scheme sandbox with all of Lilypond loaded is +available with this command line: +@example +lilypond scheme-sandbox +@end example + +@noindent +Once the sandbox is running, you will receive a guile prompt: @lisp guile> @@ -148,7 +154,7 @@ and False is @code{#f}. @item Numbers Numbers are entered in the standard fashion, -@code{1} is the (integer) number one, while @code{-1.5} is a +@code{1} is the (integer) number one, while @w{@code{-1.5}} is a floating point number (a non-integer number). @item Strings @@ -607,17 +613,59 @@ guile> (cond ((< a b) "a is less than b") @node LilyPond Scheme syntax @subsection LilyPond Scheme syntax +@funindex $ +@funindex # The Guile interpreter is part of LilyPond, which means that -Scheme can be included in LilyPond input files. The hash mark @code{#} -is used to tell the LilyPond parser that the next value is a Scheme -value. +Scheme can be included in LilyPond input files. There are several +methods for including Scheme in LilyPond. -Once the parser sees a hash mark, input is passed to the Guile -interpreter to evaluate the Scheme expression. The interpreter continues -to process input until the end of a Scheme expression is seen. +The simplest way is to use a hash mark@tie{}@code{#} before a Scheme +expression. -Scheme procedures can be defined in LilyPond input files: +Now LilyPond's input is structured into tokens and expressions, much +like human language is structured into words and sentences. LilyPond +has a lexer that recognizes tokens (literal numbers, strings, Scheme +elements, pitches and so on), and a parser that understands the syntax, +@ruser{LilyPond grammar}. Once it knows that a particular syntax rule +applies, it executes actions associated with it. + +The hash mark@tie{}@code{#} method of embedding Scheme is a natural fit +for this system. Once the lexer sees a hash mark, it calls the Scheme +reader to read one full Scheme expression (this can be an identifier, an +expression enclosed in parentheses, or several other things). After the +Scheme expression is read, it is stored away as the value for an +@code{SCM_TOKEN} in the grammar. Once the parser knows how to make use +of this token, it calls Guile for evaluating the Scheme expression. +Since the parser usually requires a bit of lookahead from the lexer to +make its parsing decisions, this separation of reading and evaluation +between lexer and parser is exactly what is needed to keep the execution +of LilyPond and Scheme expressions in sync. For this reason, you should +use the hash mark@tie{}@code{#} for calling Scheme whenever this is +feasible. + +Another way to call the Scheme interpreter from LilyPond is the use of +dollar@tie{}@code{$} instead of a hash mark for introducing Scheme +expressions. In this case, Lilypond evaluates the code right after the +lexer has read it. It checks the resulting type of the Scheme +expression and then picks a token type (one of several +@code{xxx_IDENTIFIER} in the syntax) for it. It creates a @emph{copy} +of the value and uses that for the value of the token. If the value of +the expression is void (Guile's value of @code{*unspecified*}), nothing +at all is passed to the parser. + +This is, in fact, exactly the same mechanism that Lilypond employs when +you call any variable or music function by name, as @code{\name}, with +the only difference that its end is determined by the Lilypond lexer +without consulting the Scheme reader, and thus only variable names +consistent with the current Lilypond mode are accepted. + +The immediate action of @code{$} can lead to surprises, @ref{Input +variables and Scheme}. Using @code{#} where the parser supports it is +usually preferable. + +Now let's take a look at some actual Scheme code. Scheme procedures can +be defined in LilyPond input files: @example #(define (average a b c) (/ (+ a b c) 3)) @@ -625,7 +673,7 @@ Scheme procedures can be defined in LilyPond input files: Note that LilyPond comments (@code{%} and @code{%@{ %@}}) cannot be used within Scheme code, even in a LilyPond input file, because -the Guile interpreter, not the LilyPond parser, is interpreting +the Guile interpreter, not the LilyPond lexer, is reading the Scheme expression. Comments in Guile Scheme are entered as follows: @@ -640,7 +688,7 @@ as follows: @end example For the rest of this section, we will assume that the data is entered -in a music file, so we add @code{#}s at the beginning of each Scheme +in a music file, so we add@tie{}@code{#}s at the beginning of each Scheme expression. All of the top-level Scheme expressions in a LilyPond input file can @@ -682,6 +730,15 @@ twentyFour = #(* 2 twelve) which would result in the number 24 being stored in the LilyPond (and Scheme) variable @code{twentyFour}. +The usual way to refer to Lilypond variables, @ref{LilyPond Scheme +syntax}, is to call them using a backslash, i.e., @code{\twentyFour}. +Since this creates a copy of the value for most of LilyPond's internal +types, in particular music expressions, music functions don't usually +create copies of material they change. For this reason, music +expressions given with @code{#} should usually not contain material that +is not either created from scratch or explicitly copied rather than +directly referenced. + @node Input variables and Scheme @subsection Input variables and Scheme @@ -733,9 +790,6 @@ imported in a @code{\score} block by means of a second variable @lilypond[verbatim] traLaLa = { c'4 d'4 } -%% dummy action to deal with parser lookahead -#(display "this needs to be here, sorry!") - #(define newLa (map ly:music-deep-copy (list traLaLa traLaLa))) #(define twice @@ -746,27 +800,39 @@ traLaLa = { c'4 d'4 } @c Due to parser lookahead -In this example, the assignment happens after the parser has -verified that nothing interesting happens after -@code{traLaLa = @{ ... @}}. Without the dummy statement in the -above example, the @code{newLa} definition is executed before -@code{traLaLa} is defined, leading to a syntax error. +This is actually a rather interesting example. The assignment will only +take place after the parser has ascertained that nothing akin to +@code{\addlyrics} follows, so it needs to check what comes next. It +reads @code{#} and the following Scheme expression @emph{without} +evaluating it, so it can go ahead with the assignment, and +@emph{afterwards} execute the Scheme code without problem. The above example shows how to @q{export} music expressions from the input to the Scheme interpreter. The opposite is also possible. By -wrapping a Scheme value in the function @code{ly:export}, a Scheme +placing it after @code{$}, a Scheme value is interpreted as if it were entered in LilyPond syntax. Instead of defining @code{\twice}, the example above could also have been written as @example ... -@{ #(ly:export (make-sequential-music (list newLa))) @} +@{ $(make-sequential-music (list newLa)) @} @end example -Scheme code is evaluated as soon as the parser encounters it. To -define some Scheme code in a macro (to be called later), use -@ref{Void functions}, or +You can use @code{$} with a Scheme expression anywhere you could use +@code{\@var{name}} after having assigned the Scheme expression to a +variable @var{name}. This replacement happens in the @q{lexer}, so +Lilypond is not even aware of the difference. + +One drawback, however, is that of timing. If we had been using @code{$} +instead of @code{#} for defining @code{newLa} in the above example, the +following Scheme definition would have failed because @code{traLaLa} +would not yet have been defined. For an explanation of this timing +problem, @ref{LilyPond Scheme syntax}. + +In any case, evaluation of Scheme code happens in the parser at latest. +If you need it to be executed at a later point of time, @ref{Void scheme +functions}, or store it in a macro: @example #(define (nopc) @@ -780,7 +846,7 @@ define some Scheme code in a macro (to be called later), use @knownissues Mixing Scheme and LilyPond variables is not possible with the -@code{--safe} option. +@option{--safe} option. @node Object properties @@ -987,7 +1053,18 @@ a file. lilypond file.ly >display.txt @end example -With a bit of reformatting, the above information is easier to read, +With a combined bit of Lilypond and Scheme magick, you can actually +let Lilypond direct just this output to a file of its own: + +@example +@{ + $(with-output-to-file "display.txt" + (lambda () #@{ \displayMusic @{ c'4\f @} #@})) +@} +@end example + + +A bit of reformatting makes the above information easier to read: @example (make-music 'SequentialMusic @@ -1006,6 +1083,10 @@ containing a @code{NoteEvent} object (storing the duration and pitch properties) and any extra information (in this case, an @code{AbsoluteDynamicEvent} with a @code{"f"} text property. +@funindex{\void} +@code{\displayMusic} returns the music it displays, so it will get +interpreted as well as displayed. To avoid interpretation, write +@code{\void} before @code{\displayMusic}. @node Music properties @subsection Music properties @@ -1353,7 +1434,7 @@ TODO Find a simple example @lilypond[quote,verbatim,ragged-right] padText = #(define-music-function (parser location padding) (number?) #{ - \once \override TextScript #'padding = #$padding + \once \override TextScript #'padding = #padding #}) \relative c''' { @@ -1378,7 +1459,7 @@ tempoPadded = #(define-music-function (parser location padding tempotext) (number? string?) #{ \once \override Score.MetronomeMark #'padding = $padding - \tempo \markup { \bold $tempotext } + \tempo \markup { \bold #tempotext } #}) \relative c'' {