+2004-05-06 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+ * lily/parser.yy (Generic_prefix_music_scm): add more
+ music_function symbols.
+
+ * lily/include/music-function.hh: rename to music-function
+
2004-05-05 Han-Wen Nienhuys <hanwen@xs4all.nl>
* lily/music-head.cc (LY_DEFINE): change order of args.
@code{element}. The body of a repeat is in @code{element} property of
@internalsref{RepeatedMusic}, and the alternatives in @code{elements}.
+
+
+
+@node Extending music syntax
+@appendixsubsec Extending music syntax
+
+The syntax of composite music expressions, like
+@code{\repeat}, @code{\transpose} and @code{\context}
+follows the general form of
+
+@example
+ \@code{keyword} @var{non-music-arguments} @var{music-arguments}
+@end example
+
+Such syntax can also be defined as user code. To do this, it is
+necessary to create a @em{music function}. This is a specially marked
+Scheme function. For example, the music function @code{\apply} applies
+a user-defined function to a music expression. Its syntax is
+
+@example
+\apply #@var{func} @var{music}
+@end example
+
+A music function is created with @code{ly:make-music-function}.
+
+
+
@node Manipulating music expressions
@appendixsubsec Manipulating music expressions
\header
{
-texidoc = "Music heads are generic music transformation functions,
+texidoc = "Music function are generic music transformation functions,
which can be used to extend music syntax seamlessly."
}
\version "2.3.1"
#(define myBar
- (ly:make-music-head
+ (ly:make-music-function
(list string?)
(lambda (where type)
(context-spec-music
--- /dev/null
+/*
+ music-head.hh -- declare music_function
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 2004 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+*/
+
+#ifndef MUSIC_FUNCTION_HH
+#define MUSIC_FUNCTION_HH
+
+#include "lily-guile.hh"
+
+SCM ly_make_music_function (SCM, SCM);
+SCM get_music_function_transform (SCM);
+bool is_music_function (SCM);
+
+#endif /* MUSIC_FUNCTION_HH */
+
+++ /dev/null
-/*
- music-head.hh -- declare Music_head
-
- source file of the GNU LilyPond music typesetter
-
- (c) 2004 Han-Wen Nienhuys <hanwen@xs4all.nl>
-
-*/
-
-#ifndef MUSIC_HEAD_HH
-#define MUSIC_HEAD_HH
-
-#include "lily-guile.hh"
-
-SCM ly_make_music_head (SCM, SCM);
-SCM get_music_head_transform (SCM);
-bool is_music_head (SCM);
-
-#endif /* MUSIC_HEAD_HH */
-
#include <iostream>
using namespace std;
-#include "music-head.hh"
+#include "music-function.hh"
#include "source-file.hh"
#include "parse-scm.hh"
#include "lily-guile.hh"
return l;
}
SCM sid = lookup_identifier (str);
- if (is_music_head (sid))
+ if (is_music_function (sid))
{
- yylval.scm = get_music_head_transform (sid);
- return music_head_type (yylval.scm);
+ yylval.scm = get_music_function_transform (sid);
+
+ return music_function_type (yylval.scm);
}
if (sid != SCM_UNDEFINED)
int
-music_head_type (SCM func)
+music_function_type (SCM func)
{
SCM type= scm_object_property (func, ly_symbol2scm ("music-head-signature-keyword"));
if (type == ly_symbol2scm ("scm"))
{
- return MUSIC_HEAD_SCM;
+ return MUSIC_FUNCTION_SCM;
}
else if (type == ly_symbol2scm ("music"))
{
- return MUSIC_HEAD_MUSIC;
+ return MUSIC_FUNCTION_MUSIC;
}
else if (type == ly_symbol2scm ("scm-music"))
{
- return MUSIC_HEAD_SCM_MUSIC;
+ return MUSIC_FUNCTION_SCM_MUSIC;
+ }
+ else if (type == ly_symbol2scm ("music-music"))
+ {
+ return MUSIC_FUNCTION_MUSIC_MUSIC;
}
else if (type == ly_symbol2scm ("scm-music-music"))
{
- return MUSIC_HEAD_SCM_MUSIC_MUSIC;
+ return MUSIC_FUNCTION_SCM_MUSIC_MUSIC;
}
else if (type == ly_symbol2scm ("scm-scm-music"))
{
- return MUSIC_HEAD_SCM_SCM_MUSIC;
+ return MUSIC_FUNCTION_SCM_SCM_MUSIC;
}
else
assert (false);
- return MUSIC_HEAD_SCM_MUSIC_MUSIC;
+ return MUSIC_FUNCTION_SCM_MUSIC_MUSIC;
}
*/
-#include "music-wrapper.hh"
-
+#include "music-wrapper.hh"
Music_wrapper::Music_wrapper ()
%token <scm> MARKUP_HEAD_SCM0_SCM1_SCM2
%token <scm> MARKUP_HEAD_SCM0_SCM1_MARKUP2
-%token <scm> MUSIC_HEAD_SCM
-%token <scm> MUSIC_HEAD_MUSIC
-%token <scm> MUSIC_HEAD_SCM_MUSIC
-%token <scm> MUSIC_HEAD_MUSIC_MUSIC
-%token <scm> MUSIC_HEAD_SCM_SCM_MUSIC
-%token <scm> MUSIC_HEAD_SCM_MUSIC_MUSIC
+%token <scm> MUSIC_FUNCTION_SCM
+%token <scm> MUSIC_FUNCTION_MUSIC
+%token <scm> MUSIC_FUNCTION_SCM_MUSIC
+%token <scm> MUSIC_FUNCTION_MUSIC_MUSIC
+%token <scm> MUSIC_FUNCTION_SCM_SCM_MUSIC
+%token <scm> MUSIC_FUNCTION_SCM_MUSIC_MUSIC
%token <scm> MARKUP_IDENTIFIER MARKUP_HEAD_LIST0
%type <scm> markup markup_line markup_list markup_list_body full_markup
%type <book> book_block book_body
%type <i> exclamations questions dots optional_rest
-%type <i> bass_mod
+%type <i> bass_mod
%type <scm> grace_head
%type <scm> oct_check
%type <scm> context_mod_list
%type <music> toplevel_music
%type <music> simple_element event_chord command_element
%type <music> Composite_music Simple_music Prefix_composite_music Generic_prefix_music
+%type <scm> Generic_prefix_music_scm
%type <music> Grouped_music_list
%type <music> Repeated_music
%type <scm> Alternative_music
| Sequential_music { $$ = $1; }
;
+Generic_prefix_music_scm:
+ MUSIC_FUNCTION_SCM {
+ THIS->push_spot ();
+ } embedded_scm {
+ $$ = scm_list_3 ($1, make_input (THIS->pop_spot ()), $3);
+ }
+ | MUSIC_FUNCTION_MUSIC {
+ THIS->push_spot ();
+ } Music {
+ $$ = scm_list_3 ($1, make_input (THIS->pop_spot ()), $3->self_scm ());
+ scm_gc_unprotect_object ($3->self_scm ());
+ }
+ | MUSIC_FUNCTION_SCM_MUSIC {
+ THIS->push_spot ();
+ } embedded_scm Music {
+ $$ = scm_list_4 ($1, make_input (THIS->pop_spot ()), $3, $4->self_scm ());
+ scm_gc_unprotect_object ($4->self_scm ());
+ }
+ | MUSIC_FUNCTION_MUSIC_MUSIC {
+ THIS->push_spot ();
+ } Music Music {
+ $$ = scm_list_4 ($1, make_input (THIS->pop_spot ()), $3->self_scm (), $4->self_scm ());
+ scm_gc_unprotect_object ($3->self_scm ());
+ scm_gc_unprotect_object ($4->self_scm ());
+ }
+ | MUSIC_FUNCTION_SCM_MUSIC_MUSIC {
+ THIS->push_spot ();
+ } embedded_scm Music Music {
+ $$ = scm_list_5 ($1, make_input (THIS->pop_spot ()),
+ $3, $4->self_scm (), $5->self_scm ());
+ scm_gc_unprotect_object ($5->self_scm ());
+ scm_gc_unprotect_object ($4->self_scm ());
+ }
+ ;
+
Generic_prefix_music:
- MUSIC_HEAD_SCM { THIS->push_spot (); } embedded_scm {
- SCM m = scm_call_2 ($1, make_input (THIS->pop_spot ()),
- $3);
+ Generic_prefix_music_scm {
+ SCM func = ly_car ($1);
+ Input *loc = unsmob_input (ly_cadr ($1));
+ SCM args = ly_cddr ($1);
+ SCM sig = scm_object_property (func, ly_symbol2scm ("music-head-signature"));
+ int k = 0;
+ bool ok = true;
+ for (SCM s = sig, t = args;
+ ok && ly_c_pair_p (s) && ly_c_pair_p (t);
+ s = ly_cdr (s), t = ly_cdr (t)) {
+ k++;
+ if (scm_call_1 (ly_car (s), ly_car (t)) != SCM_BOOL_T)
+ {
+ loc->error (_f ("Argument %d failed typecheck", k));
+ THIS->error_level_ = 1;
+ ok = false;
+ }
+ }
+ SCM m = SCM_EOL;
+ if (ok)
+ m = scm_apply_0 (func, ly_cdr ($1));
if (unsmob_music (m))
- { $$ = unsmob_music (m);
+ {
+ $$ = unsmob_music (m);
scm_gc_protect_object (m);
- }
+ }
else
- {
- THIS->parser_error ("MUSIC_HEAD should return Music");
- $$ = MY_MAKE_MUSIC("Music");
- }
+ {
+ loc->error (_ ("Music head function should return Music object."));
+ $$ = MY_MAKE_MUSIC ("Music");
+ }
+
}
;
+
Prefix_composite_music:
Generic_prefix_music {
$$ = $1;