From 8f7266efa3d78051e93156d0bdc645c339f7fe87 Mon Sep 17 00:00:00 2001 From: hanwen Date: Fri, 24 Sep 2004 10:42:47 +0000 Subject: [PATCH] * 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. --- ChangeLog | 18 +++- Documentation/topdocs/NEWS.texi | 6 ++ lily/book.cc | 7 ++ lily/include/score.hh | 3 +- lily/lily-parser.cc | 12 ++- lily/parser.yy | 24 ++++- lily/score.cc | 21 ++++- ly/music-functions-init.ly | 2 +- make/ly-rules.make | 8 -- scm/define-music-properties.scm | 1 + scm/music-functions.scm | 15 +++ scripts/lilypond-book.py | 162 ++++++++++++++++++-------------- 12 files changed, 188 insertions(+), 91 deletions(-) diff --git a/ChangeLog b/ChangeLog index b6f84d3789..7f6b37bda3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,19 @@ 2004-09-24 Han-Wen Nienhuys + * 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. @@ -7,8 +21,8 @@ * 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 diff --git a/Documentation/topdocs/NEWS.texi b/Documentation/topdocs/NEWS.texi index fccb0325bf..71512df1fd 100644 --- a/Documentation/topdocs/NEWS.texi +++ b/Documentation/topdocs/NEWS.texi @@ -8,6 +8,12 @@ @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 diff --git a/lily/book.cc b/lily/book.cc index 0eff1b5117..af4ecae8fe 100644 --- a/lily/book.cc +++ b/lily/book.cc @@ -64,6 +64,13 @@ Book::print_smob (SCM, SCM p, scm_print_state*) 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")); diff --git a/lily/include/score.hh b/lily/include/score.hh index 31a2e1483d..3705d16be5 100644 --- a/lily/include/score.hh +++ b/lily/include/score.hh @@ -24,7 +24,8 @@ class Score : public Input public: Link_array defs_; SCM header_; - + bool error_found_; + SCM get_music () const; void set_music (SCM music, SCM parser); Score (); diff --git a/lily/lily-parser.cc b/lily/lily-parser.cc index fc40c51e96..6f3c510906 100644 --- a/lily/lily-parser.cc +++ b/lily/lily-parser.cc @@ -418,6 +418,9 @@ LY_DEFINE (ly_parser_print_score, "ly:parser-print-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"); @@ -490,12 +493,13 @@ LY_DEFINE (ly_parser_print_book, "ly:parser-print-book", 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; } diff --git a/lily/parser.yy b/lily/parser.yy index 0ab0b2f65c..c8ce217748 100644 --- a/lily/parser.yy +++ b/lily/parser.yy @@ -660,7 +660,8 @@ book_body: $$->header_ = $2; } | book_body error { - + $$->bookpaper_ = 0; + $$->scores_.clear(); } ; @@ -705,7 +706,7 @@ score_body: scm_gc_unprotect_object ($2->self_scm ()); } | score_body error { - + $$->error_found_ = true; } ; @@ -804,8 +805,8 @@ The representation of a list is the (LIST . LAST-CONS) - to have efficient append. -*/ + to have efficient append. */ + Music_list: /* empty */ { $$ = scm_cons (SCM_EOL, SCM_EOL); @@ -814,6 +815,7 @@ Music_list: 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 @@ -821,12 +823,24 @@ Music_list: 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 diff --git a/lily/score.cc b/lily/score.cc index ecdddb64a8..0e9564758c 100644 --- a/lily/score.cc +++ b/lily/score.cc @@ -31,6 +31,7 @@ Score::Score () { header_ = SCM_EOL; music_ = SCM_EOL; + error_found_ = false; smobify_self (); } @@ -221,6 +222,9 @@ Score::book_rendering (String outname, Output_def *paperbook, Output_def *default_def) { + if (error_found_) + return SCM_EOL; + SCM scaled_bookdef = SCM_EOL; Real scale = 1.0; @@ -270,6 +274,11 @@ LY_DEFINE (ly_score_embedded_format, "ly:score-embedded-format", 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"); @@ -312,8 +321,18 @@ Score::set_music (SCM music, SCM parser) 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 diff --git a/ly/music-functions-init.ly b/ly/music-functions-init.ly index 0410976cbb..70755dff3b 100644 --- a/ly/music-functions-init.ly +++ b/ly/music-functions-init.ly @@ -63,7 +63,7 @@ keepWithTag = (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)))) diff --git a/make/ly-rules.make b/make/ly-rules.make index 0e899a7771..0ab32491c1 100644 --- a/make/ly-rules.make +++ b/make/ly-rules.make @@ -2,31 +2,24 @@ $(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 $@ @@ -35,7 +28,6 @@ $(outdir)/%.nexi: %.tely (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 $< diff --git a/scm/define-music-properties.scm b/scm/define-music-properties.scm index 66977251db..f4d852363f 100644 --- a/scm/define-music-properties.scm +++ b/scm/define-music-properties.scm @@ -56,6 +56,7 @@ e.g. @code{\\tag #'part ...} could tag a piece of music as only being active in (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") diff --git a/scm/music-functions.scm b/scm/music-functions.scm index 20b88d111c..3212e52159 100644 --- a/scm/music-functions.scm +++ b/scm/music-functions.scm @@ -623,11 +623,26 @@ Syntax: (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)) diff --git a/scripts/lilypond-book.py b/scripts/lilypond-book.py index fce5bb106d..25b185abda 100644 --- a/scripts/lilypond-book.py +++ b/scripts/lilypond-book.py @@ -839,8 +839,14 @@ def process_snippets (cmd, ly_snippets, png_snippets): 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'): @@ -903,6 +909,27 @@ format2ext = { 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 @@ -914,7 +941,8 @@ def do_file (input_filename): 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 = '' @@ -954,82 +982,75 @@ def do_file (input_filename): 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 @@ -1095,7 +1116,10 @@ def main (): 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 () -- 2.39.5