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