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