]> git.donarmstrong.com Git - lilypond.git/blob - lily/scheme-engraver.cc
54d96208229152c03ce29fc3616dd4f4fe109eea
[lilypond.git] / lily / scheme-engraver.cc
1 /*
2   scheme-engraver.cc -- implement Scheme_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   Copyright (c) 2009--2015 Han-Wen Nienhuys <hanwen@lilypond.org>
7
8   LilyPond is free software: you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation, either version 3 of the License, or
11   (at your option) any later version.
12
13   LilyPond is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "scheme-engraver.hh"
23
24 #include "grob.hh"
25
26 #include "translator.icc"
27
28 #include "scm-hash.hh"
29
30 void
31 Scheme_engraver::pre_init ()
32 {
33   initialize_function_ = SCM_EOL;
34   finalize_function_ = SCM_EOL;
35
36   interface_acknowledger_hash_.set (SCM_EOL, SCM_EOL);
37
38   must_be_last_ = false;
39   per_instance_listeners_ = SCM_EOL;
40   for (int i = 0; i < TRANSLATOR_METHOD_PRECOMPUTE_COUNT; i++)
41     precomputable_methods_[i] = SCM_UNDEFINED;
42 }
43
44 Scheme_engraver::~Scheme_engraver ()
45 {
46 }
47
48 // Extracts the value if callable, if not return SCM_UNDEFINED;
49 static SCM
50 callable (SCM symbol, SCM defn)
51 {
52   SCM val = ly_assoc_get (symbol, defn, SCM_BOOL_F);
53   return ly_is_procedure (val) ? val : SCM_UNDEFINED;
54 }
55
56 bool
57 Scheme_engraver::must_be_last () const
58 {
59   return must_be_last_;
60 }
61
62 void
63 Scheme_engraver::fetch_precomputable_methods (SCM ptrs[])
64 {
65   for (int i = 0; i < TRANSLATOR_METHOD_PRECOMPUTE_COUNT; i++)
66     ptrs[i] = precomputable_methods_[i];
67 }
68
69 Scheme_engraver::Scheme_engraver (SCM definition)
70 {
71   precomputable_methods_[START_TRANSLATION_TIMESTEP]
72     = callable (ly_symbol2scm ("start-translation-timestep"), definition);
73   precomputable_methods_[STOP_TRANSLATION_TIMESTEP]
74     = callable (ly_symbol2scm ("stop-translation-timestep"), definition);
75   precomputable_methods_[PROCESS_MUSIC]
76     = callable (ly_symbol2scm ("process-music"), definition);
77   precomputable_methods_[PROCESS_ACKNOWLEDGED]
78     = callable (ly_symbol2scm ("process-acknowledged"), definition);
79   initialize_function_ = callable (ly_symbol2scm ("initialize"), definition);
80   finalize_function_ = callable (ly_symbol2scm ("finalize"), definition);
81
82   SCM p = ly_assoc_get (ly_symbol2scm ("listeners"), definition, SCM_EOL);
83   SCM listeners = SCM_EOL;
84
85   must_be_last_ = to_boolean (ly_assoc_get (ly_symbol2scm ("must-be-last"),
86                                             definition,
87                                             SCM_BOOL_F));
88
89   for (; scm_is_pair (p); p = scm_cdr (p))
90     {
91       SCM event_class = scm_caar (p);
92       SCM proc = scm_cdar (p);
93
94       if (!(ly_is_procedure (proc) && ly_is_symbol (event_class)))
95         continue;
96
97       // We should check the arity of the function?
98
99       // Record for later lookup.
100       listeners = scm_acons (event_class, proc, listeners);
101     }
102
103   SCM hash1 =
104     init_acknowledgers (ly_assoc_get (ly_symbol2scm ("acknowledgers"),
105                                       definition, SCM_EOL));
106   SCM hash2 =
107     init_acknowledgers (ly_assoc_get (ly_symbol2scm ("end-acknowledgers"),
108                                       definition, SCM_EOL));
109
110   per_instance_listeners_ = listeners;
111   interface_acknowledger_hash_.set (hash1, hash2);
112
113   // It's not defined whether Scheme_engraver::derived_mark is already
114   // active while the construction is underway, so we make sure we
115   // keep a version of everything on the stack that is not still
116   // covered by `definition'.
117
118   scm_remember_upto_here_2 (definition, listeners);
119   scm_remember_upto_here_2 (hash1, hash2);
120
121   // TODO: hook up description, props read/written, grobs created
122   // etc. to provide automatic documentation.
123 }
124
125 SCM
126 Scheme_engraver::init_acknowledgers (SCM alist)
127 {
128   SCM hash = Scheme_hash_table::make_smob ();
129   for (SCM p = alist; scm_is_pair (p); p = scm_cdr (p))
130     {
131       SCM iface = scm_caar (p);
132       SCM proc = scm_cdar (p);
133
134       if (!(ly_is_procedure (proc) && ly_is_symbol (iface)))
135         continue;
136
137       unsmob<Scheme_hash_table>(hash)->set (iface, proc);
138     }
139   return hash;
140 }
141
142 SCM
143 Scheme_engraver::get_listener_list () const
144 {
145   return per_instance_listeners_;
146 }
147
148 void
149 Scheme_engraver::initialize ()
150 {
151   if (!SCM_UNBNDP (initialize_function_))
152     scm_call_1 (initialize_function_, self_scm ());
153 }
154
155 void
156 Scheme_engraver::finalize ()
157 {
158   if (!SCM_UNBNDP (finalize_function_))
159     scm_call_1 (finalize_function_, self_scm ());
160 }
161
162 void
163 Scheme_engraver::derived_mark () const
164 {
165   for (int i = 0; i < TRANSLATOR_METHOD_PRECOMPUTE_COUNT; i++)
166     scm_gc_mark (precomputable_methods_[i]);
167
168   scm_gc_mark (initialize_function_);
169   scm_gc_mark (finalize_function_);
170   scm_gc_mark (per_instance_listeners_);
171   scm_gc_mark (interface_acknowledger_hash_[START]);
172   scm_gc_mark (interface_acknowledger_hash_[STOP]);
173 }