]> git.donarmstrong.com Git - lilypond.git/commitdiff
Issue 4487/1: Implement partial function calls
authorDavid Kastrup <dak@gnu.org>
Tue, 7 Jul 2015 19:44:59 +0000 (21:44 +0200)
committerDavid Kastrup <dak@gnu.org>
Sat, 18 Jul 2015 04:42:12 +0000 (06:42 +0200)
A partial function call acts as a function where the start of the
argument list has already been supplied.  For example:

makeRed = \tweak color #red \etc

Then one can use this as

{ c' \makeRed d' e'-\makeRed -. }

lily/include/lily-imports.hh
lily/lily-imports.cc
lily/lily-lexer.cc
lily/parser.yy
scm/ly-syntax-constructors.scm

index 120ff11cb7e3adf0af47f5bf826711748a93f956..535b40bea40a07e8672e3af8e96001056adee75c 100644 (file)
@@ -119,6 +119,7 @@ namespace Syntax {
   extern Variable multi_measure_rest;
   extern Variable music_function;
   extern Variable music_function_call_error;
+  extern Variable partial_music_function;
   extern Variable property_operation;
   extern Variable repeat;
   extern Variable repetition_chord;
index 6f16c0ebc05d7aaabc890693e193adaf515191f1..2a8ecf9e84579893b459edd24138871b116d56f9 100644 (file)
@@ -112,6 +112,7 @@ namespace Syntax {
   Variable multi_measure_rest ("multi-measure-rest");
   Variable music_function ("music-function");
   Variable music_function_call_error ("music-function-call-error");
+  Variable partial_music_function ("partial-music-function");
   Variable property_operation ("property-operation");
   Variable repeat ("repeat");
   Variable repetition_chord ("repetition-chord");
index 68b5578994b654e5bc12f95e505ae9af7ba142d0..b6cbda7f976160ee0b9cd5f0463a446eee9aa686 100644 (file)
@@ -57,6 +57,7 @@ static Keyword_ent the_key_tab[]
   {"description", DESCRIPTION},
   {"drummode", DRUMMODE},
   {"drums", DRUMS},
+  {"etc", ETC},
   {"figuremode", FIGUREMODE},
   {"figures", FIGURES},
   {"header", HEADER},
index 25b7cd86c3e95f1ec6da4379b9fb6db3575fca6a..581791d256badd07139b44758f2ed9fedb4e4a1a 100644 (file)
@@ -265,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"
@@ -693,6 +694,25 @@ identifier_init_nonumber:
         | embedded_scm
        | full_markup_list
         | context_modification
+       | partial_function ETC
+       ;
+
+partial_function:
+       MUSIC_FUNCTION function_arglist_partial
+       {
+               $$ = MAKE_SYNTAX (partial_music_function, @$,
+                                 $1, $2);
+       }
+       | EVENT_FUNCTION function_arglist_partial
+       {
+               $$ = MAKE_SYNTAX (partial_music_function, @$,
+                                 $1, $2);
+       }
+       | SCM_FUNCTION function_arglist_partial
+       {
+               $$ = MAKE_SYNTAX (partial_music_function, @$,
+                                 $1, $2);
+       }
        ;
 
 context_def_spec_block:
@@ -2004,6 +2024,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;
index 04629bf65568389fd731030d89622355625fd72c..b53e0cb34e0a2bb479847e51ca553b5f5cabafb8 100644 (file)
            n (type-name pred) (music->make-music arg))
    (*location*)))
 
+(define-public (partial-music-function fun args)
+  (let* ((sig (ly:music-function-signature fun))
+         (args (and (list args) (reverse! args))))
+    (and args
+         (ly:make-music-function
+          (cons (car sig) (list-tail (cdr sig) (length args)))
+          (lambda rest
+            (apply (ly:music-function-extract fun)
+                   (append args rest)))))))
+
 (define-public (void-music)
   (ly:set-origin! (make-music 'Music)))