]> git.donarmstrong.com Git - lilypond.git/blob - lily/translator.cc
dc70c155ce97058e9491a598360ceb7f3d19012c
[lilypond.git] / lily / translator.cc
1 /*
2   translator.cc -- implement Translator
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include "translator.hh"
10
11 #include "context-def.hh"
12 #include "dispatcher.hh"
13 #include "global-context.hh"
14 #include "international.hh"
15 #include "translator-group.hh"
16 #include "warn.hh"
17
18 #include "translator.icc"
19 #include "ly-smobs.icc"
20
21 Translator::~Translator ()
22 {
23 }
24
25 void
26 Translator::init ()
27 {
28   must_be_last_ = false;
29   self_scm_ = SCM_EOL;
30   daddy_context_ = 0;
31   smobify_self ();
32 }
33
34 void
35 Translator::process_music ()
36 {
37 }
38
39 void
40 Translator::process_acknowledged ()
41 {
42 }
43
44 Translator::Translator ()
45 {
46   init ();
47 }
48
49 Translator::Translator (Translator const &src)
50 {
51   init ();
52   must_be_last_ = src.must_be_last_;
53 }
54
55 Moment
56 Translator::now_mom () const
57 {
58   return daddy_context_->now_mom ();
59 }
60
61 Output_def *
62 Translator::get_output_def () const
63 {
64   return daddy_context_->get_output_def ();
65 }
66
67 Translator_group *
68 Translator::get_daddy_translator () const
69 {
70   return daddy_context_->implementation ();
71 }
72
73 void
74 Translator::protect_event (SCM ev)
75 {
76   get_daddy_translator ()->protect_event (ev);
77 }
78
79 SCM
80 Translator::internal_get_property (SCM sym) const
81 {
82   return daddy_context_->internal_get_property (sym);
83 }
84
85 void
86 Translator::stop_translation_timestep ()
87 {
88 }
89
90 /*
91   this function is called once each moment, before any user
92   information enters the translators.  (i.e. no \property or event has
93   been processed yet.)
94 */
95 void
96 Translator::start_translation_timestep ()
97 {
98 }
99
100 void
101 Translator::initialize ()
102 {
103 }
104
105 void
106 Translator::finalize ()
107 {
108 }
109
110 void
111 Translator::connect_to_context (Context *c)
112 {
113   for (translator_listener_record *r = get_listener_list (); r; r=r->next_)
114     c->events_below ()->add_listener (r->get_listener_ (this), r->event_class_);
115 }
116
117 void
118 Translator::disconnect_from_context (Context *c)
119 {
120   for (translator_listener_record *r = get_listener_list (); r; r=r->next_)
121     c->events_below ()->remove_listener (r->get_listener_ (this), r->event_class_);
122 }
123
124 static SCM listened_event_class_table;
125 void
126 ensure_listened_hash ()
127 {
128   if (!listened_event_class_table)
129     listened_event_class_table = scm_permanent_object (scm_c_make_hash_table (61));
130 }
131
132
133 LY_DEFINE (ly_get_listened_event_classes, "ly:get-listened-event-classes",
134            0, 0, 0, (),
135            "Return a list of all event classes that some translator listens"
136            " to.")
137 {
138   ensure_listened_hash ();
139   return ly_hash_table_keys (listened_event_class_table);
140 }
141
142 LY_DEFINE (ly_is_listened_event_class, "ly:is-listened-event-class",
143            1, 0, 0, (SCM sym),
144            "Is @var{sym} a listened event class?")
145 {
146   ensure_listened_hash ();
147   return scm_hashq_ref (listened_event_class_table, sym, SCM_BOOL_F);
148 }
149
150 void
151 add_listened_event_class (SCM sym)
152 {
153   ensure_listened_hash ();
154   scm_hashq_set_x (listened_event_class_table, sym, SCM_BOOL_T);
155 }
156
157
158 /*
159   internally called once, statically, for each translator
160   listener. Connects the name of an event class with a procedure that
161   fetches the corresponding listener.
162
163   The method should only be called from the macro
164   IMPLEMENT_TRANSLATOR_LISTENER.
165  */
166 void
167 Translator::add_translator_listener (translator_listener_record **listener_list,
168                                      translator_listener_record *r,
169                                      Listener (*get_listener) (void *), 
170                                      const char *ev_class)
171 {
172   /* ev_class is the C++ identifier name. Convert to scm symbol */
173   string name = string (ev_class);
174   name = replace_all (&name, '_', '-');
175   name += "-event";
176   
177   SCM class_sym = scm_str2symbol (name.c_str ());
178   
179   add_listened_event_class (class_sym);
180
181   r->event_class_ = class_sym;
182   r->get_listener_ = get_listener;
183   r->next_ = *listener_list;
184   *listener_list = r;
185 }
186
187 /*
188  Helps the individual static_translator_description methods of translators.
189 */
190 SCM
191 Translator::static_translator_description (const char *grobs,
192                                            const char *desc,
193                                            translator_listener_record *listener_list,
194                                            const char *read, 
195                                            const char *write) const
196 {
197   SCM static_properties = SCM_EOL;                                      
198
199   static_properties = scm_acons (ly_symbol2scm ("grobs-created"),       
200                                  parse_symbol_list (grobs), static_properties);
201   
202   static_properties = scm_acons (ly_symbol2scm ("description"), 
203                                  scm_from_locale_string (desc), static_properties); 
204   
205   SCM list = SCM_EOL;
206   for (; listener_list; listener_list = listener_list->next_)
207     list = scm_cons (listener_list->event_class_, list);
208   static_properties = scm_acons (ly_symbol2scm ("events-accepted"),
209                                  list, static_properties);
210   
211   static_properties = scm_acons (ly_symbol2scm ("properties-read"),     
212                                  parse_symbol_list (read), static_properties); 
213   
214   static_properties = scm_acons (ly_symbol2scm ("properties-written"), 
215                                  parse_symbol_list (write), static_properties); 
216   
217   return static_properties;                                             
218 }
219   
220 /*
221   SMOBS
222 */
223 SCM
224 Translator::mark_smob (SCM sm)
225 {
226   Translator *me = (Translator *) SCM_CELL_WORD_1 (sm);
227   me->derived_mark ();
228   return SCM_EOL;
229 }
230
231 Global_context *
232 Translator::get_global_context () const
233 {
234   return daddy_context_->get_global_context ();
235 }
236
237 Context *
238 Translator::get_score_context () const
239 {
240   return daddy_context_->get_score_context ();
241 }
242
243 IMPLEMENT_SMOBS (Translator);
244 IMPLEMENT_DEFAULT_EQUAL_P (Translator);
245 IMPLEMENT_TYPE_P (Translator, "ly:translator?");
246
247 bool
248 Translator::must_be_last () const
249 {
250   return must_be_last_;
251 }
252
253 void
254 Translator::derived_mark () const
255 {
256 }
257
258 int
259 Translator::print_smob (SCM s, SCM port, scm_print_state *)
260 {
261   Translator *me = (Translator *) SCM_CELL_WORD_1 (s);
262   scm_puts ("#<Translator ", port);
263   scm_puts (me->class_name (), port);
264   scm_puts (" >", port);
265   return 1;
266 }
267
268 void
269 add_acknowledger (Engraver_void_function_engraver_grob_info ptr,
270                   char const *func_name,
271                   vector<Acknowledge_information> *ack_array)
272 {
273   Acknowledge_information inf;
274   inf.function_ = ptr;
275
276   string interface_name (func_name);
277
278   interface_name = replace_all (&interface_name, '_', '-');
279   interface_name += "-interface";
280
281   /*
282     this is only called during program init, so safe to use scm_gc_protect_object ()
283   */
284   inf.symbol_ = scm_gc_protect_object (ly_symbol2scm (interface_name.c_str ()));
285   ack_array->push_back (inf);
286 }
287
288 Engraver_void_function_engraver_grob_info
289 generic_get_acknowledger (SCM sym, vector<Acknowledge_information> const *ack_array)
290 {
291   for (vsize i = 0; i < ack_array->size (); i++)
292     {
293       if (ack_array->at (i).symbol_ == sym)
294         return ack_array->at (i).function_;
295     }
296   return 0;
297 }
298
299
300 Moment
301 get_event_length (Stream_event *e)
302 {
303   Moment *m = unsmob_moment (e->get_property ("length"));
304   if (m)
305     return *m;
306   else
307     return Moment (0);
308 }
309
310 Moment
311 get_event_length (Stream_event *e, Moment now)
312 {
313   Moment len = get_event_length (e);
314   
315   if (now.grace_part_)
316     {
317       len.grace_part_ = len.main_part_;
318       len.main_part_ = Rational (0);
319     }
320   return len;
321 }
322
323 /*
324   Helper, used through ASSIGN_EVENT_ONCE to throw warnings for
325   simultaneous events. The helper is only useful in listen_* methods
326   of translators.
327 */
328 bool
329 internal_event_assignment (Stream_event **old_ev, Stream_event *new_ev, const char *function)
330 {
331   if (*old_ev &&
332       !to_boolean (scm_equal_p ((*old_ev)->self_scm (), 
333                                new_ev->self_scm ())))
334     {
335       /* extract event class from function name */
336       string ev_class = function;
337
338       /* This assertion fails if EVENT_ASSIGNMENT was called outside a
339          translator listener. Don't do that. */
340       const char *prefix = "listen_";
341       assert (0 == ev_class.find (prefix));
342
343       /* "listen_foo_bar" -> "foo-bar" */
344       ev_class.erase (0, strlen (prefix));
345       replace_all (&ev_class, '_', '-');
346
347       new_ev->origin ()->warning (_f ("Two simultaneous %s events, junking this one", ev_class.c_str ()));
348       (*old_ev)->origin ()->warning (_f ("Previous %s event here", ev_class.c_str ()));
349       return false;
350     }
351   else
352     {
353       *old_ev = new_ev;
354       return true;
355     }
356 }
357
358 ADD_TRANSLATOR (Translator,
359                 /* doc */
360                 "Base class.  Not instantiated.",
361
362                 /* create */
363                 "",
364
365                 /* read */
366                 "",
367
368                 /* write */
369                 ""
370                 );