]> git.donarmstrong.com Git - lilypond.git/commitdiff
Merge branch 'issue4096' into HEAD
authorDavid Kastrup <dak@gnu.org>
Sun, 14 Sep 2014 05:46:29 +0000 (07:46 +0200)
committerDavid Kastrup <dak@gnu.org>
Sun, 14 Sep 2014 05:46:29 +0000 (07:46 +0200)
input/regression/addlyrics-existing-context.ly [new file with mode: 0644]
lily/parser.yy
scm/ly-syntax-constructors.scm

diff --git a/input/regression/addlyrics-existing-context.ly b/input/regression/addlyrics-existing-context.ly
new file mode 100644 (file)
index 0000000..94e9ab8
--- /dev/null
@@ -0,0 +1,25 @@
+\version "2.19.14"
+
+\header {
+  texidoc = "
+@code{\\addlyrics} should be able to attach itself to named and unnamed @code{Voice}
+constructs.  For all tests where this succeeds, the noteheads will be red."
+}
+
+\layout { ragged-right = ##t }
+
+\new Staff \new Voice \with { \override NoteHead.color = #red }
+{ \tempo \markup \typewriter "\\new Staff \\new Voice" c'1 }
+\addlyrics { Oh! }
+
+\new Voice \with { \override NoteHead.color = #red }
+{ \tempo \markup \typewriter "\\new Voice" c'1 }
+\addlyrics { Oh! }
+
+\new Staff \new Voice = "named" \with { \override NoteHead.color = #red }
+{ \tempo \markup \typewriter "\\new Staff \\new Voice = \"named\"" c'1 }
+\addlyrics { Oh! }
+
+\new Voice = "named" \with { \override NoteHead.color = #red }
+{ \tempo \markup \typewriter "\\new Voice = \"named\"" c'1 }
+\addlyrics { Oh! }
index eac4dad0f3aa397367160536a3df04907fcc1266..645b35b6ee04147cbd31a545638ea5bcd8c93b9a 100644 (file)
@@ -1222,7 +1222,11 @@ braced_music_list:
 
 music: music_assign
        | lyric_element_music
-       | pitch_or_music
+       | pitch_as_music
+       ;
+
+pitch_as_music:
+       pitch_or_music
        {
                $$ = make_music_from_simple (parser, @1, $1);
                 if (!Music::unsmob ($$))
@@ -1404,9 +1408,88 @@ context_mod_list:
         }
         ;
 
-composite_music:
-       complex_music
+context_prefix:
+       CONTEXT symbol optional_id optional_context_mod {
+                Context_mod *ctxmod = Context_mod::unsmob ($4);
+                SCM mods = SCM_EOL;
+                if (ctxmod)
+                        mods = ctxmod->get_mods ();
+               $$ = START_MAKE_SYNTAX ("context-specification", $2, $3, mods, SCM_BOOL_F);
+       }
+       | NEWCONTEXT symbol optional_id optional_context_mod {
+                Context_mod *ctxmod = Context_mod::unsmob ($4);
+                SCM mods = SCM_EOL;
+                if (ctxmod)
+                        mods = ctxmod->get_mods ();
+               $$ = START_MAKE_SYNTAX ("context-specification", $2, $3, mods, SCM_BOOL_T);
+       }
+       ;
+
+new_lyrics:
+       ADDLYRICS lyric_mode_music {
+               $$ = scm_list_1 ($2);
+       }
+       | new_lyrics ADDLYRICS lyric_mode_music {
+               $$ = scm_cons ($3, $1);
+       }
+       ;
+
+/* basic_music is basically the same as composite_music but with
+ * context-prefixed music and lyricized music explicitly removed.  The
+ * reason is that in a sequence
+ *
+ *   \new Staff \new Voice { ... } \addlyrics { ... } \addlyrics { ... }
+ *
+ * we need to group both \addlyrics together (as they go with the same
+ * voice) but then combine them with \new Voice { ... }, meaning that
+ * combining \new Voice { ... } needs higher priority than
+ * { ... } \addlyrics, and *not* have \new Staff \new Voice { ... }
+ * combine before combining \new Voice { ... } \addlyrics: only one
+ * layer of context-prefixed music should assemble before \addlyrics
+ * is integrated.  Total mess, and we sort this mess out with explicit
+ * rules preferring a single context-prefix.
+ */
+
+basic_music:
+       music_function_call
+       | repeated_music
        | music_bare
+       | LYRICSTO simple_string lyric_mode_music {
+               $$ = MAKE_SYNTAX ("lyric-combine", @$, $2, $3);
+       }
+       ;
+
+contextable_music:
+       basic_music
+       | pitch_as_music
+       | event_chord
+       ;
+
+contexted_basic_music:
+       context_prefix contextable_music new_lyrics
+       {
+               Input i;
+               i.set_location (@1, @2);
+               $$ = FINISH_MAKE_SYNTAX ($1, i, $2);
+               $$ = MAKE_SYNTAX ("add-lyrics", @$, $$, scm_reverse_x ($3, SCM_EOL));
+       } %prec COMPOSITE
+       | context_prefix contextable_music
+       {
+               $$ = FINISH_MAKE_SYNTAX ($1, @$, $2);
+       } %prec COMPOSITE
+       | context_prefix contexted_basic_music
+       {
+               $$ = FINISH_MAKE_SYNTAX ($1, @$, $2);
+       }
+       ;
+
+composite_music:
+       basic_music %prec COMPOSITE
+       | contexted_basic_music
+       | basic_music new_lyrics
+       {
+               $$ = MAKE_SYNTAX ("add-lyrics", @$, $1, scm_reverse_x ($2, SCM_EOL));
+       } %prec COMPOSITE
        ;
 
 music_bare:
@@ -2138,33 +2221,6 @@ lyric_mode_music:
        | MUSIC_IDENTIFIER
        ;
 
-complex_music:
-       music_function_call
-       | repeated_music                { $$ = $1; }
-       | re_rhythmed_music     { $$ = $1; }
-       | complex_music_prefix music
-       {
-               $$ = FINISH_MAKE_SYNTAX ($1, @$, $2);
-       }
-       ;
-
-complex_music_prefix:
-       CONTEXT symbol optional_id optional_context_mod {
-                Context_mod *ctxmod = Context_mod::unsmob ($4);
-                SCM mods = SCM_EOL;
-                if (ctxmod)
-                        mods = ctxmod->get_mods ();
-               $$ = START_MAKE_SYNTAX ("context-specification", $2, $3, mods, SCM_BOOL_F);
-       }
-       | NEWCONTEXT symbol optional_id optional_context_mod {
-                Context_mod *ctxmod = Context_mod::unsmob ($4);
-                SCM mods = SCM_EOL;
-                if (ctxmod)
-                        mods = ctxmod->get_mods ();
-               $$ = START_MAKE_SYNTAX ("context-specification", $2, $3, mods, SCM_BOOL_T);
-       }
-       ;
-
 mode_changed_music:
        mode_changing_head grouped_music_list {
                if ($1 == ly_symbol2scm ("chords"))
@@ -2249,24 +2305,6 @@ mode_changing_head_with_context:
        }
        ;
 
-new_lyrics:
-       ADDLYRICS lyric_mode_music {
-               $$ = scm_list_1 ($2);
-       }
-       | new_lyrics ADDLYRICS lyric_mode_music {
-               $$ = scm_cons ($3, $1);
-       }
-       ;
-
-re_rhythmed_music:
-       composite_music new_lyrics {
-               $$ = MAKE_SYNTAX ("add-lyrics", @$, $1, scm_reverse_x ($2, SCM_EOL));
-       } %prec COMPOSITE
-       | LYRICSTO simple_string lyric_mode_music {
-               $$ = MAKE_SYNTAX ("lyric-combine", @$, $2, $3);
-       }
-       ;
-
 context_change:
        CHANGE symbol '=' simple_string  {
                $$ = MAKE_SYNTAX ("context-change", @$, $2, $4);
index 73e871686e3ee079f488ec646b0d550d870206ba..68bfb1f9f163361ada22655459bd303ea0f96395 100644 (file)
@@ -207,15 +207,21 @@ into a @code{MultiMeasureTextEvent}."
                 'context-type ctx
                 'origin location)))
 
-;; TODO: It seems that this function rarely returns anything useful.
-(define (get-first-context-id type mus)
-  "Find the name of a ContextSpeccedMusic with given type"
+(define (get-first-context-id! type mus)
+  "Find the name of a ContextSpeccedMusic with given type, possibly naming it"
   (let ((id (ly:music-property mus 'context-id)))
-    (if (and (eq? (ly:music-property mus 'type) 'ContextSpeccedMusic)
-             (eq? (ly:music-property mus 'context-type) type)
-             (string? id)
-             (not (string-null? id)))
-        id
+    (if (and (eq? (ly:music-property mus 'name) 'ContextSpeccedMusic)
+             (eq? (ly:music-property mus 'context-type) type))
+        (if (and (string? id)
+                 (not (string-null? id)))
+            id
+            ;; We may reliably give a new context a unique name, but
+            ;; not an existing one
+            (if (ly:music-property mus 'create-new #f)
+                (let ((id (get-next-unique-voice-name)))
+                  (set! (ly:music-property mus 'context-id) id)
+                  id)
+                '()))
         '())))
 
 (define unique-counter -1)
@@ -241,17 +247,26 @@ into a @code{MultiMeasureTextEvent}."
   (lyric-combine-music voice music location))
 
 (define-ly-syntax (add-lyrics parser location music addlyrics-list)
-  (let* ((existing-voice-name (get-first-context-id 'Voice music))
+  (let* ((existing-voice-name (get-first-context-id! 'Voice music))
          (voice-name (if (string? existing-voice-name)
                          existing-voice-name
                          (get-next-unique-voice-name)))
          (voice (if (string? existing-voice-name)
-                    (music)
-                    (make-music 'ContextSpeccedMusic
-                                'element music
-                                'context-type 'Voice
-                                'context-id voice-name
-                                'origin (ly:music-property music 'origin))))
+                    music
+                    (if (eq? (ly:music-property music 'name) 'ContextSpeccedMusic)
+                        (begin
+                          (set! (ly:music-property music 'element)
+                                (make-music 'ContextSpeccedMusic
+                                            'element (ly:music-property music 'element)
+                                            'context-type 'Voice
+                                            'context-id voice-name
+                                            'origin (ly:music-property music 'origin)))
+                          music)
+                        (make-music 'ContextSpeccedMusic
+                                    'element music
+                                    'context-type 'Voice
+                                    'context-id voice-name
+                                    'origin (ly:music-property music 'origin)))))
          (lyricstos (map (lambda (mus)
                            (let* ((loc (ly:music-property mus 'origin))
                                   (lyr (lyric-combine-music voice-name mus loc)))