and@w{ }@code{#}.
It extracts the Lilypond code block and generates a call to the
-LilyPond @code{parser} which is executed at runtime to interpret the
-LilyPond code block. Any embedded Scheme expression is executed in
-the lexical environment of the Lilypond code block, so you have access
-to local variables and function parameters at the point the Lilypond
-code block is written.
+LilyPond @code{parser} which is executed at runtime to interpret
+the LilyPond code block. Any embedded Scheme expression is
+executed in the lexical environment of the Lilypond code block, so
+you have access to local variables and function parameters at the
+point the Lilypond code block is written. If @code{location}
+refers to a valid input location (which it usually does inside of
+music/@/scheme functions), all music generated inside the code
+block has its @samp{origin} set to @code{location}.
A LilyPond code block may contain anything that you can use on the right
side of an assignment. In addition, an empty LilyPond block corresponds
SCM scopes_;
SCM start_module_;
int hidden_state_;
+ Input override_input_;
SCM eval_scm (SCM, char extra_token = 0);
public:
SCM eval_scm_token (SCM sval) { return eval_scm (sval, '#'); }
Input last_input_;
Lily_lexer (Sources *, Lily_parser *);
- Lily_lexer (Lily_lexer const &, Lily_parser *);
+ Lily_lexer (Lily_lexer const &, Lily_parser *, SCM);
int yylex ();
void add_lexed_char (int);
void prepare_for_next_token ();
int try_special_identifiers (SCM *, SCM);
Input here_input () const;
+ Input const &override_input (Input const &) const;
void add_scope (SCM);
SCM set_current_scope ();
bool ignore_version_b_;
Lily_parser (Sources *sources);
- Lily_parser (Lily_parser const &, SCM closures = SCM_EOL);
+ Lily_parser (Lily_parser const &, SCM closures = SCM_EOL,
+ SCM location = SCM_BOOL_F);
DECLARE_SCHEME_CALLBACK (layout_description, ());
chordmodifier_tab_ = scm_make_vector (scm_from_int (1), SCM_EOL);
}
-Lily_lexer::Lily_lexer (Lily_lexer const &src, Lily_parser *parser)
+Lily_lexer::Lily_lexer (Lily_lexer const &src, Lily_parser *parser,
+ SCM override_input)
: Includable_lexer ()
{
parser_ = parser;
main_input_level_ = 0;
extra_tokens_ = SCM_EOL;
+ if (unsmob_input (override_input))
+ override_input_ = *unsmob_input (override_input);
smobify_self ();
return Input (*lexloc_);
}
+Input const &
+Lily_lexer::override_input (Input const &in) const
+{
+ return override_input_.get_source_file ()
+ ? override_input_ : in;
+}
+
void
Lily_lexer::prepare_for_next_token ()
{
}
LY_DEFINE (ly_parser_clone, "ly:parser-clone",
- 1, 1, 0, (SCM parser_smob, SCM closures),
+ 1, 2, 0, (SCM parser_smob, SCM closures, SCM location),
"Return a clone of @var{parser-smob}. An association list"
" of port positions to closures can be specified in @var{closures}"
" in order to have @code{$} and @code{#} interpreted in their original"
- " lexical environment.")
+ " lexical environment. If @var{location} is a valid location,"
+ " it becomes the source of all music expressions inside.")
{
LY_ASSERT_SMOB (Lily_parser, parser_smob, 1);
Lily_parser *parser = unsmob_lily_parser (parser_smob);
closures = SCM_EOL;
else
LY_ASSERT_TYPE (ly_is_list, closures, 2);
- Lily_parser *clone = new Lily_parser (*parser, closures);
+ Lily_parser *clone = new Lily_parser (*parser, closures, location);
return clone->unprotect ();
}
lexer_->unprotect ();
}
-Lily_parser::Lily_parser (Lily_parser const &src, SCM closures)
+Lily_parser::Lily_parser (Lily_parser const &src, SCM closures, SCM location)
{
lexer_ = 0;
sources_ = src.sources_;
smobify_self ();
if (src.lexer_)
{
- lexer_ = new Lily_lexer (*src.lexer_, this);
+ lexer_ = new Lily_lexer (*src.lexer_, this, location);
+ lexer_->unprotect ();
}
-
- lexer_->unprotect ();
}
Lily_parser::~Lily_parser ()
%{
-#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.
#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 ();
mus = mus->clone ();
*destination = mus->self_scm ();
unsmob_music (*destination)->
- set_property ("origin", make_input (last_input_));
+ set_property ("origin",
+ make_input (override_input (last_input_)));
bool is_event = mus->is_mus_type ("post-event");
mus->unprotect ();
#(note-names-language parser default-language)
#(ly:set-option 'old-relative #f)
+#(define location #f)
#(define toplevel-scores (list))
#(define toplevel-bookparts (list))
#(define $defaultheader #f)
(set! closures
(cons `(cons ,p (lambda () ,expr))
closures)))))))))))
- (define (embedded-lilypond parser lily-string filename line closures)
- (let* ((clone (ly:parser-clone parser closures))
+ (define (embedded-lilypond parser lily-string filename line
+ closures location)
+ (let* ((clone (ly:parser-clone parser closures location))
(result (ly:parse-string-expression clone lily-string
filename line)))
(if (ly:parser-has-error? clone)
(ly:parser-error parser (_ "error in #{ ... #}")))
result))
- (list embedded-lilypond 'parser lily-string filename line (cons 'list (reverse! closures)))))
+ (list embedded-lilypond
+ 'parser lily-string filename line
+ (cons 'list (reverse! closures))
+ 'location)))
(read-hash-extend #\{ read-lily-expression)