]> git.donarmstrong.com Git - lilypond.git/blob - lily/translator-group.cc
LSR: update.
[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,
218                           Translator_group_method tg_ptr, Direction dir)
219 {
220   Translator_group *tg
221     = dynamic_cast<Translator_group *> (c->implementation ());
222
223   if (tg && dir == DOWN)
224     {
225       (tg->*tg_ptr) ();
226       translator_each (tg->get_simple_trans_list (), ptr);
227     }
228
229   for (SCM s = c->children_contexts (); scm_is_pair (s);
230        s = scm_cdr (s))
231     recurse_over_translators (unsmob_context (scm_car (s)), ptr, tg_ptr, dir);
232
233   if (tg && dir == UP)
234     {
235       translator_each (tg->get_simple_trans_list (),
236                        ptr);
237
238       (tg->*tg_ptr) ();
239     }
240 }
241
242 Translator_group::Translator_group ()
243 {
244   simple_trans_list_ = SCM_EOL;
245   protected_events_ = SCM_EOL;
246   context_ = 0;
247   smobify_self ();
248 }
249
250 void
251 Translator_group::derived_mark () const
252 {
253 }
254
255 void
256 Translator_group::precompute_method_bindings ()
257 {
258   for (SCM s = simple_trans_list_; scm_is_pair (s); s = scm_cdr (s))
259     {
260       Translator *tr = unsmob_translator (scm_car (s));
261       Translator_void_method_ptr ptrs[TRANSLATOR_METHOD_PRECOMPUTE_COUNT];
262       tr->fetch_precomputable_methods (ptrs);
263
264       assert (tr);
265       for (int i = 0; i < TRANSLATOR_METHOD_PRECOMPUTE_COUNT; i++)
266         {
267           if (ptrs[i])
268             precomputed_method_bindings_[i].push_back (Translator_method_binding (tr, ptrs[i]));
269         }
270     }
271
272   fetch_precomputable_methods (precomputed_self_method_bindings_);
273 }
274
275 void
276 Translator_group::precomputed_translator_foreach (Translator_precompute_index idx)
277 {
278   vector<Translator_method_binding> &bindings (precomputed_method_bindings_[idx]);
279   for (vsize i = 0; i < bindings.size (); i++)
280     bindings[i].invoke ();
281 }
282
283 void
284 Translator_group::fetch_precomputable_methods (Translator_group_void_method ptrs[])
285 {
286   for (int i = 0; i < TRANSLATOR_METHOD_PRECOMPUTE_COUNT; i++)
287     ptrs[i] = 0;
288 }
289
290 void
291 Translator_group::call_precomputed_self_method (Translator_precompute_index idx)
292 {
293   if (precomputed_self_method_bindings_[idx])
294     (*precomputed_self_method_bindings_[idx]) (this);
295 }
296
297 Translator_group::~Translator_group ()
298 {
299 }
300
301 #include "ly-smobs.icc"
302
303 IMPLEMENT_SMOBS (Translator_group);
304 IMPLEMENT_DEFAULT_EQUAL_P (Translator_group);
305 IMPLEMENT_TYPE_P (Translator_group, "ly:translator-group?");
306
307 int
308 Translator_group::print_smob (SCM s, SCM port, scm_print_state *)
309 {
310   Translator_group *me = (Translator_group *) SCM_CELL_WORD_1 (s);
311   scm_puts ("#<Translator_group ", port);
312   scm_puts (me->class_name (), port);
313   scm_display (me->simple_trans_list_, port);
314   scm_puts (" >", port);
315   return 1;
316 }
317
318 SCM
319 Translator_group::mark_smob (SCM smob)
320 {
321   Translator_group *me = (Translator_group *)SCM_CELL_WORD_1 (smob);
322
323   me->derived_mark ();
324   scm_gc_mark (me->protected_events_);
325   return me->simple_trans_list_;
326 }