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