]> git.donarmstrong.com Git - lilypond.git/blob - lily/context.cc
Revert "Issue 4550 (1/2) Avoid "using namespace std;" in included files"
[lilypond.git] / lily / context.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 2004--2015 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
6   LilyPond is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   LilyPond is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "context.hh"
21
22 #include "context-def.hh"
23 #include "dispatcher.hh"
24 #include "global-context.hh"
25 #include "international.hh"
26 #include "main.hh"
27 #include "output-def.hh"
28 #include "profile.hh"
29 #include "program-option.hh"
30 #include "scm-hash.hh"
31 #include "translator-group.hh"
32 #include "warn.hh"
33 #include "lily-imports.hh"
34
35 bool
36 Context::is_removable () const
37 {
38   return scm_is_null (context_list_) && ! client_count_
39          && !dynamic_cast<Global_context const *> (daddy_context_);
40 }
41
42 void
43 Context::check_removal ()
44 {
45   for (SCM p = context_list_; scm_is_pair (p); p = scm_cdr (p))
46     {
47       Context *ctx = unsmob<Context> (scm_car (p));
48
49       ctx->check_removal ();
50       if (ctx->is_removable ())
51         {
52           recurse_over_translators (ctx, &Translator::finalize,
53                                     &Translator_group::finalize,
54                                     UP);
55           send_stream_event (ctx, "RemoveContext", 0, 0);
56         }
57     }
58 }
59
60 Scheme_hash_table *
61 Context::properties_dict () const
62 {
63   return unsmob<Scheme_hash_table> (properties_scm_);
64 }
65
66 void
67 Context::add_context (Context *child)
68 {
69   context_list_ = ly_append2 (context_list_,
70                               scm_cons (child->self_scm (), SCM_EOL));
71
72   child->daddy_context_ = this;
73   events_below_->register_as_listener (child->events_below_);
74 }
75
76 Context::Context ()
77 {
78   daddy_context_ = 0;
79   aliases_ = SCM_EOL;
80   client_count_ = 0;
81   implementation_ = 0;
82   properties_scm_ = SCM_EOL;
83   accepts_list_ = SCM_EOL;
84   default_child_ = SCM_EOL;
85   context_list_ = SCM_EOL;
86   definition_ = SCM_EOL;
87   definition_mods_ = SCM_EOL;
88   event_source_ = 0;
89   events_below_ = 0;
90
91   smobify_self ();
92
93   properties_scm_ = Scheme_hash_table::make_smob ();
94   event_source_ = new Dispatcher ();
95   event_source_->unprotect ();
96   events_below_ = new Dispatcher ();
97   events_below_->unprotect ();
98 }
99
100 /* TODO:  this shares code with find_create_context ().  */
101 Context *
102 Context::create_unique_context (SCM name, const string &id, SCM operations)
103 {
104   /*
105     Don't create multiple score contexts.
106   */
107   Global_context *gthis = dynamic_cast<Global_context *> (this);
108   if (gthis && gthis->get_score_context ())
109     return gthis->get_score_context ()->create_unique_context (name, id, operations);
110
111   vector<Context_def *> path = path_to_acceptable_context (name);
112   if (path.size ())
113     {
114       Context *current = this;
115
116       // Iterate through the path and create all of the implicit contexts.
117       for (vsize i = 0; i < path.size (); i++)
118         {
119           SCM ops = SCM_EOL;
120           string id_str = "\\new";
121           if (i == path.size () - 1)
122             {
123               ops = operations;
124               id_str = id;
125             }
126           current = current->create_context (path[i],
127                                              id_str,
128                                              ops);
129         }
130
131       return current;
132     }
133
134   /*
135     Don't go up to Global_context, because global goes down to the
136     Score context
137   */
138   Context *ret = 0;
139   if (daddy_context_ && !dynamic_cast<Global_context *> (daddy_context_))
140     ret = daddy_context_->create_unique_context (name, id, operations);
141   else
142     {
143       warning (_f ("cannot find or create new `%s'",
144                    ly_symbol2string (name).c_str ()));
145       ret = 0;
146     }
147   return ret;
148 }
149
150 Context *
151 Context::find_create_context (SCM n, const string &id, SCM operations)
152 {
153   /*
154     Don't create multiple score contexts.
155   */
156   Global_context *gthis = dynamic_cast<Global_context *> (this);
157   if (gthis)
158     {
159       if (gthis->get_score_context ())
160         return gthis->get_score_context ()->find_create_context (n, id, operations);
161
162       // Special case: If we use \set Timing.xxx = whatever before
163       // Score is established, the alias of Score to Timing will not
164       // be taken into account.  We check for this particular case
165       // here.  Aliases apart from Score-level ones don't warrant
166       // context creation as they could create unwanted contexts, like
167       // RhythmicVoice instead of Voice.  Creating a Score context,
168       // however, can't really do anything wrong.
169
170       SCM score_name = default_child_context_name ();
171       SCM score_def = find_context_def (get_output_def (), score_name);
172
173       if (Context_def *cd = unsmob<Context_def> (score_def))
174         {
175           if (cd->is_alias (n))
176             return create_context (cd, id, operations);
177         }
178     }
179
180
181   if (Context *existing = find_context_below (this, n, id))
182     return existing;
183
184   if (scm_is_eq (n, ly_symbol2scm ("Bottom")))
185     {
186       Context *tg = get_default_interpreter (id);
187       return tg;
188     }
189
190   vector<Context_def *> path = path_to_acceptable_context (n);
191
192   if (path.size ())
193     {
194       Context *current = this;
195
196       // start at 1.  The first one (index 0) will be us.
197       for (vsize i = 0; i < path.size (); i++)
198         {
199           SCM ops = (i == path.size () - 1) ? operations : SCM_EOL;
200
201           string this_id = "";
202           if (i == path.size () - 1)
203             this_id = id;
204
205           current = current->create_context (path[i],
206                                              this_id,
207                                              ops);
208         }
209
210       return current;
211     }
212
213   /*
214     Don't go up to Global_context, because global goes down to the
215     Score context
216   */
217   Context *ret = 0;
218   if (daddy_context_ && !dynamic_cast<Global_context *> (daddy_context_))
219     ret = daddy_context_->find_create_context (n, id, operations);
220   else
221     {
222       warning (_f ("cannot find or create `%s' called `%s'",
223                    ly_symbol2string (n).c_str (), id));
224       ret = 0;
225     }
226   return ret;
227 }
228
229 void
230 Context::acknowledge_infant (SCM sev)
231 {
232   infant_event_ = unsmob<Stream_event> (sev);
233 }
234
235 void
236 Context::set_property_from_event (SCM sev)
237 {
238   Stream_event *ev = unsmob<Stream_event> (sev);
239
240   SCM sym = ev->get_property ("symbol");
241   if (scm_is_symbol (sym))
242     {
243       SCM val = ev->get_property ("value");
244
245       if (SCM_UNBNDP (val)) {
246         unset_property (sym);
247         return;
248       }
249
250       bool ok = true;
251       ok = type_check_assignment (sym, val, ly_symbol2scm ("translation-type?"));
252
253       if (ok)
254         {
255           if (to_boolean (ev->get_property ("once")))
256             {
257               if (Global_context *g = get_global_context ())
258                 {
259                   SCM old_val = SCM_UNDEFINED;
260                   if (here_defined (sym, &old_val))
261                     g->add_finalization (scm_list_4 (ly_context_set_property_x_proc,
262                                                      self_scm (),
263                                                      sym,
264                                                      old_val));
265                   else
266                     g->add_finalization (scm_list_3 (ly_context_unset_property_proc,
267                                                      self_scm (),
268                                                      sym));
269                 }
270             }
271           set_property (sym, val);
272         }
273     }
274 }
275
276 void
277 Context::unset_property_from_event (SCM sev)
278 {
279   Stream_event *ev = unsmob<Stream_event> (sev);
280
281   SCM sym = ev->get_property ("symbol");
282   bool ok = type_check_assignment (sym, SCM_EOL, ly_symbol2scm ("translation-type?"));
283
284   if (ok)
285     {
286       if (to_boolean (ev->get_property ("once")))
287         {
288           if (Global_context *g = get_global_context ())
289             {
290               SCM old_val = SCM_UNDEFINED;
291               if (here_defined (sym, &old_val))
292                 g->add_finalization (scm_list_4 (ly_context_set_property_x_proc,
293                                                  self_scm (),
294                                                  sym,
295                                                  old_val));
296               else
297                 g->add_finalization (scm_list_3 (ly_context_unset_property_proc,
298                                                  self_scm (),
299                                                  sym));
300             }
301         }
302       unset_property (sym);
303     }
304 }
305
306 /*
307   Creates a new context from a CreateContext event, and sends an
308   AnnounceNewContext event to this context.
309 */
310 void
311 Context::create_context_from_event (SCM sev)
312 {
313   Stream_event *ev = unsmob<Stream_event> (sev);
314
315   string id = ly_scm2string (ev->get_property ("id"));
316   SCM ops = ev->get_property ("ops");
317   SCM type_scm = ev->get_property ("type");
318   string type = ly_symbol2string (type_scm);
319
320   vector<Context_def *> path = path_to_acceptable_context (type_scm);
321
322   if (path.size () != 1)
323     {
324       programming_error (to_string ("Invalid CreateContext event: Cannot create %s context", type.c_str ()));
325       return;
326     }
327   Context_def *cdef = path[0];
328
329   Context *new_context = cdef->instantiate (ops);
330
331   new_context->id_string_ = id;
332
333   /* Register various listeners:
334       - Make the new context hear events that universally affect contexts
335       - connect events_below etc. properly */
336   /* We want to be the first ones to hear our own events. Therefore, wait
337      before registering events_below_ */
338   new_context->event_source ()->
339   add_listener (new_context->GET_LISTENER (Context, create_context_from_event),
340                 ly_symbol2scm ("CreateContext"));
341   new_context->event_source ()->
342   add_listener (new_context->GET_LISTENER (Context, remove_context),
343                 ly_symbol2scm ("RemoveContext"));
344   new_context->event_source ()->
345   add_listener (new_context->GET_LISTENER (Context, change_parent),
346                 ly_symbol2scm ("ChangeParent"));
347   new_context->event_source ()->
348   add_listener (new_context->GET_LISTENER (Context, set_property_from_event),
349                 ly_symbol2scm ("SetProperty"));
350   new_context->event_source ()->
351   add_listener (new_context->GET_LISTENER (Context, unset_property_from_event),
352                 ly_symbol2scm ("UnsetProperty"));
353
354   new_context->events_below_->register_as_listener (new_context->event_source_);
355   add_context (new_context);
356
357   new_context->unprotect ();
358
359   Context_def *td = unsmob<Context_def> (new_context->definition_);
360
361   /* This cannot move before add_context (), because \override
362      operations require that we are in the hierarchy.  */
363   td->apply_default_property_operations (new_context);
364   apply_property_operations (new_context, ops);
365
366   send_stream_event (this, "AnnounceNewContext", 0,
367                      ly_symbol2scm ("context"), new_context->self_scm (),
368                      ly_symbol2scm ("creator"), sev);
369 }
370
371 vector<Context_def *>
372 Context::path_to_acceptable_context (SCM name) const
373 {
374   // The 'accepts elements in definition_mods_ is a list of ('accepts string),
375   // but the Context_def expects to see elements of the form ('accepts symbol).
376   SCM accepts = SCM_EOL;
377   for (SCM s = definition_mods_; scm_is_pair (s); s = scm_cdr (s))
378     if (scm_is_eq (scm_caar (s), ly_symbol2scm ("accepts")))
379       {
380         SCM elt = scm_list_2 (scm_caar (s), scm_string_to_symbol (scm_cadar (s)));
381         accepts = scm_cons (elt, accepts);
382       }
383
384   return unsmob<Context_def> (definition_)->path_to_acceptable_context (name,
385          get_output_def (),
386          scm_reverse_x (accepts, SCM_EOL));
387
388 }
389
390 Context *
391 Context::create_context (Context_def *cdef,
392                          const string &id,
393                          SCM ops)
394 {
395   infant_event_ = 0;
396   /* TODO: This is fairly misplaced. We can fix this when we have taken out all
397      iterator specific stuff from the Context class */
398   event_source_->
399   add_listener (GET_LISTENER (Context, acknowledge_infant),
400                 ly_symbol2scm ("AnnounceNewContext"));
401   /* The CreateContext creates a new context, and sends an announcement of the
402      new context through another event. That event will be stored in
403      infant_event_ to create a return value. */
404   send_stream_event (this, "CreateContext", 0,
405                      ly_symbol2scm ("ops"), ops,
406                      ly_symbol2scm ("type"), cdef->get_context_name (),
407                      ly_symbol2scm ("id"), ly_string2scm (id));
408   event_source_->
409   remove_listener (GET_LISTENER (Context, acknowledge_infant),
410                    ly_symbol2scm ("AnnounceNewContext"));
411
412   assert (infant_event_);
413   SCM infant_scm = infant_event_->get_property ("context");
414   Context *infant = unsmob<Context> (infant_scm);
415
416   if (!infant || infant->get_parent_context () != this)
417     {
418       programming_error ("create_context: can't locate newly created context");
419       return 0;
420     }
421
422   return infant;
423 }
424
425 /*
426   Default child context as a SCM string, or something else if there is
427   none.
428 */
429 SCM
430 Context::default_child_context_name () const
431 {
432   return default_child_;
433 }
434
435 bool
436 Context::is_bottom_context () const
437 {
438   return !scm_is_symbol (default_child_context_name ());
439 }
440
441 Context *
442 Context::get_default_interpreter (const string &context_id)
443 {
444   if (!is_bottom_context ())
445     {
446       SCM nm = default_child_context_name ();
447       SCM st = find_context_def (get_output_def (), nm);
448
449       string name = ly_symbol2string (nm);
450       Context_def *t = unsmob<Context_def> (st);
451       if (!t)
452         {
453           warning (_f ("cannot find or create: `%s'", name.c_str ()));
454           t = unsmob<Context_def> (definition_);
455         }
456       if (scm_is_symbol (t->get_default_child (SCM_EOL)))
457         {
458           Context *tg = create_context (t, "\\new", SCM_EOL);
459           return tg->get_default_interpreter (context_id);
460         }
461       return create_context (t, context_id, SCM_EOL);
462     }
463   else if (!context_id.empty () && context_id != id_string ())
464     {
465       if (daddy_context_ && !dynamic_cast<Global_context *> (daddy_context_))
466         return daddy_context_->get_default_interpreter (context_id);
467       warning (_f ("cannot find or create new Bottom = \"%s\"",
468                    context_id.c_str ()));
469     }
470   return this;
471 }
472
473 /*
474   PROPERTIES
475 */
476 Context *
477 Context::where_defined (SCM sym, SCM *value) const
478 {
479 #ifdef DEBUG
480   if (profile_property_accesses)
481     note_property_access (&context_property_lookup_table, sym);
482 #endif
483
484   if (properties_dict ()->try_retrieve (sym, value))
485     return (Context *)this;
486
487   return (daddy_context_) ? daddy_context_->where_defined (sym, value) : 0;
488 }
489
490 /* Quick variant of where_defined.  Checks only the context itself. */
491
492 bool
493 Context::here_defined (SCM sym, SCM *value) const
494 {
495 #ifdef DEBUG
496   if (profile_property_accesses)
497     note_property_access (&context_property_lookup_table, sym);
498 #endif
499
500   return properties_dict ()->try_retrieve (sym, value);
501 }
502
503 /*
504   return SCM_EOL when not found.
505 */
506 SCM
507 Context::internal_get_property (SCM sym) const
508 {
509 #ifdef DEBUG
510   if (profile_property_accesses)
511     note_property_access (&context_property_lookup_table, sym);
512 #endif
513
514   SCM val = SCM_EOL;
515   if (properties_dict ()->try_retrieve (sym, &val))
516     return val;
517
518   if (daddy_context_)
519     return daddy_context_->internal_get_property (sym);
520
521   return val;
522 }
523
524 /*
525 Called by the send_stream_event macro. props is a 0-terminated array of
526 properties and corresponding values, interleaved. This method should not
527 be called from any other place than the send_stream_event macro.
528 */
529 void
530 Context::internal_send_stream_event (SCM type, Input *origin, SCM props[])
531 {
532   Stream_event *e = new Stream_event (Lily::ly_make_event_class (type), origin);
533   for (int i = 0; props[i]; i += 2)
534     {
535       e->set_property (props[i], props[i + 1]);
536     }
537   event_source_->broadcast (e);
538   e->unprotect ();
539 }
540
541 bool
542 Context::is_alias (SCM sym) const
543 {
544   if (scm_is_eq (sym, ly_symbol2scm ("Bottom")))
545     return is_bottom_context ();
546   if (scm_is_eq (sym, context_name_symbol ()))
547     return true;
548
549   return scm_is_true (scm_c_memq (sym, aliases_));
550 }
551
552 void
553 Context::add_alias (SCM sym)
554 {
555   aliases_ = scm_cons (sym, aliases_);
556 }
557
558 /* we don't (yet) instrument context properties */
559 void
560 Context::instrumented_set_property (SCM sym, SCM val, const char *, int, const char *)
561 {
562   internal_set_property (sym, val);
563 }
564
565 void
566 Context::internal_set_property (SCM sym, SCM val)
567 {
568   bool type_check_ok = type_check_assignment (sym, val, ly_symbol2scm ("translation-type?"));
569
570   if (do_internal_type_checking_global)
571     assert (type_check_ok);
572
573   if (type_check_ok)
574     properties_dict ()->set (sym, val);
575 }
576
577 /*
578   TODO: look up to check whether we have inherited var?
579 */
580 void
581 Context::unset_property (SCM sym)
582 {
583   properties_dict ()->remove (sym);
584 }
585
586 void
587 Context::change_parent (SCM sev)
588 {
589   Stream_event *ev = unsmob<Stream_event> (sev);
590   Context *to = unsmob<Context> (ev->get_property ("context"));
591
592   disconnect_from_parent ();
593   to->add_context (this);
594 }
595
596 /*
597   Die. The next GC sweep should take care of the actual death.
598  */
599 void
600 Context::remove_context (SCM)
601 {
602   /* ugh, the translator group should listen to RemoveContext events by itself */
603   Translator_group *impl = implementation ();
604   if (impl)
605     impl->disconnect_from_context ();
606   disconnect_from_parent ();
607 }
608
609 void
610 Context::disconnect_from_parent ()
611 {
612   daddy_context_->events_below_->unregister_as_listener (events_below_);
613   daddy_context_->context_list_ = scm_delq_x (self_scm (), daddy_context_->context_list_);
614   daddy_context_ = 0;
615 }
616
617 Context *
618 find_context_above (Context *where, SCM type)
619 {
620   while (where && !where->is_alias (type))
621     where = where->get_parent_context ();
622
623   return where;
624 }
625
626 Context *
627 find_context_above_by_parent_type (Context *where, SCM parent_type)
628 {
629   for (Context *child = 0; where;
630        child = where, where = where->get_parent_context ())
631     if (where->is_alias (parent_type))
632       return child;
633
634   return 0;
635 }
636
637 Context *
638 find_context_below (Context *where,
639                     SCM type, const string &id)
640 {
641   if (where->is_alias (type))
642     {
643       if (id == "" || where->id_string () == id)
644         return where;
645     }
646
647   Context *found = 0;
648   for (SCM s = where->children_contexts ();
649        !found && scm_is_pair (s); s = scm_cdr (s))
650     {
651       Context *tr = unsmob<Context> (scm_car (s));
652
653       found = find_context_below (tr, type, id);
654     }
655
656   return found;
657 }
658
659 Context *
660 find_context_near (Context *where,
661                    SCM type, const string &id)
662 {
663   for ( ; where; where = where->get_parent_context ())
664     {
665       Context *found = find_context_below (where, type, id);
666       if (found)
667         return found;
668     }
669
670   return 0;
671 }
672
673 Context *
674 find_top_context (Context *where)
675 {
676   Context *top = where;
677   for ( ; where; where = where->get_parent_context())
678     top = where;
679   return top;
680 }
681
682 SCM
683 Context::properties_as_alist () const
684 {
685   return properties_dict ()->to_alist ();
686 }
687
688 SCM
689 Context::context_name_symbol () const
690 {
691   Context_def *td = unsmob<Context_def> (definition_);
692   return td->get_context_name ();
693 }
694
695 string
696 Context::context_name () const
697 {
698   return ly_symbol2string (context_name_symbol ());
699 }
700
701 Context *
702 Context::get_score_context () const
703 {
704   if (daddy_context_)
705     return daddy_context_->get_score_context ();
706   else
707     return 0;
708 }
709
710 Output_def *
711 Context::get_output_def () const
712 {
713   return daddy_context_ ? daddy_context_->get_output_def () : 0;
714 }
715
716 Context::~Context ()
717 {
718 }
719
720 Moment
721 Context::now_mom () const
722 {
723   Context const *p = this;
724   while (p->daddy_context_)
725     p = p->daddy_context_;
726
727   return p->now_mom ();
728 }
729
730 int
731 Context::print_smob (SCM port, scm_print_state *) const
732 {
733   scm_puts ("#<", port);
734   scm_puts (class_name (), port);
735   if (Context_def *d = unsmob<Context_def> (definition_))
736     {
737       scm_puts (" ", port);
738       scm_display (d->get_context_name (), port);
739     }
740
741   if (!id_string_.empty ())
742     {
743       scm_puts ("=", port);
744       scm_puts (id_string_.c_str (), port);
745     }
746
747   scm_puts (" ", port);
748
749   scm_display (context_list_, port);
750   scm_puts (" >", port);
751
752   return 1;
753 }
754
755 SCM
756 Context::mark_smob () const
757 {
758   scm_gc_mark (context_list_);
759   scm_gc_mark (aliases_);
760   scm_gc_mark (definition_);
761   scm_gc_mark (definition_mods_);
762   scm_gc_mark (properties_scm_);
763   scm_gc_mark (accepts_list_);
764   scm_gc_mark (default_child_);
765
766   if (implementation_)
767     scm_gc_mark (implementation_->self_scm ());
768
769   if (event_source_)
770     scm_gc_mark (event_source_->self_scm ());
771
772   if (events_below_)
773     scm_gc_mark (events_below_->self_scm ());
774
775   return properties_scm_;
776 }
777
778 const char Context::type_p_name_[] = "ly:context?";
779
780 Global_context *
781 Context::get_global_context () const
782 {
783   if (dynamic_cast<Global_context *> ((Context *) this))
784     return dynamic_cast<Global_context *> ((Context *) this);
785
786   if (daddy_context_)
787     return daddy_context_->get_global_context ();
788
789   programming_error ("no Global context");
790   return 0;
791 }
792
793 Context *
794 Context::get_parent_context () const
795 {
796   return daddy_context_;
797 }
798
799 /*
800   Ugh. Where to put this?
801 */
802 Rational
803 measure_length (Context const *context)
804 {
805   SCM l = context->get_property ("measureLength");
806   Rational length (1);
807   if (unsmob<Moment> (l))
808     length = unsmob<Moment> (l)->main_part_;
809   return length;
810 }
811
812 Moment
813 measure_position (Context const *context)
814 {
815   SCM sm = context->get_property ("measurePosition");
816
817   Moment m = 0;
818   if (unsmob<Moment> (sm))
819     {
820       m = *unsmob<Moment> (sm);
821
822       if (m.main_part_ < Rational (0))
823         {
824           Rational length (measure_length (context));
825           while (m.main_part_ < Rational (0))
826             m.main_part_ += length;
827         }
828     }
829
830   return m;
831 }
832
833 /* Finds the measure position after a note of length DUR that
834    begins at the current measure position. */
835 Moment
836 measure_position (Context const *context, Duration const *dur)
837 {
838   Moment pos = measure_position (context);
839   Rational dur_length = dur ? dur->get_length () : Rational (0);
840
841   Moment end_pos = pos.grace_part_ < Rational (0)
842                    ? Moment (pos.main_part_, pos.grace_part_ + dur_length)
843                    : Moment (pos.main_part_ + dur_length, 0);
844
845   return end_pos;
846 }
847
848 int
849 measure_number (Context const *context)
850 {
851   SCM barnum = context->get_property ("internalBarNumber");
852   SCM smp = context->get_property ("measurePosition");
853
854   int bn = robust_scm2int (barnum, 0);
855   Moment mp = robust_scm2moment (smp, Moment (0));
856   if (mp.main_part_ < Rational (0))
857     bn--;
858
859   return bn;
860 }
861
862 void
863 set_context_property_on_children (Context *trans, SCM sym, SCM val)
864 {
865   trans->set_property (sym, ly_deep_copy (val));
866   for (SCM p = trans->children_contexts (); scm_is_pair (p); p = scm_cdr (p))
867     {
868       Context *trg = unsmob<Context> (scm_car (p));
869       set_context_property_on_children (trg, sym, ly_deep_copy (val));
870     }
871 }
872
873 bool
874 melisma_busy (Context *tr)
875 {
876   // When there are subcontexts, they are responsible for maintaining
877   // melismata.
878   SCM ch = tr->children_contexts ();
879   if (scm_is_pair (ch))
880     {
881       // all contexts need to have a busy melisma for this to evaluate
882       // to true.
883
884       do {
885         if (!melisma_busy (unsmob<Context> (scm_car (ch))))
886           return false;
887         ch = scm_cdr (ch);
888       } while (scm_is_pair (ch));
889       return true;
890     }
891
892   for (SCM melisma_properties = tr->get_property ("melismaBusyProperties");
893        scm_is_pair (melisma_properties);
894        melisma_properties = scm_cdr (melisma_properties))
895     if (to_boolean (tr->get_property (scm_car (melisma_properties))))
896       return true;
897
898   return false;
899 }
900
901 bool
902 check_repeat_count_visibility (Context const *context, SCM count)
903 {
904   SCM proc = context->get_property ("repeatCountVisibility");
905   return (ly_is_procedure (proc)
906           && to_boolean (scm_call_2 (proc,
907                                      count,
908                                      context->self_scm ())));
909 }