From 0e54c303147abd52e86d3ecd79d1c1b6a4765679 Mon Sep 17 00:00:00 2001 From: David Kastrup Date: Sun, 4 Dec 2011 23:55:04 +0100 Subject: [PATCH] Documentation/extending: some improvements. --- .../extending/programming-interface.itely | 14 +-- Documentation/extending/scheme-tutorial.itely | 96 +++++++++++++------ 2 files changed, 73 insertions(+), 37 deletions(-) diff --git a/Documentation/extending/programming-interface.itely b/Documentation/extending/programming-interface.itely index c5a1111a5a..a816e564cf 100644 --- a/Documentation/extending/programming-interface.itely +++ b/Documentation/extending/programming-interface.itely @@ -207,16 +207,16 @@ functions (@pxref{Void scheme functions}) otherwise. @funindex \void Sometimes a procedure is executed in order to perform an action rather -than return a value. Some programming languages (like C and Scheme) -use functions for either concept and just discard the returned value +than return a value. Some programming languages (like C and Scheme) use +functions for either concept and just discard the returned value (usually by allowing any expression to act as statement, ignoring the result). This is clever but error-prone: most C compilers nowadays offer warnings for various non-``void'' expressions being discarded. -For many functions executing an action, the Scheme standards declare -the return value to be unspecified. Lilypond's Scheme interpreter -Guile has a unique ``unspecified'' value that it usually (such when -using @code{set!} directly on a variable) but unfortunately not -consistently returns in such cases. +For many functions executing an action, the Scheme standards declare the +return value to be unspecified. Lilypond's Scheme interpreter Guile has +a unique value @code{*unspecified*} that it usually (such when using +@code{set!} directly on a variable) but unfortunately not consistently +returns in such cases. Defining a Lilypond function with @code{define-void-function} makes sure that this special value (the only value satisfying the predicate diff --git a/Documentation/extending/scheme-tutorial.itely b/Documentation/extending/scheme-tutorial.itely index 2039948f62..ef6c435e49 100644 --- a/Documentation/extending/scheme-tutorial.itely +++ b/Documentation/extending/scheme-tutorial.itely @@ -13,7 +13,6 @@ @node Scheme tutorial @chapter Scheme tutorial -@funindex # @cindex Scheme @cindex GUILE @cindex Scheme, in-line code @@ -607,28 +606,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@tie{}@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 resulting value can be used wherever @code{SCM_TOKEN} is explicitly -accepted by the @ruser{LilyPond grammar}. +The simplest way is to use a hash mark@tie{}@code{#} before a Scheme +expression. -There is another way to execute Scheme expressions by using a +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 immediately, -checks the resulting type, and reinserts a syntactical entity of that -type (like a number, string, music expression, pitch, duration@dots{}) -into the input, making a copy of the value. This process bypasses the -grammar, and the result appears in the grammar as one of several -@code{xxx_IDENTIFIER} tokens. - -Scheme procedures can be defined in LilyPond input files: +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)) @@ -636,7 +666,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: @@ -693,6 +723,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 @@ -775,21 +814,18 @@ been written as 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 +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 -Lexer would have evaluated the Scheme code right away in order to figure -out the kind of the next token before Lilypond would have had a chance -for executing the assignment. Consequently, the Scheme definition would -have failed because @code{traLaLa} would not yet have been defined. As -a rule, using @code{#} rather than @code{$} whenever it is allowed will -cause fewer surprises. - -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 scheme functions}, or +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) -- 2.39.2