]> git.donarmstrong.com Git - lilypond.git/blob - scm/lily.scm
Add missing trailing newline
[lilypond.git] / scm / lily.scm
1 ;;;; This file is part of LilyPond, the GNU music typesetter.
2 ;;;;
3 ;;;; Copyright (C) 1998--2014 Jan Nieuwenhuizen <janneke@gnu.org>
4 ;;;; Han-Wen Nienhuys <hanwen@xs4all.nl>
5 ;;;;
6 ;;;; LilyPond is free software: you can redistribute it and/or modify
7 ;;;; it under the terms of the GNU General Public License as published by
8 ;;;; the Free Software Foundation, either version 3 of the License, or
9 ;;;; (at your option) any later version.
10 ;;;;
11 ;;;; LilyPond is distributed in the hope that it will be useful,
12 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 ;;;; GNU General Public License for more details.
15 ;;;;
16 ;;;; You should have received a copy of the GNU General Public License
17 ;;;; along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18
19 ;; Internationalisation: (_i "to be translated") gets an entry in the
20 ;; POT file; (gettext ...) must be invoked explicitly to do the actual
21 ;; "translation".
22 ;;
23 ;; (define-macro (_i x) x)
24 ;; (define-macro-public _i (x) x)
25 ;; (define-public-macro _i (x) x)
26 ;; Abbrv-PWR!
27
28 (defmacro-public _i (x) x)
29
30 ;;; Boolean thunk - are we integrating Guile V2.0 or higher with LilyPond?
31 (define-public (guile-v2)
32   (string>? (version) "1.9.10"))
33
34 (read-enable 'positions)
35 (if (not (guile-v2))
36     (debug-enable 'debug)
37     (begin
38       (debug-enable 'backtrace)
39       (debug-set! show-file-name #t)))
40
41 (define-public PLATFORM
42   (string->symbol
43    (string-downcase
44     (car (string-tokenize (utsname:sysname (uname)))))))
45
46 ;;
47 ;; Session-handling variables and procedures.
48 ;;
49 ;;  A "session" corresponds to one .ly file processed on a LilyPond
50 ;;  command line.  Every session gets to see a reasonably fresh state
51 ;;  of LilyPond and should work independently from previous files.
52 ;;
53 ;;  Session management relies on cooperation, namely the user not
54 ;;  trying to change variables and data structures internal to
55 ;;  LilyPond.  It is not proof against in-place modification of data
56 ;;  structures (as they are just reinitialized with the original
57 ;;  identities), and it is not proof against tampering with internals.
58 ;;
59 ;;  As a consequence, session management is not sufficient for
60 ;;  separating multiple independent .ly files in "-dsafe" mode: you
61 ;;  should give each its own LilyPond process when reliable separation
62 ;;  is mandatory.
63 ;;
64 ;;  For standard tasks and programming practices, multiple sessions in
65 ;;  the same LilyPond job should work reasonably independently and
66 ;;  without "bleed-over" while still loading and compiling the
67 ;;  relevant .scm and .ly files only once.
68 ;;
69
70 (define lilypond-declarations '())
71 (define after-session-hook (make-hook))
72
73 (define-public (call-after-session thunk)
74   (if (ly:undead? lilypond-declarations)
75       (ly:error (_ "call-after-session used after session start")))
76   (add-hook! after-session-hook thunk #t))
77
78 (defmacro-public define-session (name value)
79   "This defines a variable @var{name} with the starting value
80 @var{value} that is reinitialized at the start of each session.
81 A@tie{}session basically corresponds to one LilyPond file on the
82 command line.  The value is recorded at the start of the first session
83 after loading all initialization files and before loading the user
84 file and is reinstated for all of the following sessions.  This
85 happens just by replacing the value, not by copying structures, so you
86 should not destructively modify them.  For example, lists defined in
87 this manner should be changed within a session only be adding material
88 to their front or replacing them altogether, not by modifying parts of
89 them.  It is an error to call @code{define-session} after the first
90 session has started."
91   (define (add-session-variable name value)
92     (if (ly:undead? lilypond-declarations)
93         (ly:error (_ "define-session used after session start")))
94     (let ((var (make-variable value)))
95       (module-add! (current-module) name var)
96       (set! lilypond-declarations (cons var lilypond-declarations))))
97   `(,add-session-variable ',name ,value))
98
99 (defmacro-public define-session-public (name value)
100   "Like @code{define-session}, but also exports @var{name}."
101   `(begin
102      (define-session ,name ,value)
103      (export ,name)))
104
105 (define (session-terminate)
106   (if (ly:undead? lilypond-declarations)
107       (begin
108         (for-each
109          (lambda (p) (variable-set! (cadr p) (cddr p)))
110          (ly:get-undead lilypond-declarations))
111         (run-hook after-session-hook))))
112
113 (define lilypond-interfaces #f)
114
115 (define-public (session-initialize thunk)
116   "Initialize this session.  The first session in a LilyPond run is
117 initialized by calling @var{thunk}, then recording the values of all
118 variables in the current module as well as those defined with
119 @code{define-session}.  Subsequent calls of @code{session-initialize}
120 ignore @var{thunk} and instead just reinitialize all recorded
121 variables to their value after the initial call of @var{thunk}."
122
123   ;; We need to save the variables of the current module along with
124   ;; their values: functions defined in the module might refer to the
125   ;; variables.
126
127   ;; The entries in lilypond-declarations consist of a cons* consisting
128   ;; of symbol, variable, and value.  Variables defined with
129   ;; define-session have the symbol set to #f.
130
131   (if (ly:undead? lilypond-declarations)
132       (begin
133         (module-use-interfaces! (current-module) (reverse lilypond-interfaces))
134         (for-each
135          (lambda (p)
136            (let ((var (cadr p))
137                  (val (cddr p)))
138              (variable-set! var val)
139              (if (car p)
140                  (module-add! (current-module) (car p) var))))
141          (ly:get-undead lilypond-declarations)))
142       (begin
143         (thunk)
144         (set! lilypond-interfaces
145               (filter (lambda (m) (eq? 'interface (module-kind m)))
146                       (module-uses (current-module))))
147         (let ((decl (map! (lambda (v)
148                             (cons* #f v (variable-ref v)))
149                           lilypond-declarations)))
150           (module-for-each
151            (lambda (s v)
152              (let ((val (variable-ref v)))
153                (if (not (ly:lily-parser? val))
154                    (set! decl
155                          (cons
156                           (cons* s v val)
157                           decl)))))
158            (current-module))
159           (set! lilypond-declarations (ly:make-undead decl))))))
160
161 (define scheme-options-definitions
162   `(
163     ;; NAMING: either
164
165     ;; - [subject-]object-object-verb +"ing"
166     ;; - [subject-]-verb-object-object
167
168     ;; Avoid overlong lines in `lilypond -dhelp'!  Strings should not
169     ;; be longer than 48 characters per line.
170
171     (anti-alias-factor 1
172                        "Render at higher resolution (using given factor)
173 and scale down result to prevent jaggies in
174 PNG images.")
175     (aux-files
176      #t
177      "Create .tex, .texi, .count files in the
178 EPS backend.")
179     (backend
180      ps
181      "Select backend.  Possible values: 'eps, 'null,
182 'ps, 'scm, 'socket, 'svg.")
183     (check-internal-types
184      #f
185      "Check every property assignment for types.")
186     (clip-systems
187      #f
188      "Generate cut-out snippets of a score.")
189     (datadir
190      #f
191      "LilyPond prefix for data files (read-only).")
192     (debug-gc
193      #f
194      "Dump memory debugging statistics.")
195     (debug-gc-assert-parsed-dead
196      #f
197      "For memory debugging: Ensure that all
198 references to parsed objects are dead.  This is
199 an internal option, and is switched on
200 automatically for `-ddebug-gc'.")
201     (debug-lexer
202      #f
203      "Debug the flex lexer.")
204     (debug-page-breaking-scoring
205      #f
206      "Dump scores for many different page breaking
207 configurations.")
208     (debug-parser
209      #f
210      "Debug the bison parser.")
211     (debug-property-callbacks
212      #f
213      "Debug cyclic callback chains.")
214     (debug-skylines
215      #f
216      "Debug skylines.")
217     (delete-intermediate-files
218      #t
219      "Delete unusable, intermediate PostScript files.")
220     (dump-profile
221      #f
222      "Dump memory and time information for each file.")
223     (dump-cpu-profile
224      #f
225      "Dump timing information (system-dependent).")
226     (dump-signatures
227      #f
228      "Dump output signatures of each system.  Used for
229 regression testing.")
230     (eps-box-padding
231      #f
232      "Pad left edge of the output EPS bounding box by
233 given amount (in mm).")
234     (gs-load-fonts
235      #f
236      "Load fonts via Ghostscript.")
237     (gs-load-lily-fonts
238      #f
239      "Load only LilyPond fonts via Ghostscript.")
240     (gui
241      #f
242      "Run LilyPond from a GUI and redirect stderr to
243 a log file.")
244     (help
245      #f
246      "Show this help.")
247     (include-book-title-preview
248      #t
249      "Include book titles in preview images.")
250     (include-eps-fonts
251      #t
252      "Include fonts in separate-system EPS files.")
253     (include-settings
254      #f
255      "Include file for global settings, included before the score is processed.")
256     (job-count
257      #f
258      "Process in parallel, using the given number of
259 jobs.")
260     (log-file
261      #f
262      "If string FOO is given as argument, redirect
263 output to log file `FOO.log'.")
264     (max-markup-depth
265      1024
266      "Maximum depth for the markup tree. If a markup has more levels,
267 assume it will not terminate on its own, print a warning and return a
268 null markup instead.")
269     (midi-extension ,(if (eq? PLATFORM 'windows)
270                          "mid"
271                          "midi")
272                     "Set the default file extension for MIDI output
273 file to given string.")
274     (music-strings-to-paths
275      #f
276      "Convert text strings to paths when glyphs belong
277 to a music font.")
278     (point-and-click
279      #t
280      "Add point & click links to PDF and SVG output.")
281     (paper-size
282      "a4"
283      "Set default paper size.")
284     (pixmap-format
285      "png16m"
286      "Set GhostScript's output format for pixel images.")
287     (preview
288      #f
289      "Create preview images also.")
290     (print-pages
291      #t
292      "Print pages in the normal way.")
293     (protected-scheme-parsing
294      #t
295      "Continue when errors in inline scheme are caught
296 in the parser.  If #f, halt on errors and print
297 a stack trace.")
298     (profile-property-accesses
299      #f
300      "Keep statistics of get_property() calls.")
301     (resolution
302      101
303      "Set resolution for generating PNG pixmaps to
304 given value (in dpi).")
305     (read-file-list
306      #f
307      "Specify name of a file which contains a list of
308 input files to be processed.")
309     (relative-includes
310      #f
311      "When processing an \\include command, look for
312 the included file relative to the current file\
313 \n(instead of the root file)")
314     (safe
315      #f
316      "Run in safer mode.")
317     (separate-log-files
318      #f
319      "For input files `FILE1.ly', `FILE2.ly', ...
320 output log data to files `FILE1.log',
321 `FILE2.log', ...")
322     (show-available-fonts
323      #f
324      "List available font names.")
325     (strict-infinity-checking
326      #f
327      "Force a crash on encountering Inf and NaN
328 floating point exceptions.")
329     (strip-output-dir
330      #t
331      "Don't use directories from input files while
332 constructing output file names.")
333     (strokeadjust
334      #f
335      "Set the PostScript strokeadjust operator explicitly.
336 This employs different drawing primitives, resulting in
337 large PDF file size increases but often markedly better
338 PDF previews.")
339     (svg-woff
340      #f
341      "Use woff font files in SVG backend.")
342     (trace-memory-frequency
343      #f
344      "Record Scheme cell usage this many times per
345 second.  Dump results to `FILE.stacks' and
346 `FILE.graph'.")
347     (trace-scheme-coverage
348      #f
349      "Record coverage of Scheme files in `FILE.cov'.")
350     (verbose ,(ly:verbose-output?)
351              "Verbose output, i.e. loglevel at least DEBUG (read-only).")
352     (warning-as-error
353      #f
354      "Change all warning and programming_error
355 messages into errors.")
356     ))
357
358 ;; Need to do this in the beginning.  Other parts of the Scheme
359 ;; initialization depend on these options.
360
361 (for-each (lambda (x)
362             (ly:add-option (car x) (cadr x) (caddr x)))
363           scheme-options-definitions)
364
365 (for-each (lambda (x)
366             (ly:set-option (car x) (cdr x)))
367           (eval-string (ly:command-line-options)))
368
369 (debug-set! stack 0)
370
371 (if (defined? 'set-debug-cell-accesses!)
372     (set-debug-cell-accesses! #f))
373
374 ;;(set-debug-cell-accesses! 1000)
375
376 (use-modules (ice-9 regex)
377              (ice-9 safe)
378              (ice-9 format)
379              (ice-9 rdelim)
380              (ice-9 optargs)
381              (oop goops)
382              (srfi srfi-1)
383              (srfi srfi-13)
384              (srfi srfi-14)
385              (scm clip-region)
386              (scm memory-trace)
387              (scm coverage)
388              (scm safe-utility-defs))
389
390 (define-public _ gettext)
391 ;;; There are new modules defined in Guile V2.0 which we need to use.
392 ;;
393 ;;  Modules and scheme files loaded by lily.scm use currying
394 ;;  in Guile V2 this needs a module which is not present in Guile V1.8
395 ;;
396
397 (cond
398  ((guile-v2)
399   (ly:debug (_ "Using (ice-9 curried-definitions) module\n"))
400   (use-modules (ice-9 curried-definitions)))
401  (else
402   (ly:debug (_ "Guile 1.8\n"))))
403
404 ;; TODO add in modules for V1.8.7 deprecated in V2.0 and integrated
405 ;; into Guile base code, like (ice-9 syncase).
406 ;;
407
408 (define-public fancy-format
409   format)
410
411 (define-public (ergonomic-simple-format dest . rest)
412   "Like ice-9's @code{format}, but without the memory consumption."
413   (if (string? dest)
414       (apply simple-format #f dest rest)
415       (apply simple-format dest rest)))
416
417 (define format
418   ergonomic-simple-format)
419
420 ;; my display
421 (define-public (myd k v)
422   (display k)
423   (display ": ")
424   (display v)
425   (display ", ")
426   v)
427
428 (define-public (print . args)
429   (apply format (current-output-port) args))
430
431
432 ;;; General settings.
433 ;;;
434 ;;; Debugging evaluator is slower.  This should have a more sensible
435 ;;; default.
436
437
438 (if (or (ly:get-option 'verbose)
439         (ly:get-option 'trace-memory-frequency)
440         (ly:get-option 'trace-scheme-coverage))
441     (begin
442       (ly:set-option 'protected-scheme-parsing #f)
443       (debug-enable 'backtrace)
444       (read-enable 'positions)))
445
446 (if (ly:get-option 'trace-scheme-coverage)
447     (coverage:enable))
448
449 (define music-string-to-path-backends
450   '(svg))
451
452 (if (memq (ly:get-option 'backend) music-string-to-path-backends)
453     (ly:set-option 'music-strings-to-paths #t))
454
455 (define-public (ly:load x)
456   (let* ((file-name (%search-load-path x)))
457     (ly:debug "[~A" file-name)
458     (if (not file-name)
459         (ly:error (_ "cannot find: ~A") x))
460     (primitive-load-path file-name)  ;; to support Guile V2 autocompile
461     ;; TODO: Any chance to use ly:debug here? Need to extend it to prevent
462     ;;       a newline in this case
463     (if (ly:get-option 'verbose)
464         (ly:progress "]\n"))))
465
466 (define-public DOS
467   (let ((platform (string-tokenize
468                    (vector-ref (uname) 0) char-set:letter+digit)))
469     (if (null? (cdr platform)) #f
470         (member (string-downcase (cadr platform)) '("95" "98" "me")))))
471
472 (define (slashify x)
473   (if (string-index x #\\)
474       x
475       (string-regexp-substitute
476        "//*" "/"
477        (string-regexp-substitute "\\\\" "/" x))))
478
479 (define-public (ly-getcwd)
480   (if (eq? PLATFORM 'windows)
481       (slashify (getcwd))
482       (getcwd)))
483
484 (define-public (is-absolute? file-name)
485   (let ((file-name-length (string-length file-name)))
486     (if (= file-name-length 0)
487         #f
488         (or (eq? (string-ref file-name 0) #\/)
489             (and (eq? PLATFORM 'windows)
490                  (> file-name-length 2)
491                  (eq? (string-ref file-name 1) #\:)
492                  (eq? (string-ref file-name 2) #\/))))))
493
494 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
495 ;;; If necessary, emulate Guile V2 module_export_all! for Guile V1.8.n
496 (cond-expand
497  ((not guile-v2)
498   (define (module-export-all! mod)
499     (define (fresh-interface!)
500       (let ((iface (make-module)))
501         (set-module-name! iface (module-name mod))
502         ;; for guile 2: (set-module-version! iface (module-version mod))
503         (set-module-kind! iface 'interface)
504         (set-module-public-interface! mod iface)
505         iface))
506     (let ((iface (or (module-public-interface mod)
507                      (fresh-interface!))))
508       (set-module-obarray! iface (module-obarray mod))))))
509
510
511 (define-safe-public (lilypond-version)
512   (string-join
513    (map (lambda (x) (if (symbol? x)
514                         (symbol->string x)
515                         (number->string x)))
516         (ly:version))
517    "."))
518
519 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
520 ;; init pitch system
521
522 (ly:set-default-scale (ly:make-scale #(0 1 2 5/2 7/2 9/2 11/2)))
523
524 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
525 ;; other files.
526
527 ;;
528 ;;  List of Scheme files to be loaded into the (lily) module.
529 ;;
530 ;;  - Library definitions, need to be at the head of the list
531 (define init-scheme-files-lib
532   '("lily-library.scm"
533     "output-lib.scm"))
534 ;;  - Files containing definitions used later by other files later in load
535 (define init-scheme-files-used
536   '("markup-macros.scm"
537     "parser-ly-from-scheme.scm"))
538 ;;  - Main body of files to be loaded
539 (define init-scheme-files-body
540   '("file-cache.scm"
541     "define-event-classes.scm"
542     "define-music-callbacks.scm"
543     "define-music-types.scm"
544     "define-note-names.scm"
545     "c++.scm"
546     "chord-entry.scm"
547     "skyline.scm"
548     "stencil.scm"
549     "define-markup-commands.scm"
550     "markup.scm"
551     "modal-transforms.scm"
552     "chord-generic-names.scm"
553     "chord-ignatzek-names.scm"
554     "music-functions.scm"
555     "part-combiner.scm"
556     "autochange.scm"
557     "define-music-properties.scm"
558     "time-signature-settings.scm"
559     "auto-beam.scm"
560     "chord-name.scm"
561     "bezier-tools.scm"
562     "ly-syntax-constructors.scm"
563
564     "define-context-properties.scm"
565     "translation-functions.scm"
566     "script.scm"
567     "midi.scm"
568     "layout-beam.scm"
569     "parser-clef.scm"
570     "layout-slur.scm"
571     "font.scm"
572     "encoding.scm"
573
574     "bar-line.scm"
575     "flag-styles.scm"
576     "fret-diagrams.scm"
577     "tablature.scm"
578     "harp-pedals.scm"
579     "define-woodwind-diagrams.scm"
580     "display-woodwind-diagrams.scm"
581     "predefined-fretboards.scm"
582     "define-grob-properties.scm"
583     "define-grobs.scm"
584     "define-grob-interfaces.scm"
585     "define-stencil-commands.scm"
586     "scheme-engravers.scm"
587     "titling.scm"
588     "text.scm"
589
590     "paper.scm"
591     "backend-library.scm"
592     "x11-color.scm"))
593 ;;  - Files to be loaded last
594 (define init-scheme-files-tail
595   ;;  - must be after everything has been defined
596   '("safe-lily.scm"))
597 ;;
598 ;; Now construct the load list
599 ;;
600 (define init-scheme-files
601   (append init-scheme-files-lib
602           init-scheme-files-used
603           init-scheme-files-body
604           init-scheme-files-tail))
605
606 (for-each ly:load init-scheme-files)
607
608 (define-public r5rs-primary-predicates
609   `((,boolean? . "boolean")
610     (,char? . "character")
611     (,number? . "number")
612     (,pair? . "pair")
613     (,port? . "port")
614     (,procedure? . "procedure")
615     (,string? . "string")
616     (,symbol? . "symbol")
617     (,vector? . "vector")))
618
619 (define-public r5rs-secondary-predicates
620   `((,char-alphabetic? . "alphabetic character")
621     (,char-lower-case? . "lower-case character")
622     (,char-numeric? . "numeric character")
623     (,char-upper-case? . "upper-case character")
624     (,char-whitespace? . "whitespace character")
625
626     (,complex? . "complex number")
627     (,even? . "even number")
628     (,exact? . "exact number")
629     (,inexact? . "inexact number")
630     (,integer? . "integer")
631     (,negative? . "negative number")
632     (,odd? . "odd number")
633     (,positive? . "positive number")
634     (,rational? . "rational number")
635     (,real? . "real number")
636     (,zero? . "zero")
637
638     (,list? . "list")
639     (,null? . "null")
640
641     (,input-port? . "input port")
642     (,output-port? . "output port")
643
644     ;; would this ever be used?
645     (,eof-object? . "end-of-file object")
646     ))
647
648 (define-public guile-predicates
649   `((,hash-table? . "hash table")
650     ))
651
652 (define-public lilypond-scheme-predicates
653   `((,boolean-or-symbol? . "boolean or symbol")
654     (,color? . "color")
655     (,cheap-list? . "list")
656     (,fraction? . "fraction, as pair")
657     (,grob-list? . "list of grobs")
658     (,index? . "non-negative integer")
659     (,markup? . "markup")
660     (,markup-command-list? . "markup command list")
661     (,markup-list? . "markup list")
662     (,moment-pair? . "pair of moment objects")
663     (,number-list? . "number list")
664     (,number-or-grob? . "number or grob")
665     (,number-or-markup? . "number or markup")
666     (,number-or-pair? . "number or pair")
667     (,number-or-string? . "number or string")
668     (,number-pair? . "pair of numbers")
669     (,number-pair-list? . "list of number pairs")
670     (,rational-or-procedure? . "an exact rational or procedure")
671     (,rhythmic-location? . "rhythmic location")
672     (,scheme? . "any type")
673     (,string-or-pair? . "string or pair")
674     (,string-or-music? . "string or music")
675     (,string-or-symbol? . "string or symbol")
676     (,symbol-list? . "symbol list")
677     (,symbol-list-or-music? . "symbol list or music")
678     (,symbol-list-or-symbol? . "symbol list or symbol")
679     (,void? . "void")
680     ))
681
682 (define-public lilypond-exported-predicates
683   `((,ly:book? . "book")
684     (,ly:box? . "box")
685     (,ly:context? . "context")
686     (,ly:context-def? . "context definition")
687     (,ly:context-mod? . "context modification")
688     (,ly:dimension? . "dimension, in staff space")
689     (,ly:dir? . "direction")
690     (,ly:dispatcher? . "dispatcher")
691     (,ly:duration? . "duration")
692     (,ly:event? . "post event")
693     (,ly:font-metric? . "font metric")
694     (,ly:grob? . "graphical (layout) object")
695     (,ly:grob-array? . "array of grobs")
696     (,ly:input-location? . "input location")
697     (,ly:item? . "item")
698     (,ly:iterator? . "iterator")
699     (,ly:lily-lexer? . "lily-lexer")
700     (,ly:lily-parser? . "lily-parser")
701     (,ly:listener? . "listener")
702     (,ly:moment? . "moment")
703     (,ly:music? . "music")
704     (,ly:music-function? . "music function")
705     (,ly:music-list? . "list of music objects")
706     (,ly:music-output? . "music output")
707     (,ly:otf-font? . "OpenType font")
708     (,ly:output-def? . "output definition")
709     (,ly:page-marker? . "page marker")
710     (,ly:pango-font? . "pango font")
711     (,ly:paper-book? . "paper book")
712     (,ly:paper-system? . "paper-system Prob")
713     (,ly:pitch? . "pitch")
714     (,ly:prob? . "property object")
715     (,ly:score? . "score")
716     (,ly:simple-closure? . "simple closure")
717     (,ly:skyline? . "skyline")
718     (,ly:skyline-pair? . "pair of skylines")
719     (,ly:source-file? . "source file")
720     (,ly:spanner? . "spanner")
721     (,ly:spring? . "spring")
722     (,ly:stencil? . "stencil")
723     (,ly:stream-event? . "stream event")
724     (,ly:translator? . "translator")
725     (,ly:translator-group? . "translator group")
726     (,ly:undead? . "undead container")
727     (,ly:unpure-pure-container? . "unpure/pure container")
728     ))
729
730
731 (set! type-p-name-alist
732       (append r5rs-primary-predicates
733               r5rs-secondary-predicates
734               guile-predicates
735               lilypond-scheme-predicates
736               lilypond-exported-predicates))
737
738
739 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
740 ;; timing
741
742 (define (profile-measurements)
743   (let* ((t (times))
744          (stats (gc-stats)))
745     (list (- (+ (tms:cutime t)
746                 (tms:utime t))
747              (assoc-get 'gc-time-taken stats))
748           (assoc-get 'total-cells-allocated  stats 0))))
749
750 (define (dump-profile base last this)
751   (let* ((outname (format #f "~a.profile" (dir-basename base ".ly")))
752          (diff (map - this last)))
753     (ly:progress "\nWriting timing to ~a...\n" outname)
754     (format (open-file outname "w")
755             "time: ~a\ncells: ~a\n"
756             (if (ly:get-option 'dump-cpu-profile)
757                 (car diff)
758                 0)
759             (cadr diff))))
760
761 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
762 ;; debug memory leaks
763
764 (define gc-dumping
765   #f)
766
767 (define gc-protect-stat-count
768   0)
769
770 ;; Undead objects that should be ignored after the first time round
771 (define gc-zombies
772   (make-weak-key-hash-table 0))
773
774 (define-public (dump-live-object-stats outfile)
775   (for-each (lambda (x)
776               (format outfile "~a: ~a\n" (car x) (cdr x)))
777             (sort (gc-live-object-stats)
778                   (lambda (x y)
779                     (string<? (car x) (car y))))))
780
781 (define-public (dump-gc-protects)
782   (set! gc-protect-stat-count (1+ gc-protect-stat-count))
783   (let* ((protects (sort (hash-table->alist (ly:protects))
784                          (lambda (a b)
785                            (< (object-address (car a))
786                               (object-address (car b))))))
787          (out-file-name (string-append
788                          "gcstat-" (number->string gc-protect-stat-count)
789                          ".scm"))
790          (outfile (open-file out-file-name "w")))
791     (set! gc-dumping #t)
792     (ly:progress "Dumping GC statistics ~a...\n" out-file-name)
793     (for-each (lambda (y)
794                 (let ((x (car y))
795                       (c (cdr y)))
796                   (format outfile "~a (~a) = ~a\n" (object-address x) c x)))
797               (filter
798                (lambda (x)
799                  (not (symbol? (car x))))
800                protects))
801     (format outfile "\nprotected symbols: ~a\n"
802             (apply + (map (lambda (obj-count)
803                             (if (symbol? (car obj-count))
804                                 (cdr obj-count)
805                                 0))
806                           protects)))
807
808     ;; (display (ly:smob-protects))
809     (newline outfile)
810     (if (defined? 'gc-live-object-stats)
811         (let* ((stats #f))
812           (ly:progress "Live object statistics: GC'ing\n")
813           (ly:reset-all-fonts)
814           (gc)
815           (gc)
816           (ly:progress "Asserting dead objects\n")
817           (ly:set-option 'debug-gc-assert-parsed-dead #t)
818           (gc)
819           (ly:set-option 'debug-gc-assert-parsed-dead #f)
820           (for-each
821            (lambda (x)
822              (if (not (hashq-ref gc-zombies x))
823                  (begin
824                    (ly:programming-error "Parsed object should be dead: ~a" x)
825                    (hashq-set! gc-zombies x #t))))
826            (ly:parsed-undead-list!))
827           (set! stats (gc-live-object-stats))
828           (ly:progress "Dumping live object statistics.\n")
829           (dump-live-object-stats outfile)))
830     (newline outfile)
831     (let* ((stats (gc-stats)))
832       (for-each (lambda (sym)
833                   (format outfile "~a ~a ~a\n"
834                           gc-protect-stat-count
835                           sym
836                           (assoc-get sym stats "?")))
837                 '(protected-objects bytes-malloced cell-heap-size)))
838     (set! gc-dumping #f)
839     (close-port outfile)))
840
841 (define (check-memory)
842   "Read `/proc/self' to check up on memory use."
843   (define (gulp-file name)
844     (let* ((file (open-input-file name))
845            (text (read-delimited "" file)))
846       (close file)
847       text))
848
849   (let* ((stat (gulp-file "/proc/self/status"))
850          (lines (string-split stat #\newline))
851          (interesting (filter-map
852                        (lambda (l)
853                          (string-match "^VmData:[ \t]*([0-9]*) kB" l))
854                        lines))
855          (mem (string->number (match:substring (car interesting) 1))))
856     (format #t "VMDATA: ~a\n" mem)
857     (display (gc-stats))
858     (newline)
859     (if (> mem 500000)
860         (begin (dump-gc-protects)
861                (raise 1)))))
862
863 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
864
865 (define (multi-fork count)
866   "Split this process into COUNT helpers.  Returns either a list of
867 PIDs or the number of the process."
868   (define (helper count acc)
869     (if (> count 0)
870         (let* ((pid (primitive-fork)))
871           (if (= pid 0)
872               (1- count)
873               (helper (1- count) (cons pid acc))))
874         acc))
875
876   (helper count '()))
877
878 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
879
880 (define* (ly:exit status #:optional (silently #f))
881   "Exit function for lilypond"
882   (if (not silently)
883       (case status
884         ((0) (ly:basic-progress (_ "Success: compilation successfully completed")))
885         ((1) (ly:warning (_ "Compilation completed with warnings or errors")))
886         (else (ly:message ""))))
887   (exit status))
888
889 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
890
891 (define-public (lilypond-main files)
892   "Entry point for LilyPond."
893   (eval-string (ly:command-line-code))
894   (if (ly:get-option 'help)
895       (begin (ly:option-usage)
896              (ly:exit 0 #t)))
897   (if (ly:get-option 'show-available-fonts)
898       (begin (ly:font-config-display-fonts)
899              (ly:exit 0 #t)))
900   (if (ly:get-option 'gui)
901       (gui-main files))
902   (if (null? files)
903       (begin (ly:usage)
904              (ly:exit 2 #t)))
905   (if (ly:get-option 'read-file-list)
906       (set! files
907             (remove string-null?
908                     (append-map
909                      (lambda (f)
910                        (string-split (string-delete (ly:gulp-file f) #\cr) #\nl))
911                      files))))
912   (if (and (number? (ly:get-option 'job-count))
913            (>= (length files) (ly:get-option 'job-count)))
914       (let* ((count (ly:get-option 'job-count))
915              (split-todo (split-list files count))
916              (joblist (multi-fork count))
917              (errors '()))
918         (if (not (string-or-symbol? (ly:get-option 'log-file)))
919             (ly:set-option 'log-file "lilypond-multi-run"))
920         (if (number? joblist)
921             (begin (ly:set-option
922                     'log-file (format #f "~a-~a"
923                                       (ly:get-option 'log-file) joblist))
924                    (set! files (vector-ref split-todo joblist)))
925             (begin (ly:progress "\nForking into jobs:  ~a\n" joblist)
926                    (for-each
927                     (lambda (pid)
928                       (let* ((stat (cdr (waitpid pid))))
929                         (if (not (= stat 0))
930                             (set! errors
931                                   (acons (list-element-index joblist pid)
932                                          stat errors)))))
933                     joblist)
934                    (for-each
935                     (lambda (x)
936                       (let* ((job (car x))
937                              (state (cdr x))
938                              (logfile (format #f "~a-~a.log"
939                                               (ly:get-option 'log-file) job))
940                              (log (ly:gulp-file logfile))
941                              (len (string-length log))
942                              (tail (substring  log (max 0 (- len 1024)))))
943                         (if (status:term-sig state)
944                             (ly:message
945                              "\n\n~a\n"
946                              (format #f (_ "job ~a terminated with signal: ~a")
947                                      job (status:term-sig state)))
948                             (ly:message
949                              (_ "logfile ~a (exit ~a):\n~a")
950                              logfile (status:exit-val state) tail))))
951                     errors)
952                    (if (pair? errors)
953                        (ly:error "Children ~a exited with errors."
954                                  (map car errors)))
955                    ;; must overwrite individual entries
956                    (if (ly:get-option 'dump-profile)
957                        (dump-profile "lily-run-total"
958                                      '(0 0) (profile-measurements)))
959                    (if (null? errors)
960                        (ly:exit 0 #f)
961                        (ly:exit 1 #f))))))
962
963   (if (string-or-symbol? (ly:get-option 'log-file))
964       (ly:stderr-redirect (format #f "~a.log" (ly:get-option 'log-file)) "w"))
965   (let ((failed (lilypond-all files)))
966     (if (ly:get-option 'trace-scheme-coverage)
967         (begin
968           (coverage:show-all (lambda (f)
969                                (string-contains f "lilypond")))))
970     (if (pair? failed)
971         (begin (ly:error (_ "failed files: ~S") (string-join failed))
972                (ly:exit 1 #f))
973         (begin
974           (ly:exit 0 #f)))))
975
976
977 (define-public (lilypond-all files)
978   (let* ((failed '())
979          (separate-logs (ly:get-option 'separate-log-files))
980          (ping-log
981           (and separate-logs
982                (if (string-or-symbol? (ly:get-option 'log-file))
983                    (open-file (format #f "~a.log" (ly:get-option 'log-file))
984                               "a")
985                    (fdes->outport 2))))
986          (do-measurements (ly:get-option 'dump-profile))
987          (handler (lambda (key failed-file)
988                     (set! failed (append (list failed-file) failed)))))
989     (gc)
990     (for-each
991      (lambda (x)
992        (let* ((start-measurements (if do-measurements
993                                       (profile-measurements)
994                                       #f))
995               (base (dir-basename x ".ly"))
996               (all-settings (ly:all-options)))
997          (if separate-logs
998              (ly:stderr-redirect (format #f "~a.log" base) "w"))
999          (if ping-log
1000              (format ping-log "Processing ~a\n" base))
1001          (if (ly:get-option 'trace-memory-frequency)
1002              (mtrace:start-trace  (ly:get-option 'trace-memory-frequency)))
1003          (lilypond-file handler x)
1004          (ly:check-expected-warnings)
1005          (session-terminate)
1006          (if start-measurements
1007              (dump-profile x start-measurements (profile-measurements)))
1008          (if (ly:get-option 'trace-memory-frequency)
1009              (begin (mtrace:stop-trace)
1010                     (mtrace:dump-results base)))
1011          (for-each (lambda (s)
1012                      (ly:set-option (car s) (cdr s)))
1013                    all-settings)
1014          (ly:set-option 'debug-gc-assert-parsed-dead #t)
1015          (gc)
1016          (ly:set-option 'debug-gc-assert-parsed-dead #f)
1017          (for-each
1018           (lambda (x)
1019             (if (not (hashq-ref gc-zombies x))
1020                 (begin
1021                   (ly:programming-error "Parsed object should be dead: ~a" x)
1022                   (hashq-set! gc-zombies x #t))))
1023           (ly:parsed-undead-list!))
1024          (if (ly:get-option 'debug-gc)
1025              (dump-gc-protects)
1026              (ly:reset-all-fonts))
1027          (flush-all-ports)))
1028      files)
1029
1030     ;; Ensure a notice re failed files is written to aggregate logfile.
1031     (if ping-log
1032         (format ping-log "Failed files: ~a\n" failed))
1033     (if (ly:get-option 'dump-profile)
1034         (dump-profile "lily-run-total" '(0 0) (profile-measurements)))
1035     failed))
1036
1037 (define (lilypond-file handler file-name)
1038   (catch 'ly-file-failed
1039          (lambda () (ly:parse-file file-name))
1040          (lambda (x . args) (handler x file-name))))
1041
1042 (use-modules (scm editor))
1043
1044 (define-public (gui-main files)
1045   (if (null? files)
1046       (gui-no-files-handler))
1047   (if (not (string? (ly:get-option 'log-file)))
1048       (let* ((base (dir-basename (car files) ".ly"))
1049              (log-name (string-append base ".log")))
1050         (if (not (ly:get-option 'gui))
1051             (ly:message (_ "Redirecting output to ~a...") log-name))
1052         (ly:stderr-redirect log-name "w")
1053         (ly:message "# -*-compilation-*-"))
1054       (let ((failed (lilypond-all files)))
1055         (if (pair? failed)
1056             (begin
1057               ;; ugh
1058               (ly:stderr-redirect "foo" "r")
1059               (system (get-editor-command log-name 0 0 0))
1060               (ly:error (_ "failed files: ~S") (string-join failed))
1061               ;; not reached?
1062               (exit 1))
1063             (ly:exit 0 #f)))))
1064
1065 (define (gui-no-files-handler)
1066   (let* ((ly (string-append (ly:effective-prefix) "/ly/"))
1067          ;; FIXME: soft-code, localize
1068          (welcome-ly (string-append ly "Welcome_to_LilyPond.ly"))
1069          (cmd (get-editor-command welcome-ly 0 0 0)))
1070     (ly:message (_ "Invoking `~a'...\n") cmd)
1071     (system cmd)
1072     (ly:exit 1 #f)))