]> git.donarmstrong.com Git - lilypond.git/blob - lily/context.cc
* scm/framework-gnome.scm (item-event): Print grob id.
[lilypond.git] / lily / context.cc
1 /*   
2   context.cc --  implement Context
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2004 Han-Wen Nienhuys <hanwen@xs4all.nl>
7
8 */
9
10 #include "context-def.hh"
11 #include "context-selector.hh"
12 #include "context.hh"
13 #include "ly-smobs.icc"
14 #include "main.hh"
15 #include "output-def.hh"
16 #include "scm-hash.hh"
17 #include "score-context.hh"
18 #include "translator-group.hh"
19 #include "warn.hh"
20
21 bool
22 Context::is_removable () const
23 {
24   return context_list_ == SCM_EOL && ! iterator_count_ &&
25           !dynamic_cast<Score_context const*> (this);
26 }
27
28 void
29 Context::check_removal ()
30 {
31   for (SCM p = context_list_; scm_is_pair (p); p = scm_cdr (p))
32     {
33       Context *trg = unsmob_context (scm_car (p));
34
35       trg->check_removal ();
36       if (trg->is_removable ())
37         {
38           recurse_over_translators (trg, &Translator::finalize, UP);
39           remove_context (trg);
40         }
41     }
42 }
43
44 Context::Context (Context const&)
45 {
46   assert (false);
47 }
48
49 Scheme_hash_table *
50 Context::properties_dict () const
51 {
52   return Scheme_hash_table::unsmob (properties_scm_);
53 }
54
55 void
56 Context::add_context (Context *t)
57 {
58   SCM ts = t->self_scm ();
59   context_list_ = ly_append2 (context_list_,
60                               scm_cons (ts, SCM_EOL));
61   
62   t->daddy_context_ = this;
63   if (!t->init_)
64     {
65       t->init_ = true;
66       Context_selector::register_context (t);
67         
68       scm_gc_unprotect_object (ts);
69       Context_def *td = unsmob_context_def (t->definition_);
70
71       /*
72         this can not move before add_context (), because \override
73         operations require that we are in the hierarchy.
74       */
75       td->apply_default_property_operations (t);
76
77       recurse_over_translators (t, &Translator::initialize, DOWN);
78     }
79 }
80
81 Context::Context ()
82 {
83   daddy_context_ = 0;
84   init_ = false;
85   aliases_ = SCM_EOL;
86   iterator_count_  = 0;
87   implementation_ = SCM_EOL;
88   properties_scm_ = SCM_EOL;
89   accepts_list_ = SCM_EOL;
90   context_list_ = SCM_EOL;
91   definition_ = SCM_EOL;
92   
93   smobify_self ();
94
95   properties_scm_ = (new Scheme_hash_table)->self_scm ();
96   scm_gc_unprotect_object (properties_scm_);
97 }
98
99
100
101 Context*
102 Context::find_create_context (SCM n, String id,
103                               SCM operations)
104 {
105   /*
106     Don't create multiple score contexts.
107    */
108   if (dynamic_cast<Global_context*> (this)
109       && dynamic_cast<Global_context*> (this)->get_score_context ())
110     return get_score_context ()->find_create_context (n, id, operations);
111     
112   
113   Context * existing = find_context_below (this, n,id);
114   if (existing)
115     return existing;
116
117   if (n == ly_symbol2scm ("Bottom"))
118     {
119       Context* tg = get_default_interpreter ();
120       tg->id_string_ = id;
121       return tg;
122     }
123
124   /*
125     TODO: use accepts_list_.
126    */
127   Link_array<Context_def> path
128     = unsmob_context_def (definition_)->path_to_acceptable_context (n, get_output_def ());
129
130   if (path.size ())
131     {
132       Context * current = this;
133
134       // start at 1.  The first one (index 0) will be us.
135       for (int i=0; i < path.size (); i++)
136         {
137           SCM ops = (i == path.size () -1) ? operations : SCM_EOL;
138
139           Context * new_group
140             = path[i]->instantiate (ops);
141
142           if (i == path.size () -1)
143             {
144               new_group->id_string_ = id;
145             }
146
147           current->add_context (new_group);
148           apply_property_operations (new_group, ops);
149           
150           current = new_group;
151         }
152
153       return current;
154     }
155
156   /*
157     Don't go up to Global_context, because global goes down to
158     Score_context
159    */
160   Context *ret = 0;
161   if (daddy_context_ && !dynamic_cast<Global_context*> (daddy_context_))
162     ret = daddy_context_->find_create_context (n, id, operations);
163   else
164     {
165       warning (_f ("Cannot find or create `%s' called `%s'",
166                    ly_symbol2string (n).to_str0 (), id));
167       ret =0;
168     }
169   return ret;
170 }
171
172 /*
173   Default child context as a SCM string, or something else if there is
174   none.
175 */
176 SCM
177 Context::default_child_context_name () const
178 {
179   return scm_is_pair (accepts_list_)
180     ? scm_car (scm_last_pair (accepts_list_))
181     : SCM_EOL;
182 }
183
184
185 bool
186 Context::is_bottom_context () const
187 {
188   return !scm_is_symbol (default_child_context_name ());
189 }
190
191 Context*
192 Context::get_default_interpreter ()
193 {
194   if (!is_bottom_context ())
195     {
196       SCM nm = default_child_context_name ();
197       SCM st = find_context_def (get_output_def (), nm);
198
199       Context_def *t = unsmob_context_def (st);
200       if (!t)
201         {
202           warning (_f ("can't find or create: `%s'", ly_symbol2string (nm).to_str0 ()));
203           t = unsmob_context_def (this->definition_);
204         }
205       Context *tg = t->instantiate (SCM_EOL);
206       add_context (tg);
207       if (!tg->is_bottom_context ())
208         return tg->get_default_interpreter ();
209       else
210         return tg;
211     }
212   return this;
213 }
214
215 /*
216   PROPERTIES
217  */
218 Context*
219 Context::where_defined (SCM sym) const
220 {
221   if (properties_dict ()->contains (sym))
222     {
223       return (Context*)this;
224     }
225
226   return (daddy_context_) ? daddy_context_->where_defined (sym) : 0;
227 }
228
229 /*
230   return SCM_EOL when not found.
231 */
232 SCM
233 Context::internal_get_property (SCM sym) const
234 {
235   SCM val =SCM_EOL;
236   if (properties_dict ()->try_retrieve (sym, &val))
237     return val;
238
239   if (daddy_context_)
240     return daddy_context_->internal_get_property (sym);
241   
242   return val;
243 }
244
245 bool
246 Context::is_alias (SCM sym) const
247 {
248   if (sym == ly_symbol2scm ("Bottom")
249       && !scm_is_pair (accepts_list_))
250     return true;
251   if (sym == unsmob_context_def (definition_)->get_context_name ())
252     return true;
253   
254   return scm_c_memq (sym, aliases_) != SCM_BOOL_F;
255 }
256
257 void
258 Context::add_alias (SCM sym)
259 {
260   aliases_ = scm_cons (sym, aliases_);
261 }
262
263
264
265 void
266 Context::internal_set_property (SCM sym, SCM val)
267 {
268 #ifndef NDEBUG
269   if (internal_type_checking_global_b)
270     assert (type_check_assignment (sym, val, ly_symbol2scm ("translation-type?")));
271 #endif
272   
273   properties_dict ()->set (sym, val);
274 }
275
276 /*
277   TODO: look up to check whether we have inherited var? 
278  */
279 void
280 Context::unset_property (SCM sym)
281 {
282   properties_dict ()->remove (sym);
283 }
284
285 /**
286    Remove a context from the hierarchy.
287  */
288 Context *
289 Context::remove_context (Context*trans)
290 {
291   assert (trans);
292
293   context_list_ = scm_delq_x (trans->self_scm (), context_list_);
294   trans->daddy_context_ = 0;
295   return trans;
296 }
297
298 /*
299   ID == "" means accept any ID.
300  */
301 Context *
302 find_context_below (Context * where,
303                     SCM type, String id)
304 {
305   if (where->is_alias (type))
306     {
307       if (id == "" || where->id_string () == id)
308         return where;
309     }
310   
311   Context *found = 0;
312   for (SCM s = where->children_contexts ();
313        !found && scm_is_pair (s); s = scm_cdr (s))
314     {
315       Context *tr = unsmob_context (scm_car (s));
316
317       found = find_context_below (tr, type, id);
318     }
319
320   return found; 
321 }
322
323 SCM
324 Context::properties_as_alist () const
325 {
326   return properties_dict ()->to_alist ();
327 }
328
329 SCM
330 Context::context_name_symbol () const
331 {
332   Context_def *td = unsmob_context_def (definition_);
333   return td->get_context_name ();
334 }
335
336 String
337 Context::context_name () const
338 {
339   return ly_symbol2string (context_name_symbol ());
340 }
341
342 Score_context*
343 Context::get_score_context () const
344 {
345   if (Score_context *sc = dynamic_cast<Score_context*> ((Context*) this))
346     return sc;
347   else if (daddy_context_)
348     return daddy_context_->get_score_context ();
349   else
350     return 0;
351 }
352
353 Output_def *
354 Context::get_output_def () const
355 {
356   return daddy_context_ ? daddy_context_->get_output_def () : 0;
357 }
358
359 Context::~Context ()
360 {
361   
362 }
363
364 Moment
365 Context::now_mom () const
366 {
367   return daddy_context_->now_mom ();
368 }
369
370 int
371 Context::print_smob (SCM s, SCM port, scm_print_state *)
372 {
373   Context *sc = (Context *) SCM_CELL_WORD_1 (s);
374      
375   scm_puts ("#<", port);
376   scm_puts (classname (sc), port);
377   if (Context_def *d = unsmob_context_def (sc->definition_))
378     {
379       scm_puts (" ", port);
380       scm_display (d->get_context_name (), port);
381     }
382
383   if (Context *td=dynamic_cast<Context *> (sc))
384     {
385       scm_puts ("=", port);
386       scm_puts (td->id_string_.to_str0 (), port);
387     }
388   
389
390   scm_puts (" ", port);
391
392   scm_display (sc->context_list_, port);
393   scm_puts (" >", port);
394   
395   return 1;
396 }
397
398 SCM
399 Context::mark_smob (SCM sm)
400 {
401   Context *me = (Context*) SCM_CELL_WORD_1 (sm);
402   
403   scm_gc_mark (me->context_list_);
404   scm_gc_mark (me->aliases_);
405   scm_gc_mark (me->definition_);  
406   scm_gc_mark (me->properties_scm_);  
407   scm_gc_mark (me->accepts_list_);
408   scm_gc_mark (me->implementation_);
409
410   return me->properties_scm_;
411 }
412
413 IMPLEMENT_SMOBS (Context);
414 IMPLEMENT_DEFAULT_EQUAL_P (Context);
415 IMPLEMENT_TYPE_P (Context,"ly:context?");
416
417 bool
418 Context::try_music (Music* m)
419 {
420   Translator*  t = implementation ();
421   if (!t)
422     return false;
423   
424   bool b = t->try_music (m);
425   if (!b && daddy_context_)
426     b = daddy_context_->try_music (m);
427
428   return b;
429 }
430
431
432 Global_context*
433 Context::get_global_context () const
434 {
435   if (dynamic_cast<Global_context *>((Context*) this))
436     return dynamic_cast<Global_context *> ((Context*) this);
437
438   if (daddy_context_)
439     return daddy_context_->get_global_context ();
440
441   programming_error ("No Global context!");
442   return 0;
443 }
444
445 Context*
446 Context::get_parent_context () const
447 {
448   return daddy_context_;
449 }
450
451 Translator_group*
452 Context::implementation () const
453 {
454   return dynamic_cast<Translator_group*> (unsmob_translator (implementation_));
455 }