SCM sid = lookup_identifier (str);
if (is_music_function (sid))
{
+ int funtype = MUSIC_FUNCTION;
+
yylval.scm = get_music_function_transform (sid);
SCM s = scm_object_property (yylval.scm, ly_symbol2scm ("music-function-signature"));
+ if (scm_is_eq (scm_car (s), ly_lily_module_constant ("scheme-function")))
+ funtype = SCM_FUNCTION;
+
push_extra_token (EXPECT_NO_MORE_ARGS);
- for (; scm_is_pair (s); s = scm_cdr (s))
+ for (s = scm_cdr (s); scm_is_pair (s); s = scm_cdr (s))
{
SCM cs = scm_car (s);
push_extra_token (EXPECT_SCM);
else programming_error ("Function parameter without type-checking predicate");
}
- return MUSIC_FUNCTION;
+ return funtype;
}
if (sid != SCM_UNDEFINED)
(SCM signature, SCM func),
"Make a function to process music, to be used for the"
" parser. @var{func} is the function, and @var{signature}"
- " describes its arguments. @var{signature} is a list"
+ " describes its arguments. @var{signature}'s cdr is a list"
" containing either @code{ly:music?} predicates or other type"
- " predicates.")
+ " predicates. Its car is the syntax function to call.")
{
LY_ASSERT_TYPE (ly_is_procedure, func, 1);
return make_music_function (signature, func);
%token <scm> OUTPUT_DEF_IDENTIFIER
%token <scm> REAL
%token <scm> RESTNAME
+%token <scm> SCM_FUNCTION
%token <scm> SCM_IDENTIFIER
%token <scm> SCM_TOKEN
%token <scm> SCORE_IDENTIFIER
%type <scm> property_operation
%type <scm> property_path property_path_revved
%type <scm> scalar
+%type <scm> scm_function_call
%type <scm> script_abbreviation
%type <scm> simple_chord_elements
%type <scm> simple_markup
embedded_scm:
SCM_TOKEN
| SCM_IDENTIFIER
+ | scm_function_call
+ ;
+
+scm_function_call:
+ SCM_FUNCTION closed_function_arglist
+ {
+ $$ = run_music_function (PARSER, @$,
+ $1, $2);
+ }
;
embedded_lilypond:
SCM type_check_proc = ly_lily_module_constant ("type-check-list");
- if (!to_boolean (scm_call_3 (type_check_proc, make_input (loc), sig, args)))
+ if (!to_boolean (scm_call_3 (type_check_proc, make_input (loc), scm_cdr (sig), args)))
{
parser->error_level_ = 1;
return LOWLEVEL_MAKE_SYNTAX (ly_lily_module_constant ("void-music"), scm_list_2 (parser->self_scm (), make_input (loc)));
}
SCM syntax_args = scm_list_4 (parser->self_scm (), make_input (loc), func, args);
- return LOWLEVEL_MAKE_SYNTAX (ly_lily_module_constant ("music-function"), syntax_args);
+ return LOWLEVEL_MAKE_SYNTAX (scm_car (sig), syntax_args);
}
bool
(set! (ly:music-property m 'origin) location)
m)))
+;; Scheme function: Apply function, return value can be anything
+(define-ly-syntax (scheme-function parser loc fun args)
+ (apply fun parser loc args))
+
;; Music function: Apply function and check return value.
(define-ly-syntax-loc (music-function parser loc fun args)
- (let ((m (apply fun (cons* parser loc args))))
+ (let ((m (apply fun parser loc args)))
(if (ly:music? m)
m
(begin
;; (_i "doc string"), keep the literal string only
(let ((docstring (cadar body))
(body (cdr body)))
- `(ly:make-music-function (list ,@signature)
+ `(ly:make-music-function (list music-function ,@signature)
(lambda (,@args)
,docstring
,@body)))
- `(ly:make-music-function (list ,@signature)
+ `(ly:make-music-function (list music-function ,@signature)
+ (lambda (,@args)
+ ,@body))))
+
+(defmacro-public define-scheme-function (args signature . body)
+ "Helper macro for `ly:make-music-function'.
+Syntax:
+ (define-scheme-function (parser location arg1 arg2 ...) (arg1-type? arg2-type? ...)
+ ...function body...)
+"
+(if (and (pair? body) (pair? (car body)) (eqv? '_i (caar body)))
+ ;; When the music function definition contains a i10n doc string,
+ ;; (_i "doc string"), keep the literal string only
+ (let ((docstring (cadar body))
+ (body (cdr body)))
+ `(ly:make-music-function (list scheme-function ,@signature)
+ (lambda (,@args)
+ ,docstring
+ ,@body)))
+ `(ly:make-music-function (list scheme-function ,@signature)
(lambda (,@args)
,@body))))