]> git.donarmstrong.com Git - lilypond.git/blob - lily/context-def.cc
* lily/context-def.cc (filter_performers): don't go to cdrloc if
[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 /*
11   TODO: should junk this class an replace by
12   a single list of context modifications?
13  */
14
15 #include "lily-proto.hh"
16 #include "context-def.hh"
17 #include "translator-group.hh"
18 #include "warn.hh"
19 #include "music-output-def.hh"
20 #include "ly-smobs.icc"
21 #include "score-context.hh"
22
23 #include "performer.hh"
24 #include "engraver.hh"
25
26 int
27 Context_def::print_smob (SCM smob, SCM port, scm_print_state*)
28 {
29   Context_def* me = (Context_def*) SCM_CELL_WORD_1 (smob);
30
31   scm_puts ("#<Context_def ", port);
32   scm_display (me->context_name_, port);
33   scm_puts (">", port);
34   return 1;
35 }
36
37
38 SCM
39 Context_def::mark_smob (SCM smob)
40 {
41   Context_def* me = (Context_def*) SCM_CELL_WORD_1 (smob);
42
43   scm_gc_mark (me->description_);
44   scm_gc_mark (me->context_aliases_);
45   scm_gc_mark (me->accept_mods_);
46   scm_gc_mark (me->translator_mods_);
47   scm_gc_mark (me->property_ops_);  
48   scm_gc_mark (me->translator_group_type_);
49
50   return me->context_name_;
51 }
52
53
54 Context_def::Context_def ()
55 {
56   context_aliases_ = SCM_EOL;
57   translator_group_type_ = SCM_EOL;
58   accept_mods_ = SCM_EOL;
59   translator_mods_ = SCM_EOL;
60   property_ops_ = SCM_EOL;
61   context_name_ = SCM_EOL;
62   description_ = SCM_EOL;
63
64   smobify_self ();
65
66   context_name_ = ly_symbol2scm ("");
67 }
68
69 Context_def::~Context_def ()
70 {
71 }
72
73 Context_def::Context_def (Context_def const & s)
74   : Input (s)
75 {
76   context_aliases_ = SCM_EOL;
77   translator_group_type_ = SCM_EOL;
78   accept_mods_ = SCM_EOL;   
79   translator_mods_ = SCM_EOL;
80   property_ops_ = SCM_EOL;
81   context_name_ = SCM_EOL;
82   description_ = SCM_EOL;
83   
84   smobify_self ();
85   description_ = s.description_;
86
87   accept_mods_ = s.accept_mods_;
88   property_ops_ = s.property_ops_;
89   translator_mods_ = s.translator_mods_;
90   context_aliases_ = s.context_aliases_;
91   translator_group_type_ = s.translator_group_type_;
92   context_name_ = s.context_name_;
93 }
94
95
96 void
97 Context_def::add_context_mod (SCM mod)
98 {
99   SCM tag  = ly_car (mod);
100   if (ly_symbol2scm ("description")  == tag)
101     {
102       description_ = ly_cadr (mod);
103       return ;
104     }
105
106   SCM sym = ly_cadr (mod);
107   if (ly_c_string_p (sym))
108     sym = scm_string_to_symbol (sym);
109   
110   if (ly_symbol2scm ("consists") == tag
111       || ly_symbol2scm ("consists-end") == tag
112       || ly_symbol2scm ("remove") == tag)
113     {
114       if (!get_translator (sym))
115         error (_f ("Program has no such type: `%s'", ly_symbol2string (sym).to_str0 ()));
116       else
117         translator_mods_ = scm_cons (scm_list_2 (tag, sym), translator_mods_ );
118     }
119   else if (ly_symbol2scm ("accepts") == tag
120            || ly_symbol2scm ("denies") == tag)
121     {
122       accept_mods_ = scm_cons (scm_list_2 (tag, sym), accept_mods_); 
123     }
124   else if (ly_symbol2scm ("poppush") == tag
125            || ly_symbol2scm ("pop") == tag
126            || ly_symbol2scm ("push") == tag
127            || ly_symbol2scm ("assign") == tag
128            || ly_symbol2scm ("unset") == tag)
129     {
130       property_ops_ = scm_cons (mod, property_ops_);
131     }
132   else if (ly_symbol2scm ("alias") == tag)
133     {
134       context_aliases_ = scm_cons (sym, context_aliases_);
135     }
136   else if (ly_symbol2scm ("translator-type")  == tag)
137     {
138       translator_group_type_ = sym;
139     }
140   else if (ly_symbol2scm ("context-name")  == tag)
141     {
142       context_name_ = sym;
143     }
144   else
145     {
146       programming_error ("Unknown context mod tag.");
147     }
148 }
149
150
151
152 SCM
153 Context_def::get_context_name () const
154 {
155   return context_name_;
156 }
157
158 SCM
159 Context_def::get_accepted (SCM user_mod) const
160 {
161   SCM mods = scm_reverse_x (scm_list_copy (accept_mods_),
162                             user_mod);
163   SCM acc = SCM_EOL;
164   for (SCM s = mods; ly_c_pair_p (s); s = ly_cdr (s))
165     {
166       SCM tag = ly_caar (s);
167       SCM sym = ly_cadar (s);
168       if (tag == ly_symbol2scm ("accepts"))
169         acc = scm_cons (sym, acc);
170       else if (tag == ly_symbol2scm ("denies"))
171         acc = scm_delete_x (sym, acc);
172     }
173   return acc;
174 }
175
176            
177 Link_array<Context_def>
178 Context_def::path_to_acceptable_context (SCM type_sym, Music_output_def* odef) const
179 {
180   assert (ly_c_symbol_p (type_sym));
181   
182   SCM accepted = get_accepted (SCM_EOL);
183
184   Link_array<Context_def> accepteds;
185   for (SCM s = accepted; ly_c_pair_p (s); s = ly_cdr (s))
186     {
187       Context_def *t = unsmob_context_def (odef->find_context_def (ly_car (s)));
188       if (!t)
189         continue;
190       accepteds.push (t);
191     }
192
193   Link_array<Context_def> best_result;
194   for (int i=0; i < accepteds.size (); i++)
195     {
196       /*
197         don't check aliases, because \context Staff should not create RhythmicStaff.
198       */
199       if (ly_c_equal_p (accepteds[i]->get_context_name (), type_sym))
200         {
201           best_result.push (accepteds[i]);
202           return best_result;
203         }
204     }
205       
206   int best_depth= INT_MAX;
207   for (int i=0; i < accepteds.size (); i++)
208     {
209       Context_def * g = accepteds[i];
210
211       Link_array<Context_def> result
212         = g->path_to_acceptable_context (type_sym, odef);
213       if (result.size () && result.size () < best_depth)
214         {
215           result.insert (g,0);
216           best_result = result;
217
218           /*
219             this following line was added in 1.9.3, but hsould've been
220             there all along... Let's hope it doesn't cause nightmares.
221            */
222           best_depth = result.size ();
223         }
224     }
225
226   return best_result;
227 }
228
229 IMPLEMENT_SMOBS (Context_def);
230 IMPLEMENT_DEFAULT_EQUAL_P (Context_def);
231
232
233 SCM
234 Context_def::get_translator_names (SCM user_mod) const
235 {
236   SCM l1 = SCM_EOL;
237   SCM l2 = SCM_EOL;
238
239   SCM mods = scm_reverse_x (scm_list_copy (translator_mods_),
240                             user_mod);
241   
242   for (SCM s = mods; ly_c_pair_p (s); s = ly_cdr (s))
243     {
244       SCM tag = ly_caar (s);
245       SCM arg = ly_cadar (s);
246
247       if (ly_c_string_p (arg))
248         arg = scm_string_to_symbol (arg);
249       
250       if (ly_symbol2scm ("consists") == tag)
251         l1 = scm_cons (arg, l1);
252       else if (ly_symbol2scm ("consists-end") == tag)
253         l2 = scm_cons (arg, l2);
254       else if (ly_symbol2scm ("remove") == tag)
255         {
256           l1 = scm_delete_x (arg, l1);
257           l2 = scm_delete_x (arg, l2);
258         }
259     }
260
261   return scm_append_x (scm_list_2 (l1, l2));
262 }
263
264
265 SCM
266 filter_performers (SCM l)
267 {
268   for (SCM *tail = &l; ly_c_pair_p (*tail); tail = SCM_CDRLOC (*tail))
269     {
270       if (dynamic_cast<Performer*> (unsmob_translator (ly_car (*tail))))
271         {
272           *tail = ly_cdr (*tail);
273           if (!ly_c_pair_p (*tail))
274             break ;
275         }
276     }
277   return l;
278 }
279
280
281 SCM
282 filter_engravers (SCM l)
283 {
284   SCM *tail = &l;  
285   for (; ly_c_pair_p (*tail) ; tail = SCM_CDRLOC (*tail))
286     {
287       if (dynamic_cast<Engraver*> (unsmob_translator (ly_car (*tail))))
288         {
289           *tail = ly_cdr (*tail);
290           if (!ly_c_pair_p (*tail))
291             break ;
292         }
293     }
294   return l;
295 }
296
297
298 Context *
299 Context_def::instantiate (SCM ops)
300 {
301   Context * tg =  0;
302
303   if (context_name_ == ly_symbol2scm ("Score"))
304     tg = new Score_context ();
305   else
306     tg = new Context ();
307
308   tg->definition_ = self_scm ();
309
310   SCM trans_names = get_translator_names (ops); 
311
312   Translator * g = get_translator (translator_group_type_);
313   g = g->clone ();
314   
315   g->simple_trans_list_ =  SCM_EOL;
316
317   for (SCM s = trans_names; ly_c_pair_p (s) ; s = ly_cdr (s))
318     {
319       Translator * t = get_translator (ly_car (s));
320       if (!t)
321         warning (_f ("can't find: `%s'", s));
322       else
323         {
324           Translator * tr = t->clone ();
325           SCM str = tr->self_scm ();
326           g->simple_trans_list_ = scm_cons (str, g->simple_trans_list_);
327           tr->daddy_context_ = tg;
328           scm_gc_unprotect_object (str);
329         }
330     }
331
332
333   
334   tg->implementation_ = g->self_scm ();
335   if (dynamic_cast<Engraver*> (g))
336     g->simple_trans_list_ = filter_performers (g->simple_trans_list_);
337   else if (dynamic_cast<Performer*> (g))
338     g->simple_trans_list_ = filter_engravers (g->simple_trans_list_);
339         
340   g->daddy_context_ = tg;
341   tg->aliases_ = context_aliases_ ;
342   
343   scm_gc_unprotect_object (g->self_scm ());
344   
345   tg->accepts_list_ = get_accepted  (ops);
346   
347   return tg;
348 }
349
350
351 SCM
352 Context_def::clone_scm () const
353 {
354   Context_def * t = new Context_def (*this);
355
356   SCM x = t->self_scm ();
357   scm_gc_unprotect_object (x);
358   return x;
359 }
360
361 SCM
362 Context_def::make_scm ()
363 {
364   Context_def* t = new Context_def;
365
366   SCM x  =t->self_scm ();
367   scm_gc_unprotect_object (x);
368   return x;
369 }
370
371 void
372 Context_def::apply_default_property_operations (Context *tg)
373 {
374   apply_property_operations (tg , property_ops_);
375 }
376
377 SCM
378 Context_def::to_alist () const
379 {
380   SCM l = SCM_EOL;
381
382   l = scm_cons (scm_cons (ly_symbol2scm ("consists"),
383                         get_translator_names (SCM_EOL)), l);
384   l = scm_cons (scm_cons (ly_symbol2scm ("description"),  description_), l);
385   l = scm_cons (scm_cons (ly_symbol2scm ("aliases"),  context_aliases_), l);
386   l = scm_cons (scm_cons (ly_symbol2scm ("accepts"),  get_accepted (SCM_EOL)), l);
387   l = scm_cons (scm_cons (ly_symbol2scm ("property-ops"),  property_ops_), l);
388   l = scm_cons (scm_cons (ly_symbol2scm ("context-name"),  context_name_), l);
389
390   if (ly_c_symbol_p (translator_group_type_))
391     l = scm_cons (scm_cons (ly_symbol2scm ("group-type"),  translator_group_type_), l);    
392
393   return l;  
394 }
395