]> git.donarmstrong.com Git - lilypond.git/blob - lily/grob-property.cc
* input/regression/beam-quant-standard.ly: reindent, set
[lilypond.git] / lily / grob-property.cc
1 /*
2   Implement storage and manipulation of grob properties.
3 */
4
5 #include <cstring>
6
7 #include "main.hh"
8 #include "input-smob.hh"
9 #include "pointer-group-interface.hh"
10 #include "misc.hh"
11 #include "paper-score.hh"
12 #include "output-def.hh"
13 #include "spanner.hh"
14 #include "item.hh"
15 #include "misc.hh"
16 #include "item.hh"
17 #include "program-option.hh"
18 #include "profile.hh"
19
20 SCM
21 Grob::get_property_alist_chain (SCM def) const
22 {
23   return scm_list_n (mutable_property_alist_,
24                      immutable_property_alist_,
25                      def,
26                      SCM_UNDEFINED);
27 }
28
29 SCM
30 Grob::get_interfaces () const
31 {
32   return interfaces_;
33 }
34
35
36 extern void check_interfaces_for_property (Grob const *me, SCM sym);
37
38 void
39 Grob::internal_set_property (SCM sym, SCM v)
40 {
41 #ifndef NDEBUG
42   SCM grob_p = ly_lily_module_constant ("ly:grob?");
43   SCM grob_list_p = ly_lily_module_constant ("grob-list?");
44   SCM type = scm_object_property (sym, ly_symbol2scm ("backend-type?"));
45
46   if (type == grob_p
47       || type == grob_list_p
48       || (unsmob_grob (v) && ly_symbol2scm ("cause") != sym))
49     {
50       scm_display (scm_list_2 (sym, type), scm_current_output_port ());
51       assert (0);
52     }
53 #endif
54
55   /* Perhaps we simply do the assq_set, but what the heck. */
56   if (!is_live ())
57     return;
58
59   if (do_internal_type_checking_global)
60     {
61       if (!ly_is_procedure (v)
62           && !type_check_assignment (sym, v, ly_symbol2scm ("backend-type?")))
63         abort ();
64       check_interfaces_for_property (this, sym);
65     }
66
67   mutable_property_alist_ = scm_assq_set_x (mutable_property_alist_, sym, v);
68 }
69
70 //#define PROFILE_PROPERTY_ACCESSES
71 SCM
72 Grob::get_property_data (SCM sym) const
73 {
74 #ifndef NDEBUG
75   if (profile_property_accesses)
76     note_property_access (&grob_property_lookup_table, sym);
77 #endif
78   
79   SCM handle = scm_sloppy_assq (sym, mutable_property_alist_);
80   if (handle != SCM_BOOL_F)
81     return scm_cdr (handle);
82
83   handle = scm_sloppy_assq (sym, immutable_property_alist_);
84
85   if (do_internal_type_checking_global && scm_is_pair (handle))
86     {
87       SCM val = scm_cdr (handle);
88       if (!ly_is_procedure (val)
89           && !type_check_assignment (sym, val, 
90                                   ly_symbol2scm ("backend-type?")))
91         abort ();
92
93       check_interfaces_for_property (this, sym);
94     }
95   
96   return (handle == SCM_BOOL_F) ? SCM_EOL : scm_cdr (handle);
97 }
98
99 SCM
100 Grob::internal_get_property (SCM sym) const
101 {
102   SCM val = get_property_data (sym);
103   if (ly_is_procedure (val) || is_callback_chain (val))
104     {
105       val = ((Grob*)this)->try_callback (sym, val);
106     }
107   
108   return val;
109 }
110
111 #ifndef NDEBUG
112 #include "protected-scm.hh"
113 Protected_scm grob_property_callback_stack = SCM_EOL;
114 bool debug_property_callbacks = 0;
115 #endif
116
117 SCM
118 Grob::try_callback (SCM sym, SCM proc)
119 {      
120   SCM marker = ly_symbol2scm ("calculation-in-progress");
121   /*
122     need to put a value in SYM to ensure that we don't get a
123     cyclic call chain.
124   */
125   mutable_property_alist_
126     = scm_assq_set_x (mutable_property_alist_, sym, marker);
127
128 #ifndef NDEBUG
129   if (debug_property_callbacks)
130     grob_property_callback_stack = scm_acons (sym, proc, grob_property_callback_stack);
131 #endif
132
133   SCM value = SCM_EOL;
134   if (ly_is_procedure (proc))
135     value = scm_call_1 (proc, self_scm ());
136   else if (is_callback_chain (proc))
137     {
138       for (SCM s = callback_chain_extract_procedures (proc);
139            scm_is_pair (s); s = scm_cdr (s))
140         {
141           value = scm_call_2  (scm_car (s), self_scm (), value);
142         }
143     }
144   else
145     assert (false);
146   
147 #ifndef NDEBUG
148   if (debug_property_callbacks)
149     grob_property_callback_stack = scm_cdr (grob_property_callback_stack);
150 #endif
151           
152   /*
153     If the function returns SCM_UNSPECIFIED, we assume the
154     property has been set with an explicit set_property()
155     call.
156   */
157   if (value == SCM_UNSPECIFIED)
158     {
159       value = internal_get_property (sym);
160       if (value == marker)
161         mutable_property_alist_ = scm_assq_remove_x (mutable_property_alist_, marker);
162     }
163   else
164     internal_set_property (sym, value);
165           
166   return value;
167 }
168
169 void
170 Grob::internal_set_object (SCM s, SCM v)
171 {
172   /* Perhaps we simply do the assq_set, but what the heck. */
173   if (!is_live ())
174     return;
175
176   object_alist_ = scm_assq_set_x (object_alist_, s, v);
177 }
178
179 void
180 Grob::del_property (SCM sym)
181 {
182   mutable_property_alist_ = scm_assq_remove_x (mutable_property_alist_, sym);
183 }
184
185 SCM
186 Grob::internal_get_object (SCM sym) const
187 {
188 #ifdef PROFILE_PROPERTY_ACCESSES
189   note_property_access (&grob_property_lookup_table, sym);
190 #endif
191
192   SCM s = scm_sloppy_assq (sym, object_alist_);
193
194   return (s == SCM_BOOL_F) ? SCM_EOL : scm_cdr (s);
195 }
196
197 void
198 Grob::substitute_object_links (SCM crit, SCM orig)
199 {
200   set_break_subsititution (crit);
201   object_alist_ = substitute_object_alist (orig, object_alist_);
202 }
203
204 bool
205 Grob::is_live () const
206 {
207   return immutable_property_alist_ != SCM_EOL;
208 }