Compile_error exception, and remove output .texi.
* scm/define-music-properties.scm (all-music-properties): add
error-found
* lily/parser.yy (Music_list): add error-found to music with errors.
* lily/lily-parser.cc (LY_DEFINE): ignore scores with errors.
* lily/book.cc (process): ignore books with errors
* lily/include/score.hh (class Score): add error_found_ member.
2004-09-24 Han-Wen Nienhuys <hanwen@xs4all.nl>
+ * scripts/lilypond-book.py (Compile_error.process_include): catch
+ Compile_error exception, and remove output .texi.
+
+ * scm/define-music-properties.scm (all-music-properties): add
+ error-found
+
+ * lily/parser.yy (Music_list): add error-found to music with errors.
+
+ * lily/lily-parser.cc (LY_DEFINE): ignore scores with errors.
+
+ * lily/book.cc (process): ignore books with errors
+
+ * lily/include/score.hh (class Score): add error_found_ member.
+
* lily/drum-note-engraver.cc (try_music): idem.
* lily/note-heads-engraver.cc: remove start-playing-event.
* lily/part-combine-iterator.cc (Part_combine_iterator): use
BusyPlayingEvent to determine which voice was active last.
(unisono): use last active to where to get unisono information
- from.
-
+ from. This fixes: partcombine-rest.ly (again).
+v/v
* scm/part-combiner.scm (determine-split-list): cleanups
2004-09-23 Han-Wen Nienhuys <hanwen@xs4all.nl>
@itemize @bullet
+@item LilyPond does not try to produce output for files that
+have a parse error.
+
+@item @code{lilypond-book} will now remove any output files that
+contain failed music snippets.
+
@item The mode changing commands (@code{\chords}, @code{\lyrics}, etc.)
have been renamed to @code{\chordmode}, @code{\lyricmode}, etc. The
command @code{\chords} is an abbreviation for
Paper_book *
Book::process (String outname, Output_def *default_def)
{
+ bool error = false;
+ for (int i = 0; i < scores_.size(); i++)
+ error |= scores_[i]->error_found_;
+
+ if (error)
+ return 0;
+
Paper_book *paper_book = new Paper_book ();
Real scale = scm_to_double (bookpaper_->c_variable ("outputscale"));
public:
Link_array<Output_def> defs_;
SCM header_;
-
+ bool error_found_;
+
SCM get_music () const;
void set_music (SCM music, SCM parser);
Score ();
Lily_parser *parser = unsmob_my_lily_parser (parser_smob);
Score *score = unsmob_score (score_smob);
+ if (score->error_found_)
+ return SCM_UNSPECIFIED;
+
SCM_ASSERT_TYPE (parser, parser_smob, SCM_ARG1, __FUNCTION__, "parser");
SCM_ASSERT_TYPE (score, score_smob, SCM_ARG2, __FUNCTION__, "score");
Output_def *paper = get_paper (parser);
Paper_book* pb = book->process (outname.to_string (), paper);
+ if (pb)
+ {
+ pb->output (outname.to_string ());
+ scm_gc_unprotect_object (pb->self_scm ());
+ }
- pb->output (outname.to_string ());
-
scm_gc_unprotect_object (paper->self_scm ());
- scm_gc_unprotect_object (pb->self_scm ());
-
return SCM_UNSPECIFIED;
}
$$->header_ = $2;
}
| book_body error {
-
+ $$->bookpaper_ = 0;
+ $$->scores_.clear();
}
;
scm_gc_unprotect_object ($2->self_scm ());
}
| score_body error {
-
+ $$->error_found_ = true;
}
;
(LIST . LAST-CONS)
- to have efficient append.
-*/
+ to have efficient append. */
+
Music_list:
/* empty */ {
$$ = scm_cons (SCM_EOL, SCM_EOL);
SCM s = $$;
SCM c = scm_cons ($2->self_scm (), SCM_EOL);
scm_gc_unprotect_object ($2->self_scm ()); /* UGH */
+
if (ly_c_pair_p (ly_cdr (s)))
scm_set_cdr_x (ly_cdr (s), c); /* append */
else
scm_set_cdr_x (s, c); /* remember last cell */
}
| Music_list embedded_scm {
+
}
| Music_list error {
+ Music * m = MY_MAKE_MUSIC("Music");
+ // ugh. code dup
+ m->set_property ("error-found", SCM_BOOL_T);
+ SCM s = $$;
+ SCM c = scm_cons (m->self_scm (), SCM_EOL);
+ scm_gc_unprotect_object (m->self_scm ()); /* UGH */
+
+ if (ly_c_pair_p (ly_cdr (s)))
+ scm_set_cdr_x (ly_cdr (s), c); /* append */
+ else
+ scm_set_car_x (s, c); /* set first cons */
+ scm_set_cdr_x (s, c); /* remember last cell */
}
;
-
Music:
Simple_music
| Composite_music
{
header_ = SCM_EOL;
music_ = SCM_EOL;
+ error_found_ = false;
smobify_self ();
}
Output_def *paperbook,
Output_def *default_def)
{
+ if (error_found_)
+ return SCM_EOL;
+
SCM scaled_bookdef = SCM_EOL;
Real scale = 1.0;
Score * sc = unsmob_score (score);
Output_def *od = unsmob_output_def (paper);
+ if (sc->error_found_)
+ {
+ return SCM_EOL;
+ }
+
SCM_ASSERT_TYPE (sc, score, SCM_ARG1, __FUNCTION__, "Score");
SCM_ASSERT_TYPE (od, paper, SCM_ARG2, __FUNCTION__, "Output_def");
unsmob_music (music)->origin ()->error (_("Already have music in score"));
unsmob_music (music_)->origin ()->error (_("This is the previous music"));
}
-
+
+ if (Music * m = unsmob_music (music))
+ {
+ m->origin()->error (_("Error found in this music expression. Ignoring it"));
+
+ this->error_found_ = this->error_found_ || to_boolean (m->get_property ("error-found"));
+
+ }
+
this->music_ = music;
+ if (this->error_found_)
+ this->music_ = SCM_EOL;
}
SCM
(music-filter
(lambda (m)
(let* ((tags (ly:music-property m 'tags))
- (res (memq tag tags)))
+ (res (memq tag tags)))
(or
(eq? tags '())
(memq tag tags))))
$(outdir)/%.latex: %.doc
- if [ -f $@ ]; then chmod a+w $@; fi
$(PYTHON) $(LILYPOND_BOOK) $(LILYPOND_BOOK_INCLUDES) --process='$(LILYPOND) $(LILYPOND_BOOK_INCLUDES)' --output=$(outdir) --verbose $(LILYPOND_BOOK_FLAGS) $<
- chmod -w $@
# don't do ``cd $(outdir)'', and assume that $(outdir)/.. is the src dir.
# it is not, for --srcdir builds
$(outdir)/%.texi: %.tely
- if [ -f $@ ]; then chmod a+w $@; fi
rm -f $$(grep -LF '\lilypondend' $(outdir)/lily-*.tex 2>/dev/null)
$(PYTHON) $(LILYPOND_BOOK) $(LILYPOND_BOOK_INCLUDES) --process='$(LILYPOND) $(LILYPOND_BOOK_INCLUDES)' --output=$(outdir) --format=$(LILYPOND_BOOK_FORMAT) --verbose $(LILYPOND_BOOK_FLAGS) $<
- chmod -w $@
$(outdir)/%.texi: $(outdir)/%.tely
- if [ -f $@ ]; then chmod a+w $@; fi
rm -f $$(grep -LF '\lilypondend' $(outdir)/lily-*.tex 2>/dev/null)
$(PYTHON) $(LILYPOND_BOOK) $(LILYPOND_BOOK_INCLUDES) --process='$(LILYPOND) $(LILYPOND_BOOK_INCLUDES)' --output=$(outdir) --format=$(LILYPOND_BOOK_FORMAT) --verbose $(LILYPOND_BOOK_FLAGS) $<
#
# DON'T REMOVE SOURCE FILES, otherwise the .TEXI ALWAYS OUT OF DATE.
# rm -f $<
- chmod -w $@
# nexi: n[o-lilypond t]exi
# for plain info doco: don't run lilypond
$(outdir)/%.nexi: %.tely
- if [ -f $@ ]; then chmod a+w $@; fi
rm -f $(outdir)/$*.texi
$(PYTHON) $(LILYPOND_BOOK) $(LILYPOND_BOOK_INCLUDES) --output=$(outdir) --format=$(LILYPOND_BOOK_FORMAT) --verbose $(LILYPOND_BOOK_FLAGS) --process='true' $<
mv $(outdir)/$*.texinfo $@ 2>/dev/null || mv $(outdir)/$*.texi $@
(cd $(outdir) && \
ls -1 lily-*.ly | sed 's/.ly$$/.txt/' | xargs touch) || true; \
fi
- chmod -w $@
$(outdir)/%.info: $(outdir)/%.nexi
$(MAKEINFO) -I $(outdir) --output=$(outdir)/$(*F).info $<
(text-type ,symbol? "Particular type of text script (e.g. finger, dynamic).")
(tempo-unit ,ly:duration? "The unit for the metronome count.")
(tonic ,ly:pitch? "Base of the scale")
+ (error-found ,boolean? "If true, a parsing error was found in this expression")
(element ,ly:music? "The single child of a Music_wrapper music object, or the body of a repeat.")
(elements ,ly:music-list? "A list of elements for sequential of simultaneous music, or the alternatives of repeated music. ")
(force-accidental ,boolean? "If set, a cautionary accidental should always be printed on this note")
(set-debug-cell-accesses! 15000))
m)
+(define (music-check-error music)
+ (define found #f)
+ (define (signal m)
+ (if (and (ly:music? m)
+ (eq? (ly:music-property m 'error-found) #t))
+ (set! found #t)))
+
+ (for-each signal (ly:music-property music 'elements))
+ (signal (ly:music-property music 'element))
+
+ (if found
+ (set! (ly:music-property music 'error-found) #t))
+ music)
+
(define-public toplevel-music-functions
(list
;; check-start-chords ; ; no longer needed with chord syntax.
(lambda (music parser) (voicify-music music))
(lambda (x parser) (music-map glue-mm-rest-texts x))
+ (lambda (x parser) (music-map music-check-error x))
(lambda (music parser)
(music-map (quote-substitute (ly:parser-lookup parser 'musicQuotes)) music))
status = 0
if ly_names:
- status = ly.system (string.join ([cmd] + ly_names), progress_p = 1)
+ status = ly.system (string.join ([cmd] + ly_names),
+ ignore_error = 1, progress_p = 1)
+
+ if status:
+ ly.error( 'Process %s exited unsuccessfully.' % cmd )
+ raise Compile_error
+
if format == HTML or format == TEXINFO:
for i in png_names:
if not os.path.exists (i + '.eps') and os.path.exists (i + '.tex'):
LATEX: '.tex',
}
+class Compile_error:
+ pass
+
+def do_process_cmd (chunks):
+ ly_outdated = filter (lambda x: is_derived_class (x.__class__, Lilypond_snippet) \
+ and x.ly_is_outdated (), chunks)
+ png_outdated = filter (lambda x: is_derived_class (x.__class__, Lilypond_snippet) \
+ and x.png_is_outdated (), chunks)
+
+ ly.progress (_ ("Writing snippets..."))
+ map (Lilypond_snippet.write_ly, ly_outdated)
+ ly.progress ('\n')
+
+ if ly_outdated:
+ ly.progress (_ ("Processing..."))
+ process_snippets (process_cmd, ly_outdated, png_outdated)
+ else:
+ ly.progress (_ ("All snippets are up to date..."))
+ ly.progress ('\n')
+
+
def do_file (input_filename):
#ugh
global format
else:
ly.error (_ ("cannot determine format for: %s" \
% input_filename))
-
+ ly.exit (1)
+
if not input_filename or input_filename == '-':
in_handle = sys.stdin
input_fullname = '<stdin>'
os.path.exists (output_filename) and
os.path.samefile (output_filename, input_fullname)):
ly.error (_("Output would overwrite input file; use --output."))
- sys.exit (2)
+ ly.exit (2)
output_file = open (output_filename, 'w')
if output_name:
os.chdir (output_name)
-
- ly.progress (_ ("Reading %s...") % input_fullname)
- source = in_handle.read ()
- ly.progress ('\n')
-
- # FIXME: containing blocks must be first, see find_toplevel_snippets
- snippet_types = (
- 'multiline_comment',
- 'verbatim',
- 'lilypond_block',
-# 'verb',
- 'singleline_comment',
- 'lilypond_file',
- 'include',
- 'lilypond', )
- ly.progress (_ ("Dissecting..."))
- chunks = find_toplevel_snippets (source, snippet_types)
- ly.progress ('\n')
-
- global default_ly_options
- textwidth = 0
- if not default_ly_options.has_key (LINEWIDTH):
- if format == LATEX:
- textwidth = get_latex_textwidth (source)
- default_ly_options[LINEWIDTH] = '''%.0f\\pt''' \
- % textwidth
- elif format == TEXINFO:
- for (k, v) in texinfo_linewidths.items ():
- # FIXME: @paper is usually not in chunk #0:
- # \input texinfo @c -*-texinfo-*-
- # bluntly search first K of source
- # s = chunks[0].replacement_text ()
- if re.search (k, source[:1024]):
- default_ly_options[LINEWIDTH] = v
- break
-
- if filter_cmd:
- output_file.writelines ([c.filter_text () for c in chunks])
-
-
- elif process_cmd:
- ly_outdated = filter (lambda x: is_derived_class (x.__class__, Lilypond_snippet) \
- and x.ly_is_outdated (), chunks)
- png_outdated = filter (lambda x: is_derived_class (x.__class__, Lilypond_snippet) \
- and x.png_is_outdated (), chunks)
-
- ly.progress (_ ("Writing snippets..."))
- map (Lilypond_snippet.write_ly, ly_outdated)
- ly.progress ('\n')
-
- if ly_outdated:
- ly.progress (_ ("Processing..."))
- process_snippets (process_cmd, ly_outdated, png_outdated)
- else:
- ly.progress (_ ("All snippets are up to date..."))
+ try:
+ ly.progress (_ ("Reading %s...") % input_fullname)
+ source = in_handle.read ()
ly.progress ('\n')
- ly.progress (_ ("Compiling %s...") % output_filename)
- output_file.writelines ([s.replacement_text () \
- for s in chunks])
+ # FIXME: containing blocks must be first, see find_toplevel_snippets
+ snippet_types = (
+ 'multiline_comment',
+ 'verbatim',
+ 'lilypond_block',
+ # 'verb',
+ 'singleline_comment',
+ 'lilypond_file',
+ 'include',
+ 'lilypond', )
+ ly.progress (_ ("Dissecting..."))
+ chunks = find_toplevel_snippets (source, snippet_types)
ly.progress ('\n')
- def process_include (snippet):
+ global default_ly_options
+ textwidth = 0
+ if not default_ly_options.has_key (LINEWIDTH):
+ if format == LATEX:
+ textwidth = get_latex_textwidth (source)
+ default_ly_options[LINEWIDTH] = '''%.0f\\pt''' \
+ % textwidth
+ elif format == TEXINFO:
+ for (k, v) in texinfo_linewidths.items ():
+ # FIXME: @paper is usually not in chunk #0:
+ # \input texinfo @c -*-texinfo-*-
+ # bluntly search first K of source
+ # s = chunks[0].replacement_text ()
+ if re.search (k, source[:1024]):
+ default_ly_options[LINEWIDTH] = v
+ break
+
+ if filter_cmd:
+ output_file.writelines ([c.filter_text () for c in chunks])
+
+
+ elif process_cmd:
+ do_process_cmd (chunks)
+ ly.progress (_ ("Compiling %s...") % output_filename)
+ output_file.writelines ([s.replacement_text () \
+ for s in chunks])
+ ly.progress ('\n')
+
+ def process_include (snippet):
+ os.chdir (original_dir)
+ name = snippet.substring ('filename')
+ ly.progress (_ ('Processing include: %s') % name)
+ ly.progress ('\n')
+ do_file (name)
+
+ map (process_include,
+ filter (lambda x: is_derived_class (x.__class__, Include_snippet), chunks))
+ except Compile_error:
os.chdir (original_dir)
- name = snippet.substring ('filename')
- ly.progress (_ ('Processing include: %s') % name)
+ ly.progress (_('Removing `%s\'') % output_filename)
ly.progress ('\n')
- do_file (name)
- map (process_include,
- filter (lambda x: is_derived_class (x.__class__, Include_snippet), chunks))
+ os.unlink (output_filename)
+ raise Compile_error
+
def do_options ():
global format, output_name
ly.identify (sys.stderr)
ly.setup_environment ()
if files:
- do_file (files[0])
-
+ try:
+ do_file (files[0])
+ except Compile_error:
+ ly.exit (1)
+
if __name__ == '__main__':
main ()