]> git.donarmstrong.com Git - lilypond.git/blob - lily/translator.cc
* lily/translator.cc, lily/context.cc:, lily/translator-group.cc:
[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
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   r->event_class_ = class_sym;
181   r->get_listener_ = get_listener;
182   r->next_ = *listener_list;
183   *listener_list = r;
184 }
185
186 /*
187   SMOBS
188 */
189 SCM
190 Translator::mark_smob (SCM sm)
191 {
192   Translator *me = (Translator *) SCM_CELL_WORD_1 (sm);
193   me->derived_mark ();
194   return SCM_EOL;
195 }
196
197 Global_context *
198 Translator::get_global_context () const
199 {
200   return daddy_context_->get_global_context ();
201 }
202
203 Context *
204 Translator::get_score_context () const
205 {
206   return daddy_context_->get_score_context ();
207 }
208
209 IMPLEMENT_SMOBS (Translator);
210 IMPLEMENT_DEFAULT_EQUAL_P (Translator);
211 IMPLEMENT_TYPE_P (Translator, "ly:translator?");
212
213 bool
214 Translator::must_be_last () const
215 {
216   return must_be_last_;
217 }
218
219 void
220 Translator::derived_mark () const
221 {
222 }
223
224 int
225 Translator::print_smob (SCM s, SCM port, scm_print_state *)
226 {
227   Translator *me = (Translator *) SCM_CELL_WORD_1 (s);
228   scm_puts ("#<Translator ", port);
229   scm_puts (me->class_name (), port);
230   scm_puts (" >", port);
231   return 1;
232 }
233
234 void
235 add_acknowledger (Engraver_void_function_engraver_grob_info ptr,
236                   char const *func_name,
237                   vector<Acknowledge_information> *ack_array)
238 {
239   Acknowledge_information inf;
240   inf.function_ = ptr;
241
242   string interface_name (func_name);
243
244   interface_name = replace_all (interface_name, '_', '-');
245   interface_name += "-interface";
246
247   /*
248     this is only called during program init, so safe to use scm_gc_protect_object()
249   */
250   inf.symbol_ = scm_gc_protect_object (ly_symbol2scm (interface_name.c_str ()));
251   ack_array->push_back (inf);
252 }
253
254 Engraver_void_function_engraver_grob_info
255 generic_get_acknowledger (SCM sym, vector<Acknowledge_information> const *ack_array)
256 {
257   for (vsize i = 0; i < ack_array->size (); i++)
258     {
259       if (ack_array->at (i).symbol_ == sym)
260         return ack_array->at (i).function_;
261     }
262   return 0;
263 }
264
265 Moment
266 get_event_length (Stream_event *e)
267 {
268   Moment *m = unsmob_moment (e->get_property ("length"));
269   if (m)
270     return *m;
271   else
272     return Moment (0);
273 }
274
275 /*
276   Helper, used through ASSIGN_EVENT_ONCE to throw warnings for
277   simultaneous events. The helper is only useful in listen_* methods
278   of translators.
279 */
280 bool
281 internal_event_assignment (Stream_event **old_ev, Stream_event *new_ev, const char *function)
282 {
283   if (*old_ev)
284     {
285       /* extract event class from function name */
286       const char *prefix = "listen_";
287       string ev_class = function;
288       /* This assertion fails if EVENT_ASSIGNMENT was called outside a
289          translator listener. Don't do that. */
290       assert (0 == ev_class.find (prefix));
291
292       /* "listen_foo_bar" -> "foo-bar" */
293       ev_class.erase (0, strlen(prefix));
294       replace_all (ev_class, '_', '-');
295
296       new_ev->origin ()->warning (_f ("Two simultaneous %s events, junking this one", ev_class.c_str ()));
297       (*old_ev)->origin ()->warning (_f ("Previous %s event here", ev_class.c_str ()));
298       return false;
299     }
300   else
301     {
302       *old_ev = new_ev;
303       return true;
304     }
305 }
306
307 ADD_TRANSLATOR (Translator,
308                 "Base class. Unused",
309                 "",
310                 "",
311                 "",
312                 "");