Use `transform'.
[lilypond.git] / lily / translator.cc
blobae1dfbe7ff5158e4a755dd08047022b7044e80fe
1 /*
2 translator.cc -- implement Translator
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
9 #include "translator.hh"
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"
18 #include "translator.icc"
19 #include "ly-smobs.icc"
21 Translator::~Translator ()
25 void
26 Translator::init ()
28 must_be_last_ = false;
29 self_scm_ = SCM_EOL;
30 daddy_context_ = 0;
31 smobify_self ();
34 void
35 Translator::process_music ()
39 void
40 Translator::process_acknowledged ()
44 Translator::Translator ()
46 init ();
49 Translator::Translator (Translator const &src)
51 init ();
52 must_be_last_ = src.must_be_last_;
55 Moment
56 Translator::now_mom () const
58 return daddy_context_->now_mom ();
61 Output_def *
62 Translator::get_output_def () const
64 return daddy_context_->get_output_def ();
67 Translator_group *
68 Translator::get_daddy_translator () const
70 return daddy_context_->implementation ();
73 void
74 Translator::protect_event (SCM ev)
76 get_daddy_translator ()->protect_event (ev);
79 SCM
80 Translator::internal_get_property (SCM sym) const
82 return daddy_context_->internal_get_property (sym);
85 void
86 Translator::stop_translation_timestep ()
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.)
95 void
96 Translator::start_translation_timestep ()
100 void
101 Translator::initialize ()
105 void
106 Translator::finalize ()
110 void
111 Translator::connect_to_context (Context *c)
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_);
117 void
118 Translator::disconnect_from_context (Context *c)
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_);
124 static SCM listened_event_class_table;
125 void
126 ensure_listened_hash ()
128 if (!listened_event_class_table)
129 listened_event_class_table = scm_permanent_object (scm_c_make_hash_table (61));
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.")
137 ensure_listened_hash ();
138 return ly_hash_table_keys (listened_event_class_table);
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?")
145 ensure_listened_hash ();
146 return scm_hashq_ref (listened_event_class_table, sym, SCM_BOOL_F);
149 void
150 add_listened_event_class (SCM sym)
152 ensure_listened_hash ();
153 scm_hashq_set_x (listened_event_class_table, sym, SCM_BOOL_T);
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.
162 The method should only be called from the macro
163 IMPLEMENT_TRANSLATOR_LISTENER.
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)
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";
176 SCM class_sym = scm_str2symbol (name.c_str ());
178 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;
187 Helps the individual static_translator_description methods of translators.
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
196 SCM static_properties = SCM_EOL;
198 static_properties = scm_acons (ly_symbol2scm ("grobs-created"),
199 parse_symbol_list (grobs), static_properties);
201 static_properties = scm_acons (ly_symbol2scm ("description"),
202 scm_from_locale_string (desc), static_properties);
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);
210 static_properties = scm_acons (ly_symbol2scm ("properties-read"),
211 parse_symbol_list (read), static_properties);
213 static_properties = scm_acons (ly_symbol2scm ("properties-written"),
214 parse_symbol_list (write), static_properties);
216 return static_properties;
220 SMOBS
223 Translator::mark_smob (SCM sm)
225 Translator *me = (Translator *) SCM_CELL_WORD_1 (sm);
226 me->derived_mark ();
227 return SCM_EOL;
230 Global_context *
231 Translator::get_global_context () const
233 return daddy_context_->get_global_context ();
236 Context *
237 Translator::get_score_context () const
239 return daddy_context_->get_score_context ();
242 IMPLEMENT_SMOBS (Translator);
243 IMPLEMENT_DEFAULT_EQUAL_P (Translator);
244 IMPLEMENT_TYPE_P (Translator, "ly:translator?");
246 bool
247 Translator::must_be_last () const
249 return must_be_last_;
252 void
253 Translator::derived_mark () const
258 Translator::print_smob (SCM s, SCM port, scm_print_state *)
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;
267 void
268 add_acknowledger (Engraver_void_function_engraver_grob_info ptr,
269 char const *func_name,
270 vector<Acknowledge_information> *ack_array)
272 Acknowledge_information inf;
273 inf.function_ = ptr;
275 string interface_name (func_name);
277 interface_name = replace_all (interface_name, '_', '-');
278 interface_name += "-interface";
281 this is only called during program init, so safe to use scm_gc_protect_object ()
283 inf.symbol_ = scm_gc_protect_object (ly_symbol2scm (interface_name.c_str ()));
284 ack_array->push_back (inf);
287 Engraver_void_function_engraver_grob_info
288 generic_get_acknowledger (SCM sym, vector<Acknowledge_information> const *ack_array)
290 for (vsize i = 0; i < ack_array->size (); i++)
292 if (ack_array->at (i).symbol_ == sym)
293 return ack_array->at (i).function_;
295 return 0;
299 Moment
300 get_event_length (Stream_event *e)
302 Moment *m = unsmob_moment (e->get_property ("length"));
303 if (m)
304 return *m;
305 else
306 return Moment (0);
309 Moment
310 get_event_length (Stream_event *e, Moment now)
312 Moment len = get_event_length (e);
314 if (now.grace_part_)
316 len.grace_part_ = len.main_part_;
317 len.main_part_ = Rational (0);
319 return len;
323 Helper, used through ASSIGN_EVENT_ONCE to throw warnings for
324 simultaneous events. The helper is only useful in listen_* methods
325 of translators.
327 bool
328 internal_event_assignment (Stream_event **old_ev, Stream_event *new_ev, const char *function)
330 if (*old_ev &&
331 !to_boolean (scm_equal_p ((*old_ev)->self_scm (),
332 new_ev->self_scm ())))
334 /* extract event class from function name */
335 string ev_class = function;
337 /* This assertion fails if EVENT_ASSIGNMENT was called outside a
338 translator listener. Don't do that. */
339 const char *prefix = "listen_";
340 assert (0 == ev_class.find (prefix));
342 /* "listen_foo_bar" -> "foo-bar" */
343 ev_class.erase (0, strlen (prefix));
344 replace_all (ev_class, '_', '-');
346 new_ev->origin ()->warning (_f ("Two simultaneous %s events, junking this one", ev_class.c_str ()));
347 (*old_ev)->origin ()->warning (_f ("Previous %s event here", ev_class.c_str ()));
348 return false;
350 else
352 *old_ev = new_ev;
353 return true;
357 ADD_TRANSLATOR (Translator,
358 "Base class. Not instantiated.",
361 "");