X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fparser.yy;h=48dc5680b3bc5cae6b1d16fa962a50b68e2e8d96;hb=999595939c26d7f060ca73c6fd537248962942e0;hp=3fda84232f7c9b928f56cf44bc3063462f5ab33f;hpb=d2d364015c346e1aaed2a8f25dfcf11182abf3ab;p=lilypond.git diff --git a/lily/parser.yy b/lily/parser.yy index 3fda84232f..48dc5680b3 100644 --- a/lily/parser.yy +++ b/lily/parser.yy @@ -113,7 +113,7 @@ or -%pure_parser +%pure-parser %locations @@ -194,7 +194,9 @@ while (0) %{ -#define MY_MAKE_MUSIC(x, spot) make_music_with_input (ly_symbol2scm (x), spot) +#define MY_MAKE_MUSIC(x, spot) \ + make_music_with_input (ly_symbol2scm (x), \ + parser->lexer_->override_input (spot)) /* ES TODO: - Don't use lily module, create a new module instead. @@ -203,12 +205,12 @@ while (0) #define LOWLEVEL_MAKE_SYNTAX(proc, args) \ scm_apply_0 (proc, args) /* Syntactic Sugar. */ -#define MAKE_SYNTAX(name, location, ...) \ - LOWLEVEL_MAKE_SYNTAX (ly_lily_module_constant (name), scm_list_n (parser->self_scm (), make_input (location) , ##__VA_ARGS__, SCM_UNDEFINED)) +#define MAKE_SYNTAX(name, location, ...) \ + LOWLEVEL_MAKE_SYNTAX (ly_lily_module_constant (name), scm_list_n (parser->self_scm (), make_input (parser->lexer_->override_input (location)), ##__VA_ARGS__, SCM_UNDEFINED)) #define START_MAKE_SYNTAX(name, ...) \ scm_list_n (ly_lily_module_constant (name) , ##__VA_ARGS__, SCM_UNDEFINED) #define FINISH_MAKE_SYNTAX(start, location, ...) \ - LOWLEVEL_MAKE_SYNTAX (scm_car (start), scm_cons2 (parser->self_scm (), make_input (location), scm_append_x (scm_list_2 (scm_cdr (start), scm_list_n (__VA_ARGS__, SCM_UNDEFINED))))) + LOWLEVEL_MAKE_SYNTAX (scm_car (start), scm_cons2 (parser->self_scm (), make_input (parser->lexer_->override_input (location)), 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 (); @@ -224,14 +226,15 @@ SCM get_next_unique_lyrics_context_id (); static Music *make_music_with_input (SCM name, Input where); SCM check_scheme_arg (Lily_parser *parser, Input loc, - SCM arg, SCM args, SCM pred); + SCM arg, SCM args, SCM pred, SCM disp = SCM_UNDEFINED); SCM make_music_from_simple (Lily_parser *parser, Input loc, SCM pitch); SCM loc_on_music (Input loc, SCM arg); SCM make_chord_elements (Input loc, SCM pitch, SCM dur, SCM modification_list); SCM make_chord_step (SCM step, Rational alter); SCM make_simple_markup (SCM a); bool is_duration (int t); -bool is_regular_identifier (SCM id); +bool is_regular_identifier (SCM id, bool multiple=false); +SCM try_string_variants (SCM pred, SCM str); int yylex (YYSTYPE *s, YYLTYPE *loc, Lily_parser *parser); %} @@ -306,16 +309,8 @@ int yylex (YYSTYPE *s, YYLTYPE *loc, Lily_parser *parser); %token DOUBLE_ANGLE_OPEN "<<" %token DOUBLE_ANGLE_CLOSE ">>" %token E_BACKSLASH "\\" -%token E_ANGLE_CLOSE "\\>" -%token E_CHAR "\\C[haracter]" -%token E_CLOSE "\\)" %token E_EXCLAMATION "\\!" -%token E_BRACKET_OPEN "\\[" -%token E_OPEN "\\(" -%token E_BRACKET_CLOSE "\\]" -%token E_ANGLE_OPEN "\\<" %token E_PLUS "\\+" -%token E_TILDE "\\~" %token EXTENDER "__" /* @@ -327,7 +322,6 @@ If we give names, Bison complains. %token HYPHEN "--" %token CHORDMODIFIERS -%token LYRIC_MARKUP %token MULTI_MEASURE_REST @@ -361,7 +355,6 @@ If we give names, Bison complains. %token EVENT_IDENTIFIER %token EVENT_FUNCTION %token FRACTION -%token LYRICS_STRING %token LYRIC_ELEMENT %token MARKUP_FUNCTION %token MARKUP_LIST_FUNCTION @@ -374,11 +367,12 @@ If we give names, Bison complains. %token OUTPUT_DEF_IDENTIFIER %token REAL %token RESTNAME +%token SCM_ARG %token SCM_FUNCTION %token SCM_IDENTIFIER %token SCM_TOKEN -%token SCORE_IDENTIFIER %token STRING +%token SYMBOL_LIST %token TONICNAME_PITCH %left '-' '+' @@ -492,9 +486,11 @@ embedded_scm_active: ; embedded_scm_bare_arg: - embedded_scm_bare - | STRING - | full_markup + SCM_ARG + | SCM_TOKEN + { + $$ = parser->lexer_->eval_scm_token ($1); + } | full_markup_list | context_modification | score_block @@ -570,7 +566,6 @@ lilypond_header: */ assignment_id: STRING { $$ = $1; } - | LYRICS_STRING { $$ = $1; } ; assignment: @@ -593,7 +588,28 @@ identifier_init: | output_def | context_def_spec_block | music_assign - | post_event_nofinger + | post_event_nofinger post_events + { + $$ = scm_reverse_x ($2, SCM_EOL); + if (Music *m = unsmob_music ($1)) + { + if (m->is_mus_type ("post-event-wrapper")) + $$ = scm_append + (scm_list_2 (m->get_property ("elements"), + $$)); + else + $$ = scm_cons ($1, $$); + } + if (scm_is_pair ($$) + && scm_is_null (scm_cdr ($$))) + $$ = scm_car ($$); + else + { + Music * m = MY_MAKE_MUSIC ("PostEvents", @$); + m->set_property ("elements", $$); + $$ = m->unprotect (); + } + } | number_expression | FRACTION | string @@ -611,7 +627,16 @@ context_def_spec_block: context_mod_arg: embedded_scm - | composite_music + | + { + SCM nn = parser->lexer_->lookup_identifier ("pitchnames"); + parser->lexer_->push_note_state (nn); + } + composite_music + { + parser->lexer_->pop_state (); + $$ = $2; + } ; context_mod_embedded: @@ -640,7 +665,8 @@ context_def_spec_body: unsmob_context_def ($$)->origin ()->set_spot (@$); } | context_def_spec_body context_mod { - unsmob_context_def ($$)->add_context_mod ($2); + if (!SCM_UNBNDP ($2)) + unsmob_context_def ($$)->add_context_mod ($2); } | context_def_spec_body context_modification { Context_def *td = unsmob_context_def ($$); @@ -823,8 +849,16 @@ score_body: unsmob_score ($$)->origin ()->set_spot (@$); } - | SCORE_IDENTIFIER { + | embedded_scm_active { + Score *score; + if (unsmob_score ($1)) + score = new Score (*unsmob_score ($1)); + else { + score = new Score; + parser->parser_error (@1, _("score expected")); + } unsmob_score ($$)->origin ()->set_spot (@$); + $$ = score->unprotect (); } | score_body { @@ -1007,15 +1041,40 @@ music: music_arg music_embedded: music - | embedded_scm { - if (unsmob_music ($1) - || scm_is_eq ($1, SCM_UNSPECIFIED)) + if (unsmob_music ($1)->is_mus_type ("post-event")) { + parser->parser_error (@1, _ ("unexpected post-event")); + $$ = SCM_UNSPECIFIED; + } + } + | music_embedded_backup + { + $$ = $1; + } + | music_embedded_backup BACKUP lyric_element_music + { + $$ = $3; + } + ; + +music_embedded_backup: + embedded_scm + { + if (scm_is_eq ($1, SCM_UNSPECIFIED)) $$ = $1; - else - { + else if (Music *m = unsmob_music ($1)) { + if (m->is_mus_type ("post-event")) { + parser->parser_error + (@1, _ ("unexpected post-event")); + $$ = SCM_UNSPECIFIED; + } else + $$ = $1; + } else if (parser->lexer_->is_lyric_state () + && Text_interface::is_markup ($1)) + MYBACKUP (LYRIC_ELEMENT, $1, @1); + else { @$.warning (_ ("Ignoring non-music expression")); - $$ = SCM_UNSPECIFIED; + $$ = $1; } } ; @@ -1110,7 +1169,8 @@ context_mod_list: $$ = Context_mod ().smobbed_copy (); } | context_mod_list context_mod { - unsmob_context_mod ($1)->add_context_mod ($2); + if (!SCM_UNBNDP ($2)) + unsmob_context_mod ($1)->add_context_mod ($2); } | context_mod_list CONTEXT_MOD_IDENTIFIER { Context_mod *md = unsmob_context_mod ($2); @@ -1153,6 +1213,34 @@ grouped_music_list: MUSIC_FUNCTION EXPECT_PITCH EXPECT_SCM EXPECT_SCM EXPECT_NO_MORE_ARGS and this rule returns the reversed list of arguments. */ +/* Function argument lists come in a number of flavors. Whenever + * LilyPond has to pick between different flavors, the decision is + * either made because of tokens it has already seen, or it is + * postponed until tokens suitable for making the decision come up. + * For postponing decisions, it may be necessary that the competing + * rules are written in a way making them compatible until a decision + * can be made. Sometimes this is done by putting common traits into + * a separate "common" rule set. + * + * function_arglist: a full argument list. Optional arguments at the + * end of the list can only be skipped by writing \default in their + * place. + * + * function_arglist_backup: an argument list ending in an optional + * argument that may be skipped depending on its predicate. + * + * function_arglist_skip: an argument list _not_ ending in an optional + * argument that is actually taken. + * + * function_arglist_nonbackup: an argument list ending in an optional + * argument that may not be skipped because it is in end position and + * has not been shortcircuited with \default. + * + * function_arglist* / function_arglist_closed*: The closed variants + * don't end in simple music expressions that might still accept + * things like a duration or a postevent. + */ + function_arglist_skip: function_arglist_common | EXPECT_OPTIONAL EXPECT_PITCH function_arglist_skip @@ -1193,11 +1281,8 @@ function_arglist_nonbackup_common: else { Music *t = MY_MAKE_MUSIC ("FingeringEvent", @5); t->set_property ("digit", $5); - $$ = t->unprotect (); - if (scm_is_true (scm_call_1 ($2, $$))) - $$ = scm_cons ($$, $3); - else - $$ = check_scheme_arg (parser, @4, n, $3, $2); + $$ = check_scheme_arg (parser, @4, t->unprotect (), + $3, $2, n); } } @@ -1225,8 +1310,62 @@ function_arglist_closed_nonbackup: { $$ = check_scheme_arg (parser, @4, $4, $3, $2); } + | EXPECT_OPTIONAL EXPECT_SCM function_arglist SCM_IDENTIFIER + { + $$ = check_scheme_arg (parser, @4, + try_string_variants ($2, $4), + $3, $2, $4); + } + | EXPECT_OPTIONAL EXPECT_SCM function_arglist STRING + { + $$ = check_scheme_arg (parser, @4, + try_string_variants ($2, $4), + $3, $2, $4); + } + | EXPECT_OPTIONAL EXPECT_SCM function_arglist full_markup + { + $$ = check_scheme_arg (parser, @4, $4, $3, $2); + } + ; + +symbol_list_arg: + SYMBOL_LIST + | SYMBOL_LIST '.' symbol_list_rev + { + $$ = scm_append (scm_list_2 ($1, scm_reverse_x ($3, SCM_EOL))); + } + ; + +symbol_list_rev: + symbol_list_part + | symbol_list_rev '.' symbol_list_part + { + $$ = scm_append_x (scm_list_2 ($3, $1)); + } + ; + +// symbol_list_part delivers elements in reverse copy. + +symbol_list_part: + symbol_list_element + { + SCM sym_l_p = ly_lily_module_constant ("symbol-list?"); + $$ = try_string_variants (sym_l_p, $1); + if (SCM_UNBNDP ($$)) { + parser->parser_error (@1, _("not a symbol")); + $$ = SCM_EOL; + } else + $$ = scm_reverse ($$); + } + ; + + +symbol_list_element: + STRING + | embedded_scm_bare ; + function_arglist_nonbackup: function_arglist_nonbackup_common | EXPECT_OPTIONAL EXPECT_SCM function_arglist embedded_scm_arg @@ -1237,6 +1376,68 @@ function_arglist_nonbackup: { $$ = check_scheme_arg (parser, @4, $4, $3, $2); } + | function_arglist_nonbackup_reparse REPARSE SCM_ARG + { + $$ = check_scheme_arg (parser, @3, $3, $1, $2); + } + | function_arglist_nonbackup_reparse REPARSE lyric_element_music + { + $$ = check_scheme_arg (parser, @3, $3, $1, $2); + } + | function_arglist_nonbackup_reparse REPARSE symbol_list_arg + { + $$ = check_scheme_arg (parser, @3, $3, $1, $2); + } + ; + +function_arglist_nonbackup_reparse: + EXPECT_OPTIONAL EXPECT_SCM function_arglist SCM_IDENTIFIER + { + $$ = $3; + SCM res = try_string_variants ($2, $4); + if (!SCM_UNBNDP (res)) + if (scm_is_pair (res)) + MYREPARSE (@4, $2, SYMBOL_LIST, res); + else + MYREPARSE (@4, $2, SCM_ARG, res); + else if (scm_is_true + (scm_call_1 + ($2, make_music_from_simple + (parser, @4, $4)))) + MYREPARSE (@4, $2, STRING, $4); + else + MYREPARSE (@4, $2, SCM_ARG, $4); + } + | EXPECT_OPTIONAL EXPECT_SCM function_arglist STRING + { + $$ = $3; + SCM res = try_string_variants ($2, $4); + if (!SCM_UNBNDP (res)) + if (scm_is_pair (res)) + MYREPARSE (@4, $2, SYMBOL_LIST, res); + else + MYREPARSE (@4, $2, SCM_ARG, res); + else if (scm_is_true + (scm_call_1 + ($2, make_music_from_simple + (parser, @4, $4)))) + MYREPARSE (@4, $2, STRING, $4); + else + MYREPARSE (@4, $2, SCM_ARG, $4); + } + | EXPECT_OPTIONAL EXPECT_SCM function_arglist full_markup + { + $$ = $3; + if (scm_is_true (scm_call_1 ($2, $4))) + MYREPARSE (@4, $2, SCM_ARG, $4); + else if (scm_is_true + (scm_call_1 + ($2, make_music_from_simple + (parser, @4, $4)))) + MYREPARSE (@4, $2, STRING, $4); + else + MYREPARSE (@4, $2, SCM_ARG, $4); + } ; function_arglist_keep: @@ -1257,7 +1458,7 @@ function_arglist_backup: $$ = scm_cons ($4, $3); } else { $$ = scm_cons (loc_on_music (@3, $1), $3); - MYBACKUP (SCM_IDENTIFIER, $4, @4); + MYBACKUP (SCM_ARG, $4, @4); } } | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed_keep post_event_nofinger @@ -1270,21 +1471,13 @@ function_arglist_backup: MYBACKUP (EVENT_IDENTIFIER, $4, @4); } } - | EXPECT_OPTIONAL EXPECT_SCM function_arglist_keep lyric_element + | EXPECT_OPTIONAL EXPECT_SCM function_arglist_keep full_markup { - // There is no point interpreting a lyrics string as - // an event, since we don't allow music possibly - // followed by durations or postevent into closed - // music, and we only accept closed music in optional - // arguments at the moment. If this changes, more - // complex schemes might become interesting here as - // well: see how we do this at the mandatory argument - // point. if (scm_is_true (scm_call_1 ($2, $4))) $$ = scm_cons ($4, $3); else { $$ = scm_cons (loc_on_music (@3, $1), $3); - MYBACKUP (LYRICS_STRING, $4, @4); + MYBACKUP (LYRIC_ELEMENT, $4, @4); } } | EXPECT_OPTIONAL EXPECT_SCM function_arglist_closed_keep UNSIGNED @@ -1356,6 +1549,7 @@ function_arglist_backup: MYREPARSE (@5, $2, REAL, n); $$ = $3; } else { + $$ = scm_cons (loc_on_music (@3, $1), $3); MYBACKUP (REAL, n, @5); } } @@ -1365,6 +1559,7 @@ function_arglist_backup: if (scm_is_true (scm_call_1 ($2, n))) { $$ = scm_cons (n, $3); } else { + $$ = scm_cons (loc_on_music (@3, $1), $3); MYBACKUP (NUMBER_IDENTIFIER, n, @5); } } @@ -1376,20 +1571,49 @@ function_arglist_backup: { $$ = scm_cons ($4, $3); } + | EXPECT_OPTIONAL EXPECT_SCM function_arglist_keep SCM_IDENTIFIER + { + SCM res = try_string_variants ($2, $4); + if (!SCM_UNBNDP (res)) + if (scm_is_pair (res)) { + $$ = $3; + MYREPARSE (@4, $2, SYMBOL_LIST, res); + } + else + $$ = scm_cons (res, $3); + else { + $$ = scm_cons (loc_on_music (@3, $1), $3); + MYBACKUP (SCM_IDENTIFIER, $4, @4); + } + } + | EXPECT_OPTIONAL EXPECT_SCM function_arglist_keep STRING + { + SCM res = try_string_variants ($2, $4); + if (!SCM_UNBNDP (res)) + if (scm_is_pair (res)) { + $$ = $3; + MYREPARSE (@4, $2, SYMBOL_LIST, res); + } + else + $$ = scm_cons (res, $3); + else { + $$ = scm_cons (loc_on_music (@3, $1), $3); + MYBACKUP (STRING, $4, @4); + } + } | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup BACKUP { $$ = scm_cons ($1, $3); MYBACKUP(0, SCM_UNDEFINED, @3); } - | function_arglist_backup REPARSE embedded_scm_arg_closed + | function_arglist_backup REPARSE bare_number { $$ = check_scheme_arg (parser, @3, $3, $1, $2); } - | function_arglist_backup REPARSE bare_number + | function_arglist_backup REPARSE symbol_list_arg { - $$ = check_scheme_arg (parser, @3, - $3, $1, $2); + $$ = check_scheme_arg (parser, @3, $3, $1, $2); } ; @@ -1420,65 +1644,97 @@ function_arglist_common: $$ = check_scheme_arg (parser, @3, $3, $2, $1); } - | function_arglist_common_minus - | function_arglist_common_lyric + | EXPECT_SCM function_arglist_closed_optional '-' NUMBER_IDENTIFIER + { + SCM n = scm_difference ($4, SCM_UNDEFINED); + $$ = check_scheme_arg (parser, @4, n, $2, $1); + } + | function_arglist_common_reparse REPARSE SCM_ARG + { + $$ = check_scheme_arg (parser, @3, + $3, $1, $2); + } + | function_arglist_common_reparse REPARSE lyric_element_music + { + $$ = check_scheme_arg (parser, @3, + $3, $1, $2); + } + | function_arglist_common_reparse REPARSE bare_number + { + $$ = check_scheme_arg (parser, @3, + $3, $1, $2); + } + | function_arglist_common_reparse REPARSE symbol_list_arg + { + $$ = check_scheme_arg (parser, @3, $3, $1, $2); + } ; -function_arglist_common_lyric: - EXPECT_SCM function_arglist_optional lyric_element +function_arglist_common_reparse: + EXPECT_SCM function_arglist_optional SCM_IDENTIFIER { - // We check how the predicate thinks about a lyrics - // event or about a markup. If it accepts neither, we - // backup the original token. Otherwise we commit to - // taking the token. Depending on what the predicate - // is willing to accept, we interpret as a string, as - // a lyric event, or ambiguously (meaning that if - // something looking like a duration or post event - // follows, we take the event, otherwise the string). - SCM lyric_event = MAKE_SYNTAX ("lyric-event", @3, $3, - parser->default_duration_.smobbed_copy ()); - if (scm_is_true (scm_call_1 ($1, $3))) - if (scm_is_true (scm_call_1 ($1, lyric_event))) - { - $$ = $2; - MYREPARSE (@3, $1, LYRICS_STRING, $3); - } else { - $$ = scm_cons ($3, $2); - } - else if (scm_is_true (scm_call_1 ($1, lyric_event))) - { - $$ = $2; + $$ = $2; + SCM res = try_string_variants ($1, $3); + if (!SCM_UNBNDP (res)) + if (scm_is_pair (res)) + MYREPARSE (@3, $1, SYMBOL_LIST, res); + else + MYREPARSE (@3, $1, SCM_ARG, res); + else if (scm_is_true + (scm_call_1 + ($1, make_music_from_simple (parser, @3, $3)))) MYREPARSE (@3, $1, LYRIC_ELEMENT, $3); - } else { + else // This is going to flag a syntax error, we // know the predicate to be false. - check_scheme_arg (parser, @3, - $3, $2, $1); - } + MYREPARSE (@3, $1, SCM_ARG, $3); } - | function_arglist_common_lyric REPARSE lyric_element_arg + | EXPECT_SCM function_arglist_optional STRING { - // This should never be false - $$ = check_scheme_arg (parser, @3, - $3, $1, $2); + $$ = $2; + SCM res = try_string_variants ($1, $3); + if (!SCM_UNBNDP (res)) + if (scm_is_pair (res)) + MYREPARSE (@3, $1, SYMBOL_LIST, res); + else + MYREPARSE (@3, $1, SCM_ARG, res); + else if (scm_is_true + (scm_call_1 + ($1, make_music_from_simple (parser, @3, $3)))) + MYREPARSE (@3, $1, LYRIC_ELEMENT, $3); + else + // This is going to flag a syntax error, we + // know the predicate to be false. + MYREPARSE (@3, $1, SCM_ARG, $3); } - ; - -function_arglist_common_minus: - EXPECT_SCM function_arglist_closed_optional '-' UNSIGNED + | EXPECT_SCM function_arglist_optional full_markup { + $$ = $2; + if (scm_is_true (scm_call_1 ($1, $3))) + MYREPARSE (@3, $1, SCM_ARG, $3); + else if (scm_is_true + (scm_call_1 + ($1, make_music_from_simple (parser, @3, $3)))) + MYREPARSE (@3, $1, LYRIC_ELEMENT, $3); + else + // This is going to flag a syntax error, we + // know the predicate to be false. + MYREPARSE (@3, $1, SCM_ARG, $3); + } + | EXPECT_SCM function_arglist_closed_optional '-' UNSIGNED + { + $$ = $2; SCM n = scm_difference ($4, SCM_UNDEFINED); - if (scm_is_true (scm_call_1 ($1, n))) { - $$ = $2; + if (scm_is_true (scm_call_1 ($1, n))) MYREPARSE (@4, $1, REAL, n); - } else { + else { Music *t = MY_MAKE_MUSIC ("FingeringEvent", @4); t->set_property ("digit", $4); - $$ = t->unprotect (); - if (scm_is_true (scm_call_1 ($1, $$))) - $$ = scm_cons ($$, $2); + SCM m = t->unprotect (); + if (scm_is_true (scm_call_1 ($1, m))) + MYREPARSE (@4, $1, SCM_ARG, m); else - $$ = check_scheme_arg (parser, @3, n, $2, $1); + MYREPARSE (@4, $1, SCM_ARG, $4); } } @@ -1488,15 +1744,6 @@ function_arglist_common_minus: SCM n = scm_difference ($4, SCM_UNDEFINED); MYREPARSE (@4, $1, REAL, n); } - | EXPECT_SCM function_arglist_closed_optional '-' NUMBER_IDENTIFIER - { - SCM n = scm_difference ($4, SCM_UNDEFINED); - $$ = check_scheme_arg (parser, @4, n, $2, $1); - } - | function_arglist_common_minus REPARSE bare_number - { - $$ = check_scheme_arg (parser, @3, $3, $1, $2); - } ; function_arglist_closed: @@ -1516,28 +1763,6 @@ function_arglist_closed_common: $$ = check_scheme_arg (parser, @3, $3, $2, $1); } - | EXPECT_SCM function_arglist_closed_optional '-' UNSIGNED - { - SCM n = scm_difference ($4, SCM_UNDEFINED); - if (scm_is_true (scm_call_1 ($1, n))) { - $$ = scm_cons (n, $2); - } else { - Music *t = MY_MAKE_MUSIC ("FingeringEvent", @4); - t->set_property ("digit", $4); - $$ = t->unprotect (); - if (scm_is_true (scm_call_1 ($1, $$))) - $$ = scm_cons ($$, $2); - else - $$ = check_scheme_arg (parser, @3, n, $2, $1); - } - - } - | EXPECT_SCM function_arglist_closed_optional '-' REAL - { - $$ = check_scheme_arg (parser, @3, - scm_difference ($4, SCM_UNDEFINED), - $2, $1); - } | EXPECT_SCM function_arglist_closed_optional '-' NUMBER_IDENTIFIER { $$ = check_scheme_arg (parser, @3, @@ -1554,10 +1779,19 @@ function_arglist_closed_common: $$ = check_scheme_arg (parser, @3, $3, $2, $1); } - | EXPECT_SCM function_arglist_optional lyric_element + | function_arglist_common_reparse REPARSE SCM_ARG { $$ = check_scheme_arg (parser, @3, - $3, $2, $1); + $3, $1, $2); + } + | function_arglist_common_reparse REPARSE bare_number + { + $$ = check_scheme_arg (parser, @3, + $3, $1, $2); + } + | function_arglist_common_reparse REPARSE symbol_list_arg + { + $$ = check_scheme_arg (parser, @3, $3, $1, $2); } ; @@ -1652,14 +1886,14 @@ complex_music: ; complex_music_prefix: - CONTEXT simple_string optional_id optional_context_mod { + CONTEXT symbol optional_id optional_context_mod { Context_mod *ctxmod = unsmob_context_mod ($4); SCM mods = SCM_EOL; if (ctxmod) mods = ctxmod->get_mods (); $$ = START_MAKE_SYNTAX ("context-specification", $2, $3, mods, SCM_BOOL_F); } - | NEWCONTEXT simple_string optional_id optional_context_mod { + | NEWCONTEXT symbol optional_id optional_context_mod { Context_mod *ctxmod = unsmob_context_mod ($4); SCM mods = SCM_EOL; if (ctxmod) @@ -1789,39 +2023,90 @@ context_change: ; -property_path_revved: - embedded_scm_closed { - $$ = scm_cons ($1, SCM_EOL); - } - | property_path_revved embedded_scm_closed { - $$ = scm_cons ($2, $1); - } - ; - property_path: - property_path_revved { + symbol_list_rev { $$ = scm_reverse_x ($1, SCM_EOL); } + | symbol_list_rev property_path { + $$ = scm_reverse_x ($1, $2); + } ; property_operation: - STRING '=' scalar { - $$ = scm_list_3 (ly_symbol2scm ("assign"), - scm_string_to_symbol ($1), $3); + symbol '=' scalar { + $$ = scm_list_3 (ly_symbol2scm ("assign"), $1, $3); + } + | UNSET symbol { + $$ = scm_list_2 (ly_symbol2scm ("unset"), $2); } - | UNSET simple_string { - $$ = scm_list_2 (ly_symbol2scm ("unset"), - scm_string_to_symbol ($2)); + | OVERRIDE property_path '=' scalar { + if (scm_ilength ($2) < 2) { + parser->parser_error (@2, _("bad grob property path")); + $$ = SCM_UNDEFINED; + } else { + $$ = scm_cons (ly_symbol2scm ("push"), + scm_cons2 (scm_car ($2), + $4, + scm_cdr ($2))); + } } - | OVERRIDE simple_string property_path '=' scalar { - $$ = scm_append (scm_list_2 (scm_list_3 (ly_symbol2scm ("push"), - scm_string_to_symbol ($2), $5), - $3)); + | REVERT revert_arg { + $$ = scm_cons (ly_symbol2scm ("pop"), $2); + } + ; + +// This is all quite awkward for the sake of substantial backward +// compatibility while at the same time allowing a more "natural" form +// of specification not separating grob specification from grob +// property path. The purpose of this definition of revert_arg is to +// allow the symbol list which specifies grob and property to revert +// to be optionally be split into two parts after the grob (which in +// this case is just the first element of the list). symbol_list_part +// is only one path component, but it can be parsed without lookahead, +// so we can follow it with a synthetic BACKUP token when needed. If +// the first symbol_list_part already contains multiple elements (only +// possible if a Scheme expression provides them), we just parse for +// additional elements introduced by '.', which is what the +// SYMBOL_LIST backup in connection with the immediately following +// rule using symbol_list_arg does. +// +// As long as we don't have our coffers filled with both grob and at +// least one grob property specification, the rest of the required +// symbol list chain may be provided either with or without a leading +// dot. This is for both allowing the traditional +// \revert Accidental #'color +// as well as well as the "naive" form +// \revert Accidental.color + +revert_arg: + revert_arg_backup BACKUP symbol_list_arg + { + $$ = $3; + } + ; + +revert_arg_backup: + revert_arg_part + { + if (scm_is_null ($1) + || scm_is_null (scm_cdr ($1))) + MYBACKUP (SCM_ARG, $1, @1); + else + MYBACKUP (SYMBOL_LIST, scm_reverse_x ($1, SCM_EOL), @1); } - | REVERT simple_string embedded_scm { - $$ = scm_list_3 (ly_symbol2scm ("pop"), - scm_string_to_symbol ($2), $3); + ; + +// revert_arg_part delivers results in reverse +revert_arg_part: + symbol_list_part + | revert_arg_backup BACKUP SCM_ARG '.' symbol_list_part + { + $$ = scm_append_x (scm_list_2 ($5, $3)); } + | revert_arg_backup BACKUP SCM_ARG symbol_list_part + { + $$ = scm_append_x (scm_list_2 ($4, $3)); + } ; context_def_mod: @@ -1859,52 +2144,141 @@ context_mod: } ; -context_prop_spec: - simple_string { - if (!is_regular_identifier ($1)) +// If defined, at least two members. +grob_prop_spec: + symbol_list_rev + { + SCM l = scm_reverse_x ($1, SCM_EOL); + if (scm_is_pair (l) + && to_boolean + (scm_object_property (scm_car (l), + ly_symbol2scm ("is-grob?")))) + l = scm_cons (ly_symbol2scm ("Bottom"), l); + if (scm_is_null (l) || scm_is_null (scm_cdr (l))) { + parser->parser_error (@1, _ ("bad grob property path")); + l = SCM_UNDEFINED; + } + $$ = l; + } + ; + +// If defined, at least three members +grob_prop_path: + grob_prop_spec + { + if (!SCM_UNBNDP ($1) && scm_is_null (scm_cddr ($1))) { - @$.error (_("Grob name should be alphanumeric")); + parser->parser_error (@1, _ ("bad grob property path")); + $$ = SCM_UNDEFINED; + } + } + | grob_prop_spec property_path + { + if (!SCM_UNBNDP ($1)) { + $$ = scm_append_x (scm_list_2 ($1, $2)); + if (scm_is_null (scm_cddr ($$))) { + parser->parser_error (@$, _ ("bad grob property path")); + $$ = SCM_UNDEFINED; + } } - $$ = scm_list_2 (ly_symbol2scm ("Bottom"), - scm_string_to_symbol ($1)); } - | simple_string '.' simple_string { - $$ = scm_list_2 (scm_string_to_symbol ($1), - scm_string_to_symbol ($3)); + ; + +// Exactly two elements or undefined +context_prop_spec: + symbol_list_rev + { + SCM l = scm_reverse_x ($1, SCM_EOL); + switch (scm_ilength (l)) { + case 1: + l = scm_cons (ly_symbol2scm ("Bottom"), l); + case 2: + break; + default: + parser->parser_error (@1, _ ("bad context property path")); + l = SCM_UNDEFINED; + } + $$ = l; } ; simple_music_property_def: - OVERRIDE context_prop_spec property_path '=' scalar { - $$ = scm_append (scm_list_2 (scm_list_n (scm_car ($2), - ly_symbol2scm ("OverrideProperty"), - scm_cadr ($2), - $5, SCM_UNDEFINED), - $3)); - } - | REVERT context_prop_spec embedded_scm { - $$ = scm_list_4 (scm_car ($2), - ly_symbol2scm ("RevertProperty"), - scm_cadr ($2), - $3); + OVERRIDE grob_prop_path '=' scalar { + if (SCM_UNBNDP ($2)) + $$ = SCM_UNDEFINED; + else { + $$ = scm_list_5 (scm_car ($2), + ly_symbol2scm ("OverrideProperty"), + scm_cadr ($2), + $4, + scm_cddr ($2)); + } + } + | REVERT simple_revert_context revert_arg { + $$ = scm_list_4 ($2, + ly_symbol2scm ("RevertProperty"), + scm_car ($3), + scm_cdr ($3)); } | SET context_prop_spec '=' scalar { - $$ = scm_list_4 (scm_car ($2), - ly_symbol2scm ("PropertySet"), - scm_cadr ($2), - $4); + if (SCM_UNBNDP ($2)) + $$ = SCM_UNDEFINED; + else + $$ = scm_list_4 (scm_car ($2), + ly_symbol2scm ("PropertySet"), + scm_cadr ($2), + $4); } | UNSET context_prop_spec { - $$ = scm_list_3 (scm_car ($2), - ly_symbol2scm ("PropertyUnset"), - scm_cadr ($2)); + if (SCM_UNBNDP ($2)) + $$ = SCM_UNDEFINED; + else + $$ = scm_list_3 (scm_car ($2), + ly_symbol2scm ("PropertyUnset"), + scm_cadr ($2)); + } + ; + + +// This is all quite awkward for the sake of substantial backward +// compatibility while at the same time allowing a more "natural" form +// of specification not separating grob specification from grob +// property path. The purpose of this definition of +// simple_revert_context is to allow the symbol list which specifies +// grob and property to revert to be optionally be split into two +// parts after the grob (which may be preceded by a context +// specification, a case which we distinguish by checking whether the +// first symbol is a valid grob symbol instead). +// +// See revert_arg above for the main work horse of this arrangement. +// simple_revert_context just caters for the context and delegates the +// rest of the job to revert_arg. + +simple_revert_context: + symbol_list_part + { + $1 = scm_reverse_x ($1, SCM_EOL); + if (scm_is_null ($1) + || to_boolean + (scm_object_property (scm_car ($1), + ly_symbol2scm ("is-grob?")))) { + $$ = ly_symbol2scm ("Bottom"); + parser->lexer_->push_extra_token (SCM_IDENTIFIER, $1); + } else { + $$ = scm_car ($1); + parser->lexer_->push_extra_token (SCM_IDENTIFIER, + scm_cdr ($1)); + } } ; music_property_def: simple_music_property_def { - $$ = LOWLEVEL_MAKE_SYNTAX (ly_lily_module_constant ("property-operation"), scm_cons2 (parser->self_scm (), make_input (@$), $1)); + if (SCM_UNBNDP ($1)) + $$ = MAKE_SYNTAX ("void-music", @1); + else + $$ = LOWLEVEL_MAKE_SYNTAX (ly_lily_module_constant ("property-operation"), scm_cons2 (parser->self_scm (), make_input (@$), $1)); } ; @@ -1913,25 +2287,11 @@ string: $$ = $1; } | full_markup - | string '+' string { - if (!scm_is_string ($1)) { - parser->parser_error (@1, (_ ("simple string expected"))); - $1 = scm_string (SCM_EOL); - } - if (!scm_is_string ($3)) { - parser->parser_error (@3, (_ ("simple string expected"))); - $3 = scm_string (SCM_EOL); - } - $$ = scm_string_append (scm_list_2 ($1, $3)); - } ; simple_string: STRING { $$ = $1; } - | LYRICS_STRING { - $$ = $1; - } | embedded_scm_bare { if (scm_is_string ($1)) { @@ -1943,8 +2303,29 @@ simple_string: STRING { } ; +symbol: + STRING { + $$ = scm_string_to_symbol ($1); + } + | embedded_scm_bare + { + // This is a bit of overkill but makes the same + // routine responsible for all symbol interpretations. + $$ = try_string_variants (ly_lily_module_constant ("symbol?"), + $1); + if (SCM_UNBNDP ($$)) + { + parser->parser_error (@1, (_ ("symbol expected"))); + // Generate a unique symbol in case it is used + // for an assignment or similar + $$ = scm_make_symbol (ly_string2scm ("undefined")); + } + } + ; + scalar: embedded_scm_arg + | SCM_IDENTIFIER | bare_number | FRACTION | lyric_element @@ -1952,6 +2333,7 @@ scalar: scalar_closed: embedded_scm_arg_closed + | SCM_IDENTIFIER | bare_number | FRACTION | lyric_element @@ -2110,40 +2492,10 @@ command_element: command_event { $$ = $1; } - | E_BRACKET_OPEN { - Music *m = MY_MAKE_MUSIC ("LigatureEvent", @$); - m->set_property ("span-direction", scm_from_int (START)); - $$ = m->unprotect(); - } - | E_BRACKET_CLOSE { - Music *m = MY_MAKE_MUSIC ("LigatureEvent", @$); - m->set_property ("span-direction", scm_from_int (STOP)); - $$ = m->unprotect (); - } - | E_BACKSLASH { - $$ = MAKE_SYNTAX ("voice-separator", @$); - } - | '|' { - SCM pipe = parser->lexer_->lookup_identifier ("pipeSymbol"); - - Music *m = unsmob_music (pipe); - if (m) - { - m = m->clone (); - m->set_spot (@$); - $$ = m->unprotect (); - } - else - $$ = MAKE_SYNTAX ("bar-check", @$); - - } ; command_event: - E_TILDE { - $$ = MY_MAKE_MUSIC ("PesOrFlexaEvent", @$)->unprotect (); - } - | tempo_event { + tempo_event { $$ = $1; } ; @@ -2154,8 +2506,22 @@ post_events: $$ = SCM_EOL; } | post_events post_event { - unsmob_music ($2)->set_spot (@2); - $$ = scm_cons ($2, $$); + $$ = $1; + if (Music *m = unsmob_music ($2)) + { + if (m->is_mus_type ("post-event-wrapper")) + { + for (SCM p = m->get_property ("elements"); + scm_is_pair (p); + p = scm_cdr (p)) + { + $$ = scm_cons (scm_car (p), $$); + } + } else { + m->set_spot (@2); + $$ = scm_cons ($2, $$); + } + } } ; @@ -2165,7 +2531,10 @@ post_event_nofinger: } | script_dir music_function_call_closed { $$ = $2; - if (!SCM_UNBNDP ($1)) + if (!unsmob_music ($2)->is_mus_type ("post-event")) { + parser->parser_error (@2, _ ("post-event expected")); + $$ = SCM_UNSPECIFIED; + } else if (!SCM_UNBNDP ($1)) { unsmob_music ($$)->set_property ("direction", $1); } @@ -2223,55 +2592,8 @@ string_number_event: } ; -direction_less_char: - '[' { - $$ = ly_symbol2scm ("bracketOpenSymbol"); - } - | ']' { - $$ = ly_symbol2scm ("bracketCloseSymbol"); - } - | '~' { - $$ = ly_symbol2scm ("tildeSymbol"); - } - | '(' { - $$ = ly_symbol2scm ("parenthesisOpenSymbol"); - } - | ')' { - $$ = ly_symbol2scm ("parenthesisCloseSymbol"); - } - | E_EXCLAMATION { - $$ = ly_symbol2scm ("escapedExclamationSymbol"); - } - | E_OPEN { - $$ = ly_symbol2scm ("escapedParenthesisOpenSymbol"); - } - | E_CLOSE { - $$ = ly_symbol2scm ("escapedParenthesisCloseSymbol"); - } - | E_ANGLE_CLOSE { - $$ = ly_symbol2scm ("escapedBiggerSymbol"); - } - | E_ANGLE_OPEN { - $$ = ly_symbol2scm ("escapedSmallerSymbol"); - } - ; - direction_less_event: - direction_less_char { - SCM predefd = parser->lexer_->lookup_identifier_symbol ($1); - Music *m = 0; - if (unsmob_music (predefd)) - { - m = unsmob_music (predefd)->clone (); - m->set_spot (@$); - } - else - { - m = MY_MAKE_MUSIC ("Music", @$); - } - $$ = m->unprotect (); - } - | string_number_event + string_number_event | EVENT_IDENTIFIER { $$ = $1; } @@ -2377,13 +2699,7 @@ gen_text_def: make_simple_markup ($1)); $$ = t->unprotect (); } - | LYRICS_STRING { - Music *t = MY_MAKE_MUSIC ("TextScriptEvent", @$); - t->set_property ("text", - make_simple_markup ($1)); - $$ = t->unprotect (); - } - | embedded_scm_bare + | embedded_scm_closed { Music *m = unsmob_music ($1); if (m && m->is_mus_type ("post-event")) @@ -2415,8 +2731,8 @@ script_abbreviation: | '-' { $$ = scm_from_locale_string ("Dash"); } - | '|' { - $$ = scm_from_locale_string ("Bar"); + | '!' { + $$ = scm_from_locale_string ("Bang"); } | ANGLE_CLOSE { $$ = scm_from_locale_string ("Larger"); @@ -2573,38 +2889,23 @@ bass_figure: } | bass_figure figured_bass_modification { Music *m = unsmob_music ($1); - if ($2 == ly_symbol2scm ("plus")) - { - m->set_property ("augmented", SCM_BOOL_T); - } - else if ($2 == ly_symbol2scm ("slash")) - { - m->set_property ("diminished", SCM_BOOL_T); - } - else if ($2 == ly_symbol2scm ("exclamation")) - { - m->set_property ("no-continuation", SCM_BOOL_T); - } - else if ($2 == ly_symbol2scm ("backslash")) - { - m->set_property ("augmented-slash", SCM_BOOL_T); - } + m->set_property ($2, SCM_BOOL_T); } ; figured_bass_modification: E_PLUS { - $$ = ly_symbol2scm ("plus"); + $$ = ly_symbol2scm ("augmented"); } | E_EXCLAMATION { - $$ = ly_symbol2scm ("exclamation"); + $$ = ly_symbol2scm ("no-continuation"); } | '/' { - $$ = ly_symbol2scm ("slash"); + $$ = ly_symbol2scm ("diminished"); } | E_BACKSLASH { - $$ = ly_symbol2scm ("backslash"); + $$ = ly_symbol2scm ("augmented-slash"); } ; @@ -2714,39 +3015,19 @@ simple_chord_elements: ; lyric_element: - lyric_markup { + full_markup { $$ = $1; } - | LYRICS_STRING { + | STRING { $$ = $1; } + | LYRIC_ELEMENT ; -lyric_element_arg: - lyric_element - | lyric_element multiplied_duration post_events { - $$ = MAKE_SYNTAX ("lyric-event", @$, $1, $2); - if (scm_is_pair ($3)) - unsmob_music ($$)->set_property - ("articulations", scm_reverse_x ($3, SCM_EOL)); - } - | lyric_element post_event post_events { - $$ = MAKE_SYNTAX ("lyric-event", @$, $1, - parser->default_duration_.smobbed_copy ()); - unsmob_music ($$)->set_property - ("articulations", scm_cons ($2, scm_reverse_x ($3, SCM_EOL))); - } - | LYRIC_ELEMENT optional_notemode_duration post_events { - $$ = MAKE_SYNTAX ("lyric-event", @$, $1, $2); - if (scm_is_pair ($3)) - unsmob_music ($$)->set_property - ("articulations", scm_reverse_x ($3, SCM_EOL)); - } - ; - - lyric_element_music: lyric_element optional_notemode_duration post_events { + if (!parser->lexer_->is_lyric_state ()) + parser->parser_error (@1, _ ("have to be in Lyric mode for lyrics")); $$ = MAKE_SYNTAX ("lyric-event", @$, $1, $2); if (scm_is_pair ($3)) unsmob_music ($$)->set_property @@ -2823,7 +3104,7 @@ tempo_range: UNSIGNED { $$ = $1; } - | UNSIGNED '~' UNSIGNED { + | UNSIGNED '-' UNSIGNED { $$ = scm_cons ($1, $3); } ; @@ -2907,19 +3188,6 @@ questions: } ; -/* -This should be done more dynamically if possible. -*/ - -lyric_markup: - LYRIC_MARKUP - { parser->lexer_->push_markup_state (); } - markup_top { - $$ = $3; - parser->lexer_->pop_state (); - } - ; - full_markup_list: MARKUPLIST { parser->lexer_->push_markup_state (); } @@ -2939,11 +3207,13 @@ full_markup: ; markup_top: - markup_list { + simple_markup_list { $$ = scm_list_2 (ly_lily_module_constant ("line-markup"), $1); } - | markup_head_1_list simple_markup { - $$ = scm_car (scm_call_2 (ly_lily_module_constant ("map-markup-command-list"), $1, scm_list_1 ($2))); + | markup_head_1_list simple_markup + { + $$ = scm_car (MAKE_SYNTAX ("composed-markup-list", + @2, $1, scm_list_1 ($2))); } | simple_markup { $$ = $1; @@ -2965,11 +3235,15 @@ markup_scm: ; -markup_list: +simple_markup_list: markup_composed_list { $$ = $1; } - | markup_braced_list { + | markup_uncomposed_list + ; + +markup_uncomposed_list: + markup_braced_list { $$ = $1; } | markup_command_list { @@ -2981,10 +3255,28 @@ markup_list: } ; -markup_composed_list: - markup_head_1_list markup_braced_list { - $$ = scm_call_2 (ly_lily_module_constant ("map-markup-command-list"), $1, $2); +markup_list: + simple_markup_list + | markup_score + { + $$ = scm_list_1 (scm_list_2 (ly_lily_module_constant ("score-lines-markup-list"), $1)); + } + ; + +markup_score: + SCORE { + SCM nn = parser->lexer_->lookup_identifier ("pitchnames"); + parser->lexer_->push_note_state (nn); + } '{' score_body '}' { + $$ = $4; + parser->lexer_->pop_state (); + } + ; +markup_composed_list: + markup_head_1_list markup_uncomposed_list { + $$ = MAKE_SYNTAX ("composed-markup-list", + @2, $1, $2); } ; @@ -2999,7 +3291,7 @@ markup_braced_list_body: | markup_braced_list_body markup { $$ = scm_cons ($2, $1); } - | markup_braced_list_body markup_list { + | markup_braced_list_body simple_markup_list { $$ = scm_reverse_x ($2, $1); } ; @@ -3048,13 +3340,6 @@ simple_markup: STRING { $$ = make_simple_markup ($1); } - | SCORE { - SCM nn = parser->lexer_->lookup_identifier ("pitchnames"); - parser->lexer_->push_note_state (nn); - } '{' score_body '}' { - $$ = scm_list_2 (ly_lily_module_constant ("score-markup"), $4); - parser->lexer_->pop_state (); - } | MARKUP_FUNCTION markup_command_basic_arguments { $$ = scm_cons ($1, scm_reverse_x ($2, SCM_EOL)); } @@ -3062,12 +3347,17 @@ simple_markup: { $$ = $2; } + | markup_score + { + $$ = scm_list_2 (ly_lily_module_constant ("score-markup"), $1); + } ; markup: - markup_head_1_list simple_markup { - SCM mapper = ly_lily_module_constant ("map-markup-command-list"); - $$ = scm_car (scm_call_2 (mapper, $1, scm_list_1 ($2))); + markup_head_1_list simple_markup + { + $$ = scm_car (MAKE_SYNTAX ("composed-markup-list", + @2, $1, scm_list_1 ($2))); } | simple_markup { $$ = $1; @@ -3123,18 +3413,9 @@ Lily_lexer::try_special_identifiers (SCM *destination, SCM sid) *destination = unsmob_context_mod (sid)->smobbed_copy (); return CONTEXT_MOD_IDENTIFIER; - } else if (unsmob_score (sid)) { - Score *score = new Score (*unsmob_score (sid)); - *destination = score->self_scm (); - - score->unprotect (); - return SCORE_IDENTIFIER; } else if (Music *mus = unsmob_music (sid)) { mus = mus->clone (); *destination = mus->self_scm (); - unsmob_music (*destination)-> - set_property ("origin", make_input (last_input_)); - bool is_event = mus->is_mus_type ("post-event"); mus->unprotect (); return is_event ? EVENT_IDENTIFIER : MUSIC_IDENTIFIER; @@ -3172,14 +3453,34 @@ get_next_unique_lyrics_context_id () return scm_from_locale_string (s); } +// check_scheme_arg checks one argument with a given predicate for use +// in an argument list and throws a syntax error if it is unusable. +// The argument is prepended to the argument list in any case. After +// throwing a syntax error, the argument list is terminated with #f as +// its last cdr in order to mark it as uncallable while not losing +// track of its total length. +// +// There are a few special considerations: if optional argument disp +// is given (otherwise it defaults to SCM_UNDEFINED), it will be used +// instead of arg in a prospective error message. This is useful if +// arg is not the actual argument but rather a transformation of it. +// +// If arg itself is SCM_UNDEFINED, the predicate is considered false +// and an error message using disp is produced unconditionally. + SCM check_scheme_arg (Lily_parser *parser, Input loc, - SCM arg, SCM args, SCM pred) + SCM arg, SCM args, SCM pred, SCM disp) { - args = scm_cons (arg, args); - if (scm_is_true (scm_call_1 (pred, arg))) - return args; + if (SCM_UNBNDP (arg)) + args = scm_cons (disp, args); + else { + args = scm_cons (arg, args); + if (scm_is_true (scm_call_1 (pred, arg))) + return args; + } scm_set_cdr_x (scm_last_pair (args), SCM_EOL); - MAKE_SYNTAX ("argument-error", loc, scm_length (args), pred, arg); + MAKE_SYNTAX ("argument-error", loc, scm_length (args), pred, + SCM_UNBNDP (disp) ? arg : disp); scm_set_cdr_x (scm_last_pair (args), SCM_BOOL_F); return args; } @@ -3195,9 +3496,54 @@ SCM loc_on_music (Input loc, SCM arg) return arg; } +SCM +try_string_variants (SCM pred, SCM str) +{ + // a matching predicate is always ok + if (scm_is_true (scm_call_1 (pred, str))) + return str; + // a symbol may be interpreted as a list of symbols if it helps + if (scm_is_symbol (str)) { + str = scm_list_1 (str); + if (scm_is_true (scm_call_1 (pred, str))) + return str; + return SCM_UNDEFINED; + } + + // If this cannot be a string representation of a symbol list, + // we are through. + + if (!is_regular_identifier (str, true)) + return SCM_UNDEFINED; + + str = scm_string_split (str, SCM_MAKE_CHAR ('.')); + for (SCM p = str; scm_is_pair (p); p = scm_cdr (p)) + scm_set_car_x (p, scm_string_to_symbol (scm_car (p))); + + // Let's attempt the symbol list interpretation first. + + if (scm_is_true (scm_call_1 (pred, str))) + return str; + + // If there is just one symbol in the list, we might interpret + // it as a single symbol + + if (scm_is_null (scm_cdr (str))) + { + str = scm_car (str); + if (scm_is_true (scm_call_1 (pred, str))) + return str; + } + + return SCM_UNDEFINED; +} + bool -is_regular_identifier (SCM id) +is_regular_identifier (SCM id, bool multiple) { + if (!scm_is_string (id)) + return false; + string str = ly_scm2string (id); bool middle = false; @@ -3209,7 +3555,7 @@ is_regular_identifier (SCM id) || (c >= 'A' && c <= 'Z') || c > 0x7f) middle = true; - else if (middle && (c == '-' || c == '_')) + else if (middle && (c == '-' || c == '_' || (multiple && c == '.'))) middle = false; else return false; @@ -3223,17 +3569,19 @@ make_music_from_simple (Lily_parser *parser, Input loc, SCM simple) if (unsmob_music (simple)) return simple; if (parser->lexer_->is_note_state ()) { - Music *n = MY_MAKE_MUSIC ("NoteEvent", loc); - n->set_property ("duration", parser->default_duration_.smobbed_copy ()); - if (scm_is_symbol (simple)) + if (scm_is_symbol (simple)) { + Music *n = MY_MAKE_MUSIC ("NoteEvent", loc); + n->set_property ("duration", parser->default_duration_.smobbed_copy ()); n->set_property ("drum-type", simple); - else if (unsmob_pitch (simple)) + return n->unprotect (); + } + if (unsmob_pitch (simple)) { + Music *n = MY_MAKE_MUSIC ("NoteEvent", loc); + n->set_property ("duration", parser->default_duration_.smobbed_copy ()); n->set_property ("pitch", simple); - else { - n->unprotect (); - return simple; + return n->unprotect (); } - return n->unprotect (); + return simple; } else if (parser->lexer_->is_lyric_state ()) { if (Text_interface::is_markup (simple)) return MAKE_SYNTAX ("lyric-event", loc, simple,