]> git.donarmstrong.com Git - lilypond.git/blob - lily/translator.cc
* scm/define-event-classes.scm (lambda): use ly:is-listened-event-class
[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 bool
56 Translator::try_music (Music *)
57 {
58   return false;
59 }
60
61 Moment
62 Translator::now_mom () const
63 {
64   return daddy_context_->now_mom ();
65 }
66
67 Output_def *
68 Translator::get_output_def () const
69 {
70   return daddy_context_->get_output_def ();
71 }
72
73 Translator_group *
74 Translator::get_daddy_translator () const
75 {
76   return daddy_context_->implementation ();
77 }
78
79 void
80 Translator::protect_event (SCM ev)
81 {
82   get_daddy_translator ()->protect_event (ev);
83 }
84
85 SCM
86 Translator::internal_get_property (SCM sym) const
87 {
88   return daddy_context_->internal_get_property (sym);
89 }
90
91 void
92 Translator::stop_translation_timestep ()
93 {
94 }
95
96 /*
97   this function has 2 properties
98
99   - It is called before try_music ()
100
101   - It is called before any user information enters the translators.
102   (i.e. any \property or event is not processed yet.)
103 */
104 void
105 Translator::start_translation_timestep ()
106 {
107 }
108
109 void
110 Translator::initialize ()
111 {
112 }
113
114 void
115 Translator::finalize ()
116 {
117 }
118
119 void
120 Translator::connect_to_context (Context *c)
121 {
122   for (translator_listener_record *r = get_listener_list (); r; r=r->next_)
123     c->events_below ()->add_listener (r->get_listener_ (this), r->event_class_);
124 }
125
126 void
127 Translator::disconnect_from_context (Context *c)
128 {
129   for (translator_listener_record *r = get_listener_list (); r; r=r->next_)
130     c->events_below ()->remove_listener (r->get_listener_ (this), r->event_class_);
131 }
132
133 static SCM listened_event_class_table;
134 void
135 ensure_listened_hash ()
136 {
137   if (!listened_event_class_table)
138     listened_event_class_table = scm_permanent_object (scm_c_make_hash_table (61));
139 }
140
141
142 LY_DEFINE (ly_get_listened_event_classes, "ly:get-listened-event-classes",
143            0, 0, 0, (),
144            "Returns a list of all event classes that some translator listens to.")
145 {
146   ensure_listened_hash ();
147   return ly_hash_table_keys (listened_event_class_table);
148 }
149
150 LY_DEFINE (ly_is_listened_event_class, "ly:is-listened-event-class",
151            1, 0, 0, (SCM sym),
152            "Is @var{sym} a listened event class?")
153 {
154   ensure_listened_hash ();
155   return scm_hashq_ref (listened_event_class_table, sym, SCM_BOOL_F);
156 }
157
158 void
159 add_listened_event_class (SCM sym)
160 {
161   ensure_listened_hash ();
162
163   scm_hashq_set_x (listened_event_class_table, sym, SCM_BOOL_T);
164 }
165
166
167 /*
168   internally called once, statically, for each translator
169   listener. Connects the name of an event class with a procedure that
170   fetches the corresponding listener.
171
172   The method should only be called from the macro
173   IMPLEMENT_TRANSLATOR_LISTENER.
174  */
175 void
176 Translator::add_translator_listener (translator_listener_record **listener_list,
177                                      translator_listener_record *r,
178                                      Listener (*get_listener) (void *), 
179                                      const char *ev_class)
180 {
181   /* ev_class is the C++ identifier name. Convert to scm symbol */
182   string name = string (ev_class);
183   name = replace_all (name, '_', '-');
184   name += "-event";
185   
186   /* It's OK to use scm_gc_protect_object for protection, because r is
187      statically allocated. */
188   // NO it's damn not !!!! --hwn
189   SCM class_sym = scm_str2symbol (name.c_str ());
190   
191   add_listened_event_class (class_sym);
192   r->event_class_ = class_sym;
193   r->get_listener_ = get_listener;
194   r->next_ = *listener_list;
195   *listener_list = r;
196 }
197
198 /*
199   SMOBS
200 */
201 SCM
202 Translator::mark_smob (SCM sm)
203 {
204   Translator *me = (Translator *) SCM_CELL_WORD_1 (sm);
205   me->derived_mark ();
206   return SCM_EOL;
207 }
208
209 Global_context *
210 Translator::get_global_context () const
211 {
212   return daddy_context_->get_global_context ();
213 }
214
215 Context *
216 Translator::get_score_context () const
217 {
218   return daddy_context_->get_score_context ();
219 }
220
221 IMPLEMENT_SMOBS (Translator);
222 IMPLEMENT_DEFAULT_EQUAL_P (Translator);
223 IMPLEMENT_TYPE_P (Translator, "ly:translator?");
224
225 bool
226 Translator::must_be_last () const
227 {
228   return must_be_last_;
229 }
230
231 void
232 Translator::derived_mark () const
233 {
234 }
235
236 int
237 Translator::print_smob (SCM s, SCM port, scm_print_state *)
238 {
239   Translator *me = (Translator *) SCM_CELL_WORD_1 (s);
240   scm_puts ("#<Translator ", port);
241   scm_puts (me->class_name (), port);
242   scm_puts (" >", port);
243   return 1;
244 }
245
246 void
247 add_acknowledger (Engraver_void_function_engraver_grob_info ptr,
248                   char const *func_name,
249                   vector<Acknowledge_information> *ack_array)
250 {
251   Acknowledge_information inf;
252   inf.function_ = ptr;
253
254   string interface_name (func_name);
255
256   interface_name = replace_all (interface_name, '_', '-');
257   interface_name += "-interface";
258
259   inf.symbol_ = ly_symbol2scm (interface_name.c_str ());
260   ack_array->push_back (inf);
261 }
262
263 Engraver_void_function_engraver_grob_info
264 generic_get_acknowledger (SCM sym, vector<Acknowledge_information> const *ack_array)
265 {
266   for (vsize i = 0; i < ack_array->size (); i++)
267     {
268       if (ack_array->at (i).symbol_ == sym)
269         return ack_array->at (i).function_;
270     }
271   return 0;
272 }
273
274 Moment
275 get_event_length (Stream_event *e)
276 {
277   Moment *m = unsmob_moment (e->get_property ("length"));
278   if (m)
279     return *m;
280   else
281     return Moment (0);
282 }
283
284 /*
285   Helper, used through ASSIGN_EVENT_ONCE to throw warnings for
286   simultaneous events. The helper is only useful in listen_* methods
287   of translators.
288 */
289 bool
290 internal_event_assignment (Stream_event **old_ev, Stream_event *new_ev, const char *function)
291 {
292   if (*old_ev)
293     {
294       /* extract event class from function name */
295       const char *prefix = "listen_";
296       assert (!strncmp (function, "listen_", strlen (prefix)));
297       function += strlen (prefix);
298       char ev_class[strlen (function) + 1];
299       strcpy (ev_class, function);
300       for (char *c = ev_class; *c; c++)
301         if (*c == '_')
302           *c = '-';
303
304       new_ev->origin ()->warning (_f ("Two simultaneous %s events, junking this one", ev_class));
305       (*old_ev)->origin ()->warning (_f ("Previous %s event here", ev_class));
306       return false;
307     }
308   else
309     {
310       *old_ev = new_ev;
311       return true;
312     }
313 }
314
315 ADD_TRANSLATOR (Translator,
316                 "Base class. Unused",
317                 "",
318                 "",
319                 "",
320                 "");