]> git.donarmstrong.com Git - lilypond.git/blob - lily/translator-group.cc
Merge branch 'master' of git+ssh://jneem@git.sv.gnu.org/srv/git/lilypond
[lilypond.git] / lily / translator-group.cc
1 /*
2   translator-group.cc -- implement Translator_group
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>,
7                  Erik Sandberg <mandolaerik@gmail.com>
8 */
9
10 #include "translator-group.hh"
11
12 #include "context-def.hh"
13 #include "context.hh"
14 #include "dispatcher.hh"
15 #include "engraver-group.hh"
16 #include "international.hh"
17 #include "main.hh"
18 #include "music.hh"
19 #include "output-def.hh"
20 #include "performer-group.hh"
21 #include "scm-hash.hh"
22 #include "warn.hh"
23
24
25 void
26 translator_each (SCM list, Translator_method method)
27 {
28   for (SCM p = list; scm_is_pair (p); p = scm_cdr (p))
29     (unsmob_translator (scm_car (p))->*method) ();
30 }
31
32 void
33 Translator_group::initialize ()
34 {
35   precompute_method_bindings ();
36 }
37
38 void
39 Translator_group::connect_to_context (Context *c)
40 {
41   if (context_)
42     {
43       programming_error ("translator group is already connected to context "
44                          +  context_->context_name ());
45     }
46   
47   context_ = c;
48   c->event_source ()->add_listener (GET_LISTENER (create_child_translator),
49                                     ly_symbol2scm ("AnnounceNewContext"));
50   for (SCM tr_list = simple_trans_list_; scm_is_pair (tr_list); tr_list = scm_cdr (tr_list))
51     {
52       Translator *tr = unsmob_translator (scm_car (tr_list));
53       tr->connect_to_context (c);
54     }
55 }
56
57 void
58 Translator_group::disconnect_from_context ()
59 {
60   for (SCM tr_list = simple_trans_list_; scm_is_pair (tr_list); tr_list = scm_cdr (tr_list))
61     {
62       Translator *tr = unsmob_translator (scm_car (tr_list));
63       tr->disconnect_from_context (context_);
64     }
65   context_->event_source ()->remove_listener (GET_LISTENER (create_child_translator),
66                                               ly_symbol2scm ("AnnounceNewContext"));
67   context_ = 0;
68   protected_events_ = SCM_EOL;
69 }
70
71 void
72 Translator_group::finalize ()
73 {
74 }
75
76 SCM
77 filter_performers (SCM ell)
78 {
79   SCM *tail = &ell;
80   for (SCM p = ell; scm_is_pair (p); p = scm_cdr (p))
81     {
82       if (dynamic_cast<Performer *> (unsmob_translator (scm_car (*tail))))
83         *tail = scm_cdr (*tail);
84       else
85         tail = SCM_CDRLOC (*tail);
86     }
87   return ell;
88 }
89
90 SCM
91 filter_engravers (SCM ell)
92 {
93   SCM *tail = &ell;
94   for (SCM p = ell; scm_is_pair (p); p = scm_cdr (p))
95     {
96       if (dynamic_cast<Engraver *> (unsmob_translator (scm_car (*tail))))
97         *tail = scm_cdr (*tail);
98       else
99         tail = SCM_CDRLOC (*tail);
100     }
101   return ell;
102 }
103
104 /* 
105   Protects the parameter from being garbage collected. The object is
106   protected until the next disconnect_from_context call.
107
108   Whenever a child translator hears an event, the event is added to
109   this list. This eliminates the need for derived_mark methods in most
110   translators; all incoming events are instead protected by the
111   translator group.
112  
113   TODO: Should the list also be flushed at the beginning of each new
114   moment?
115  */
116 void
117 Translator_group::protect_event (SCM ev)
118 {
119   protected_events_ = scm_cons (ev, protected_events_);
120 }
121
122 /*
123   Create a new translator for a newly created child context. Triggered
124   by AnnounceNewContext events.
125  */
126 IMPLEMENT_LISTENER (Translator_group, create_child_translator);
127 void
128 Translator_group::create_child_translator (SCM sev)
129 {
130   Stream_event *ev = unsmob_stream_event (sev);
131   // get from AnnounceNewContext
132   SCM cs = ev->get_property ("context");
133   Context *new_context = unsmob_context (cs);
134   Context_def *def = unsmob_context_def (new_context->get_definition ());
135   SCM ops = new_context->get_definition_mods ();
136   
137   SCM trans_names = def->get_translator_names (ops);
138
139   Translator_group *g = get_translator_group (def->get_translator_group_type ());
140   SCM trans_list = SCM_EOL;
141
142   for (SCM s = trans_names; scm_is_pair (s); s = scm_cdr (s))
143     {
144       Translator *type = get_translator (scm_car (s));
145       if (!type)
146         warning (_f ("cannot find: `%s'", ly_symbol2string (scm_car (s)).c_str ()));
147       else
148         {
149           Translator *tr = type->clone ();
150           SCM str = tr->self_scm ();
151
152           if (tr->must_be_last ())
153             {
154               SCM cons = scm_cons (str, SCM_EOL);
155               if (scm_is_pair (trans_list))
156                 scm_set_cdr_x (scm_last_pair (trans_list), cons);
157               else
158                 trans_list = cons;
159             }
160           else
161             trans_list = scm_cons (str, trans_list);
162
163           tr->daddy_context_ = new_context;
164           tr->unprotect ();
165         }
166     }
167
168   /* Filter unwanted translator types. Required to make
169      \with {\consists "..."} work. */
170   if (dynamic_cast<Engraver_group *> (g))
171     g->simple_trans_list_ = filter_performers (trans_list);
172   else if (dynamic_cast<Performer_group *> (g))
173     g->simple_trans_list_ = filter_engravers (trans_list);
174
175   // TODO: scrap Context::implementation
176   new_context->implementation_ = g;
177
178   g->connect_to_context (new_context);
179   g->unprotect ();
180
181   recurse_over_translators (new_context,
182                             &Translator::initialize,
183                             &Translator_group::initialize,
184                             DOWN);
185 }
186
187 SCM
188 Translator_group::get_simple_trans_list ()
189 {
190   return simple_trans_list_;
191 }
192
193 void
194 precomputed_recurse_over_translators (Context *c, Translator_precompute_index idx, Direction dir)
195 {
196   Translator_group *tg
197     = dynamic_cast<Translator_group *> (c->implementation ());
198
199   if (tg && dir == DOWN)
200     {
201       tg->precomputed_translator_foreach (idx);
202       tg->call_precomputed_self_method (idx);
203     }
204
205   for (SCM s = c->children_contexts (); scm_is_pair (s);
206        s = scm_cdr (s))
207     precomputed_recurse_over_translators (unsmob_context (scm_car (s)), idx, dir);
208
209   if (tg && dir == UP)
210     {
211       tg->precomputed_translator_foreach (idx);
212       tg->call_precomputed_self_method (idx);
213     }
214 }
215
216 void
217 recurse_over_translators (Context *c, Translator_method ptr, Translator_group_method tg_ptr, Direction dir)
218 {
219   Translator_group *tg
220     = dynamic_cast<Translator_group *> (c->implementation ());
221
222   if (tg && dir == DOWN)
223     {
224       (tg->*tg_ptr) ();
225       translator_each (tg->get_simple_trans_list (), ptr);
226     }
227
228   for (SCM s = c->children_contexts (); scm_is_pair (s);
229        s = scm_cdr (s))
230     recurse_over_translators (unsmob_context (scm_car (s)), ptr, tg_ptr, dir);
231
232   if (tg && dir == UP)
233     {
234       translator_each (tg->get_simple_trans_list (),
235                        ptr);
236
237       (tg->*tg_ptr) ();
238     }
239 }
240
241 Translator_group::Translator_group ()
242 {
243   simple_trans_list_ = SCM_EOL;
244   protected_events_ = SCM_EOL;
245   context_ = 0;
246   smobify_self ();
247 }
248
249 void
250 Translator_group::derived_mark () const
251 {
252 }
253
254 void
255 Translator_group::precompute_method_bindings ()
256 {
257   for (SCM s = simple_trans_list_; scm_is_pair (s); s = scm_cdr (s))
258     {
259       Translator *tr = unsmob_translator (scm_car (s));
260       Translator_void_method_ptr ptrs[TRANSLATOR_METHOD_PRECOMPUTE_COUNT];
261       tr->fetch_precomputable_methods (ptrs);
262
263       assert (tr);
264       for (int i = 0; i < TRANSLATOR_METHOD_PRECOMPUTE_COUNT; i++)
265         {
266           if (ptrs[i])
267             precomputed_method_bindings_[i].push_back (Translator_method_binding (tr, ptrs[i]));
268         }
269     }
270
271   fetch_precomputable_methods (precomputed_self_method_bindings_);
272 }
273
274 void
275 Translator_group::precomputed_translator_foreach (Translator_precompute_index idx)
276 {
277   vector<Translator_method_binding> &bindings (precomputed_method_bindings_[idx]);
278   for (vsize i = 0; i < bindings.size (); i++)
279     bindings[i].invoke ();
280 }
281
282 void
283 Translator_group::fetch_precomputable_methods (Translator_group_void_method ptrs[])
284 {
285   for (int i = 0; i < TRANSLATOR_METHOD_PRECOMPUTE_COUNT; i++)
286     ptrs[i] = 0;
287 }
288
289 void
290 Translator_group::call_precomputed_self_method (Translator_precompute_index idx)
291 {
292   if (precomputed_self_method_bindings_[idx])
293     (*precomputed_self_method_bindings_[idx]) (this);
294 }
295
296 Translator_group::~Translator_group ()
297 {
298 }
299
300 #include "ly-smobs.icc"
301
302 IMPLEMENT_SMOBS (Translator_group);
303 IMPLEMENT_DEFAULT_EQUAL_P (Translator_group);
304 IMPLEMENT_TYPE_P (Translator_group, "ly:translator-group?");
305
306 int
307 Translator_group::print_smob (SCM s, SCM port, scm_print_state *)
308 {
309   Translator_group *me = (Translator_group *) SCM_CELL_WORD_1 (s);
310   scm_puts ("#<Translator_group ", port);
311   scm_puts (me->class_name (), port);
312   scm_display (me->simple_trans_list_, port);
313   scm_puts (" >", port);
314   return 1;
315 }
316
317 SCM
318 Translator_group::mark_smob (SCM smob)
319 {
320   Translator_group *me = (Translator_group *)SCM_CELL_WORD_1 (smob);
321
322   me->derived_mark ();
323   scm_gc_mark (me->protected_events_);
324   return me->simple_trans_list_;
325 }