]> git.donarmstrong.com Git - lilypond.git/blob - lily/context-def.cc
* lily/slur.cc (broken_trend_offset): robustness fix.
[lilypond.git] / lily / context-def.cc
1 /*   
2   translator-def.cc --  implement Context_def
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 2000--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7   
8  */
9
10 #include "lily-proto.hh"
11 #include "context-def.hh"
12 #include "translator-group.hh"
13 #include "warn.hh"
14 #include "music-output-def.hh"
15 #include "ly-smobs.icc"
16 #include "score-context.hh"
17
18 int
19 Context_def::print_smob (SCM smob, SCM port, scm_print_state*)
20 {
21   Context_def* me = (Context_def*) SCM_CELL_WORD_1 (smob);
22
23   scm_puts ("#<Context_def ", port);
24   scm_display (me->context_name_, port);
25   scm_puts (">", port);
26   return 1;
27 }
28
29
30 SCM
31 Context_def::mark_smob (SCM smob)
32 {
33   Context_def* me = (Context_def*) SCM_CELL_WORD_1 (smob);
34
35   scm_gc_mark (me->description_);
36   scm_gc_mark (me->context_aliases_);
37   scm_gc_mark (me->accept_mods_);
38   scm_gc_mark (me->translator_mods_);
39   scm_gc_mark (me->property_ops_);  
40   scm_gc_mark (me->translator_group_type_);
41
42   return me->context_name_;
43 }
44
45
46 Context_def::Context_def ()
47 {
48   context_aliases_ = SCM_EOL;
49   translator_group_type_ = SCM_EOL;
50   accept_mods_ = SCM_EOL;
51   translator_mods_ = SCM_EOL;
52   property_ops_ = SCM_EOL;
53   context_name_ = SCM_EOL;
54   description_ = SCM_EOL;
55
56   smobify_self();
57 }
58
59 Context_def::~Context_def ()
60 {
61 }
62
63 Context_def::Context_def (Context_def const & s)
64   : Input (s)
65 {
66   context_aliases_ = SCM_EOL;
67   translator_group_type_ = SCM_EOL;
68   accept_mods_ = SCM_EOL;   
69   translator_mods_ = SCM_EOL;
70   property_ops_ = SCM_EOL;
71   context_name_ = SCM_EOL;
72   description_ = SCM_EOL;
73   
74   smobify_self();
75   description_ = s.description_;
76
77   accept_mods_ = s.accept_mods_;
78   property_ops_ = s.property_ops_;
79   translator_mods_ = s.translator_mods_;
80   context_aliases_ = s.context_aliases_;
81   translator_group_type_ = s.translator_group_type_;
82   context_name_ = s.context_name_;
83 }
84
85
86 void
87 Context_def::add_context_mod (SCM mod)
88 {
89   SCM tag  = gh_car (mod);
90   if (ly_symbol2scm ("description")  == tag)
91     {
92       description_ = gh_cadr (mod);
93       return ;
94     }
95
96   SCM sym = gh_cadr (mod);
97   if (gh_string_p (sym))
98     sym = scm_string_to_symbol (sym);
99   
100   if (ly_symbol2scm ("consists") == tag
101       || ly_symbol2scm ("consists-end") == tag
102       || ly_symbol2scm ("remove") == tag)
103     {
104       if (!get_translator (sym))
105         error (_f ("Program has no such type: `%s'", ly_symbol2string (sym).to_str0 ()));
106       else
107         translator_mods_ = gh_cons (scm_list_2 (tag, sym), translator_mods_ );
108     }
109   else if (ly_symbol2scm ("accepts") == tag
110            || ly_symbol2scm ("denies") == tag)
111     {
112       accept_mods_ = gh_cons (scm_list_2 (tag, sym), accept_mods_); 
113     }
114   else if (ly_symbol2scm ("poppush") == tag
115            || ly_symbol2scm ("pop") == tag
116            || ly_symbol2scm ("push") == tag
117            || ly_symbol2scm ("assign") == tag
118            || ly_symbol2scm ("unset") == tag)
119     {
120       property_ops_ = gh_cons (mod, property_ops_);
121     }
122   else if (ly_symbol2scm ("alias") == tag)
123     {
124       context_aliases_ = gh_cons (sym, context_aliases_);
125     }
126   else if (ly_symbol2scm ("translator-type")  == tag)
127     {
128       translator_group_type_ = sym;
129     }
130   else if (ly_symbol2scm ("context-name")  == tag)
131     {
132       context_name_ = sym;
133     }
134   else
135     {
136       programming_error ("Unknown context mod tag.");
137     }
138 }
139
140
141
142 SCM
143 Context_def::get_context_name () const
144 {
145   return context_name_;
146 }
147
148 SCM
149 Context_def::get_accepted (SCM user_mod) const
150 {
151   SCM mods = scm_reverse_x (scm_list_copy (accept_mods_),
152                             user_mod);
153   SCM acc = SCM_EOL;
154   for (SCM s = mods; gh_pair_p (s); s = gh_cdr (s))
155     {
156       SCM tag = gh_caar (s);
157       SCM sym = gh_cadar (s);
158       if (tag == ly_symbol2scm ("accepts"))
159         acc = gh_cons (sym, acc);
160       else if (tag == ly_symbol2scm ("denies"))
161         acc = scm_delete_x (sym, acc);
162     }
163   return acc;
164 }
165
166            
167 Link_array<Context_def>
168 Context_def::path_to_acceptable_context (SCM type_sym, Music_output_def* odef) const
169 {
170   assert (gh_symbol_p (type_sym));
171   
172   SCM accepted = get_accepted (SCM_EOL);
173
174   Link_array<Context_def> accepteds;
175   for (SCM s = accepted; gh_pair_p (s); s = ly_cdr (s))
176     {
177       Context_def *t = unsmob_context_def (odef->find_context_def (ly_car (s)));
178       if (!t)
179         continue;
180       accepteds.push (t);
181     }
182
183   Link_array<Context_def> best_result;
184   for (int i=0; i < accepteds.size (); i++)
185     {
186       /*
187         don't check aliases, because \context Staff should not create RhythmicStaff.
188       */
189       if (gh_equal_p (accepteds[i]->get_context_name (), type_sym))
190         {
191           best_result.push (accepteds[i]);
192           return best_result;
193         }
194     }
195       
196   int best_depth= INT_MAX;
197   for (int i=0; i < accepteds.size (); i++)
198     {
199       Context_def * g = accepteds[i];
200
201       Link_array<Context_def> result
202         = g->path_to_acceptable_context (type_sym, odef);
203       if (result.size () && result.size () < best_depth)
204         {
205           result.insert (g,0);
206           best_result = result;
207
208           /*
209             this following line was added in 1.9.3, but hsould've been
210             there all along... Let's hope it doesn't cause nightmares.
211            */
212           best_depth = result.size();
213         }
214     }
215
216   return best_result;
217 }
218
219 IMPLEMENT_SMOBS (Context_def);
220 IMPLEMENT_DEFAULT_EQUAL_P (Context_def);
221
222
223 SCM
224 Context_def::get_translator_names (SCM user_mod) const
225 {
226   SCM l1 = SCM_EOL;
227   SCM l2 = SCM_EOL;
228
229   SCM mods = scm_reverse_x (scm_list_copy (translator_mods_),
230                             user_mod);
231   
232   for (SCM s = mods; gh_pair_p (s); s = gh_cdr (s))
233     {
234       SCM tag = gh_caar (s);
235       SCM arg = gh_cadar (s);
236
237       if (gh_string_p (arg))
238         arg = scm_string_to_symbol (arg);
239       
240       if (ly_symbol2scm ("consists") == tag)
241         l1 = gh_cons (arg, l1);
242       else if (ly_symbol2scm ("consists-end") == tag)
243         l2 = gh_cons (arg, l2);
244       else if (ly_symbol2scm ("remove") == tag)
245         {
246           l1 = scm_delete_x (arg, l1);
247           l2 = scm_delete_x (arg, l2);
248         }
249     }
250
251   return scm_append_x (scm_list_2 (l1, l2));
252 }
253
254
255 Context *
256 Context_def::instantiate (SCM ops)
257 {
258   Context * tg =  0;
259
260   if (context_name_ == ly_symbol2scm ("Score"))
261     tg = new Score_context ();
262   else
263     tg = new Context ();
264
265   
266   tg->definition_ = self_scm ();
267
268   SCM trans_names = get_translator_names (ops); 
269
270   Translator * g = get_translator (translator_group_type_);
271   g = g->clone ();
272   
273   g->simple_trans_list_ = names_to_translators (trans_names, tg);
274   tg->implementation_ = g->self_scm ();
275   g->daddy_context_ = tg;
276   
277   scm_gc_unprotect_object (g->self_scm ());
278   
279   tg->accepts_list_ = get_accepted  (ops);
280   
281   return tg;
282 }
283
284
285 SCM
286 Context_def::clone_scm () const
287 {
288   Context_def * t = new Context_def (*this);
289   scm_gc_unprotect_object (t->self_scm());
290   return t->self_scm();
291 }
292
293 SCM
294 Context_def::make_scm ()
295 {
296   Context_def* t = new Context_def;
297   scm_gc_unprotect_object (t->self_scm());
298   return t->self_scm();
299 }
300
301 void
302 Context_def::apply_default_property_operations (Context *tg)
303 {
304   apply_property_operations (tg , property_ops_);
305 }
306
307 SCM
308 Context_def::to_alist () const
309 {
310   SCM l = SCM_EOL;
311
312   l = gh_cons (gh_cons (ly_symbol2scm ("consists"),
313                         get_translator_names (SCM_EOL)), l);
314   l = gh_cons (gh_cons (ly_symbol2scm ("description"),  description_), l);
315   l = gh_cons (gh_cons (ly_symbol2scm ("aliases"),  context_aliases_), l);
316   l = gh_cons (gh_cons (ly_symbol2scm ("accepts"),  get_accepted (SCM_EOL)), l);
317   l = gh_cons (gh_cons (ly_symbol2scm ("property-ops"),  property_ops_), l);
318   l = gh_cons (gh_cons (ly_symbol2scm ("context-name"),  context_name_), l);
319
320   if (gh_symbol_p (translator_group_type_))
321     l = gh_cons (gh_cons (ly_symbol2scm ("group-type"),  translator_group_type_), l);    
322
323   return l;  
324 }
325
326 bool
327 Context_def::is_alias (SCM sym) const
328 {
329   bool b  = sym == context_name_;
330
331   for (SCM a = context_aliases_; !b && gh_pair_p (a); a = ly_cdr (a))
332     b = b || sym == ly_car (a);
333
334   return b;
335 }