]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/parser.yy
Issue 4487/3: Implement partial markups
[lilypond.git] / lily / parser.yy
index 8c08819d7dd9b52aaea3568ae2bcdf8604671796..9da363df933d208053348e40223a98e6ea359a6e 100644 (file)
@@ -187,39 +187,30 @@ Lily_parser::parser_error (Input const *i, Lily_parser *parser, SCM *, const str
                               parser->lexer_->override_input (spot))
 
 /* ES TODO:
-- Don't use lily module, create a new module instead.
 - delay application of the function
 */
 
-static SCM
-syntax_call (void *arg)
-{
-       SCM sarg = reinterpret_cast <SCM> (arg);
-       return scm_apply_0 (scm_car (sarg), scm_cdr (sarg));
-}
-
-#define LOWLEVEL_MAKE_SYNTAX(location, args)                           \
-       scm_c_with_fluid                                                \
-               (Lily::f_location,                                      \
-                parser->lexer_->override_input (location).smobbed_copy (), \
-                syntax_call,                                           \
-                reinterpret_cast <void*> (args))
+#define LOWLEVEL_MAKE_SYNTAX(location, proc, ...)                      \
+       with_location                                                   \
+               (parser->lexer_->override_input (location).smobbed_copy (), \
+                proc,                                                  \
+                ##__VA_ARGS__)
 
 /* Syntactic Sugar. */
 #define MAKE_SYNTAX(name, location, ...)                               \
-       LOWLEVEL_MAKE_SYNTAX (location,                                 \
-                             scm_list_n (Lily::name,                   \
-                                         ##__VA_ARGS__, SCM_UNDEFINED))
+       LOWLEVEL_MAKE_SYNTAX (location, Syntax::name, ##__VA_ARGS__)
 
 #define START_MAKE_SYNTAX(name, ...)                                   \
-       scm_list_n (Lily::name,                                         \
-                   ##__VA_ARGS__, SCM_UNDEFINED)
+       scm_list_n (Syntax::name, ##__VA_ARGS__, SCM_UNDEFINED)
 
 #define FINISH_MAKE_SYNTAX(start, location, ...)                       \
-       LOWLEVEL_MAKE_SYNTAX (location,                                 \
-                             scm_append_x                              \
-                             (scm_list_2 (start, scm_list_n            \
-                                          (__VA_ARGS__, SCM_UNDEFINED))))
+       LOWLEVEL_MAKE_SYNTAX                                            \
+               (location,                                              \
+                Guile_user::apply,                                     \
+                scm_car (start),                                       \
+                scm_append_x                                           \
+                (scm_list_2 (scm_cdr (start),                          \
+                             scm_list_n (__VA_ARGS__, SCM_UNDEFINED))))
 
 SCM get_next_unique_context_id ();
 SCM get_next_unique_lyrics_context_id ();
@@ -274,6 +265,7 @@ int yylex (YYSTYPE *s, YYLTYPE *loc, Lily_parser *parser);
 %token DESCRIPTION "\\description"
 %token DRUMMODE "\\drummode"
 %token DRUMS "\\drums"
+%token ETC "\\etc"
 %token FIGUREMODE "\\figuremode"
 %token FIGURES "\\figures"
 %token HEADER "\\header"
@@ -518,6 +510,7 @@ embedded_scm_bare_arg:
                $$ = parser->lexer_->eval_scm_token ($1, @1);
        }
        | FRACTION
+       | partial_markup
        | full_markup_list
        | context_modification
        | score_block
@@ -700,8 +693,61 @@ identifier_init_nonumber:
        | FRACTION
        | string
         | embedded_scm
+       | partial_markup
        | full_markup_list
         | context_modification
+       | partial_function ETC
+       {
+               $$ = MAKE_SYNTAX (partial_music_function, @$,
+                                 scm_reverse_x (scm_car ($1), SCM_EOL),
+                                 scm_reverse_x (scm_cdr ($1), SCM_EOL));
+       }
+       ;
+
+// Partial functions
+partial_function:
+       MUSIC_FUNCTION function_arglist_partial
+       {
+               $$ = scm_cons (scm_list_1 ($1), scm_list_1 ($2));
+       }
+       | EVENT_FUNCTION function_arglist_partial
+       {
+               $$ = scm_cons (scm_list_1 ($1), scm_list_1 ($2));
+       }
+       | SCM_FUNCTION function_arglist_partial
+       {
+               $$ = scm_cons (scm_list_1 ($1), scm_list_1 ($2));
+       }
+       | MUSIC_FUNCTION EXPECT_SCM function_arglist_optional partial_function
+       {
+               $$ = scm_cons (scm_cons ($1, scm_car ($4)),
+                              scm_cons ($3, scm_cdr ($4)));
+       }
+       | EVENT_FUNCTION EXPECT_SCM function_arglist_optional partial_function
+       {
+               $$ = scm_cons (scm_cons ($1, scm_car ($4)),
+                              scm_cons ($3, scm_cdr ($4)));
+       }
+       | SCM_FUNCTION EXPECT_SCM function_arglist_optional partial_function
+       {
+               $$ = scm_cons (scm_cons ($1, scm_car ($4)),
+                              scm_cons ($3, scm_cdr ($4)));
+       }
+       | MUSIC_FUNCTION EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup partial_function
+       {
+               $$ = scm_cons (scm_cons ($1, scm_car ($5)),
+                              scm_cons ($4, scm_cdr ($5)));
+       }
+       | EVENT_FUNCTION EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup partial_function
+       {
+               $$ = scm_cons (scm_cons ($1, scm_car ($5)),
+                              scm_cons ($4, scm_cdr ($5)));
+       }
+       | SCM_FUNCTION EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup partial_function
+       {
+               $$ = scm_cons (scm_cons ($1, scm_car ($5)),
+                              scm_cons ($4, scm_cdr ($5)));
+       }
        ;
 
 context_def_spec_block:
@@ -2013,6 +2059,56 @@ function_arglist_skip_nonbackup:
        }
        ;
 
+// Partial function arglists are returned just in their incomplete
+// state: when combined with the music function, the missing parts of
+// the signature can be reconstructed
+//
+// To serve as a partial arglist, the argument list must absolutely
+// _not_ be in "skipping optional arguments" mode since then there is
+// some backup token that has nowhere to go before \etc.
+//
+// So we can skim off an arbitrary number of arguments from the end of
+// the argument list.  The argument list remaining afterwards has to
+// be in not-skipping-optional-arguments mode.
+
+function_arglist_partial:
+       EXPECT_SCM function_arglist_optional
+       {
+               $$ = $2;
+       }
+       | EXPECT_SCM function_arglist_partial_optional
+       {
+               $$ = $2;
+       }
+       | EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup
+       {
+               $$ = $3;
+       }
+       | EXPECT_OPTIONAL EXPECT_SCM function_arglist_partial
+       {
+               $$ = $3;
+       }
+       ;
+
+function_arglist_partial_optional:
+       EXPECT_SCM function_arglist_optional
+       {
+               $$ = $2;
+       }
+       | EXPECT_SCM function_arglist_partial_optional
+       {
+               $$ = $2;
+       }
+       | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup
+       {
+               $$ = $3;
+       }
+       | EXPECT_OPTIONAL EXPECT_SCM function_arglist_partial_optional
+       {
+               $$ = $3;
+       }
+       ;
+
 function_arglist_common:
        EXPECT_NO_MORE_ARGS {
                $$ = SCM_EOL;
@@ -3518,11 +3614,24 @@ full_markup_list:
        }
        ;
 
-full_markup:
+markup_mode:
        MARKUP
-               { parser->lexer_->push_markup_state (); }
-       markup_top {
-               $$ = $3;
+       {
+               parser->lexer_->push_markup_state ();
+       }
+       ;
+
+full_markup:
+       markup_mode markup_top {
+               $$ = $2;
+               parser->lexer_->pop_state ();
+       }
+       ;
+
+partial_markup:
+       markup_mode markup_head_1_list ETC
+       {
+               $$ = MAKE_SYNTAX (partial_markup, @2, $2);
                parser->lexer_->pop_state ();
        }
        ;