]> git.donarmstrong.com Git - lilypond.git/blob - lily/translator.cc
Merge branch 'master' of git+ssh://jneem@git.sv.gnu.org/srv/git/lilypond
[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--2006 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            "Returns a list of all event classes that some translator listens to.")
136 {
137   ensure_listened_hash ();
138   return ly_hash_table_keys (listened_event_class_table);
139 }
140
141 LY_DEFINE (ly_is_listened_event_class, "ly:is-listened-event-class",
142            1, 0, 0, (SCM sym),
143            "Is @var{sym} a listened event class?")
144 {
145   ensure_listened_hash ();
146   return scm_hashq_ref (listened_event_class_table, sym, SCM_BOOL_F);
147 }
148
149 void
150 add_listened_event_class (SCM sym)
151 {
152   ensure_listened_hash ();
153   scm_hashq_set_x (listened_event_class_table, sym, SCM_BOOL_T);
154 }
155
156
157 /*
158   internally called once, statically, for each translator
159   listener. Connects the name of an event class with a procedure that
160   fetches the corresponding listener.
161
162   The method should only be called from the macro
163   IMPLEMENT_TRANSLATOR_LISTENER.
164  */
165 void
166 Translator::add_translator_listener (translator_listener_record **listener_list,
167                                      translator_listener_record *r,
168                                      Listener (*get_listener) (void *), 
169                                      const char *ev_class)
170 {
171   /* ev_class is the C++ identifier name. Convert to scm symbol */
172   string name = string (ev_class);
173   name = replace_all (name, '_', '-');
174   name += "-event";
175   
176   SCM class_sym = scm_str2symbol (name.c_str ());
177   
178   add_listened_event_class (class_sym);
179
180   r->event_class_ = class_sym;
181   r->get_listener_ = get_listener;
182   r->next_ = *listener_list;
183   *listener_list = r;
184 }
185
186 /*
187  Helps the individual static_translator_description methods of translators.
188 */
189 SCM
190 Translator::static_translator_description (const char *grobs,
191                                            const char *desc,
192                                            translator_listener_record *listener_list,
193                                            const char *read, 
194                                            const char *write) const
195 {
196   SCM static_properties = SCM_EOL;                                      
197
198   static_properties = scm_acons (ly_symbol2scm ("grobs-created"),       
199                                  parse_symbol_list (grobs), static_properties);
200   
201   static_properties = scm_acons (ly_symbol2scm ("description"), 
202                                  scm_from_locale_string (desc), static_properties); 
203   
204   SCM list = SCM_EOL;
205   for (; listener_list; listener_list = listener_list->next_)
206     list = scm_cons (listener_list->event_class_, list);
207   static_properties = scm_acons (ly_symbol2scm ("events-accepted"),
208                                  list, static_properties);
209   
210   static_properties = scm_acons (ly_symbol2scm ("properties-read"),     
211                                  parse_symbol_list (read), static_properties); 
212   
213   static_properties = scm_acons (ly_symbol2scm ("properties-written"), 
214                                  parse_symbol_list (write), static_properties); 
215   
216   return static_properties;                                             
217 }
218   
219 /*
220   SMOBS
221 */
222 SCM
223 Translator::mark_smob (SCM sm)
224 {
225   Translator *me = (Translator *) SCM_CELL_WORD_1 (sm);
226   me->derived_mark ();
227   return SCM_EOL;
228 }
229
230 Global_context *
231 Translator::get_global_context () const
232 {
233   return daddy_context_->get_global_context ();
234 }
235
236 Context *
237 Translator::get_score_context () const
238 {
239   return daddy_context_->get_score_context ();
240 }
241
242 IMPLEMENT_SMOBS (Translator);
243 IMPLEMENT_DEFAULT_EQUAL_P (Translator);
244 IMPLEMENT_TYPE_P (Translator, "ly:translator?");
245
246 bool
247 Translator::must_be_last () const
248 {
249   return must_be_last_;
250 }
251
252 void
253 Translator::derived_mark () const
254 {
255 }
256
257 int
258 Translator::print_smob (SCM s, SCM port, scm_print_state *)
259 {
260   Translator *me = (Translator *) SCM_CELL_WORD_1 (s);
261   scm_puts ("#<Translator ", port);
262   scm_puts (me->class_name (), port);
263   scm_puts (" >", port);
264   return 1;
265 }
266
267 void
268 add_acknowledger (Engraver_void_function_engraver_grob_info ptr,
269                   char const *func_name,
270                   vector<Acknowledge_information> *ack_array)
271 {
272   Acknowledge_information inf;
273   inf.function_ = ptr;
274
275   string interface_name (func_name);
276
277   interface_name = replace_all (interface_name, '_', '-');
278   interface_name += "-interface";
279
280   /*
281     this is only called during program init, so safe to use scm_gc_protect_object()
282   */
283   inf.symbol_ = scm_gc_protect_object (ly_symbol2scm (interface_name.c_str ()));
284   ack_array->push_back (inf);
285 }
286
287 Engraver_void_function_engraver_grob_info
288 generic_get_acknowledger (SCM sym, vector<Acknowledge_information> const *ack_array)
289 {
290   for (vsize i = 0; i < ack_array->size (); i++)
291     {
292       if (ack_array->at (i).symbol_ == sym)
293         return ack_array->at (i).function_;
294     }
295   return 0;
296 }
297
298 Moment
299 get_event_length (Stream_event *e)
300 {
301   Moment *m = unsmob_moment (e->get_property ("length"));
302   if (m)
303     return *m;
304   else
305     return Moment (0);
306 }
307
308 /*
309   Helper, used through ASSIGN_EVENT_ONCE to throw warnings for
310   simultaneous events. The helper is only useful in listen_* methods
311   of translators.
312 */
313 bool
314 internal_event_assignment (Stream_event **old_ev, Stream_event *new_ev, const char *function)
315 {
316   if (*old_ev &&
317       !to_boolean (scm_equal_p ((*old_ev)->self_scm (), 
318                                new_ev->self_scm ())))
319     {
320       /* extract event class from function name */
321       string ev_class = function;
322
323       /* This assertion fails if EVENT_ASSIGNMENT was called outside a
324          translator listener. Don't do that. */
325       const char *prefix = "listen_";
326       assert (0 == ev_class.find (prefix));
327
328       /* "listen_foo_bar" -> "foo-bar" */
329       ev_class.erase (0, strlen(prefix));
330       replace_all (ev_class, '_', '-');
331
332       new_ev->origin ()->warning (_f ("Two simultaneous %s events, junking this one", ev_class.c_str ()));
333       (*old_ev)->origin ()->warning (_f ("Previous %s event here", ev_class.c_str ()));
334       return false;
335     }
336   else
337     {
338       *old_ev = new_ev;
339       return true;
340     }
341 }
342
343 ADD_TRANSLATOR (Translator,
344                 "Base class. Not instantiated.",
345                 "",
346                 "",
347                 "");