]> git.donarmstrong.com Git - lilypond.git/blob - lily/context-def.cc
* lily/lexer.ll: change is_string -> ly_c_string_p
[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 (is_symbol (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 (is_equal (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         }
274     }
275   return l;
276 }
277
278
279 SCM
280 filter_engravers (SCM l)
281 {
282   for (SCM *tail = &l; ly_c_pair_p (*tail) ; tail = SCM_CDRLOC (*tail))
283     {
284       if (dynamic_cast<Engraver*> (unsmob_translator (ly_car (*tail))))
285         {
286           *tail = ly_cdr (*tail);
287         }
288     }
289   return l;
290 }
291
292
293 Context *
294 Context_def::instantiate (SCM ops)
295 {
296   Context * tg =  0;
297
298   if (context_name_ == ly_symbol2scm ("Score"))
299     tg = new Score_context ();
300   else
301     tg = new Context ();
302
303   tg->definition_ = self_scm ();
304
305   SCM trans_names = get_translator_names (ops); 
306
307   Translator * g = get_translator (translator_group_type_);
308   g = g->clone ();
309   
310   g->simple_trans_list_ =  SCM_EOL;
311
312   for (SCM s = trans_names; ly_c_pair_p (s) ; s = ly_cdr (s))
313     {
314       Translator * t = get_translator (ly_car (s));
315       if (!t)
316         warning (_f ("can't find: `%s'", s));
317       else
318         {
319           Translator * tr = t->clone ();
320           SCM str = tr->self_scm ();
321           g->simple_trans_list_ = scm_cons (str, g->simple_trans_list_);
322           tr->daddy_context_ = tg;
323           scm_gc_unprotect_object (str);
324         }
325     }
326
327
328   
329   tg->implementation_ = g->self_scm ();
330   if (dynamic_cast<Engraver*> (g))
331     g->simple_trans_list_ = filter_performers (g->simple_trans_list_);
332   else if (dynamic_cast<Performer*> (g))
333     g->simple_trans_list_ = filter_engravers (g->simple_trans_list_);
334         
335   g->daddy_context_ = tg;
336   tg->aliases_ = context_aliases_ ;
337   
338   scm_gc_unprotect_object (g->self_scm ());
339   
340   tg->accepts_list_ = get_accepted  (ops);
341   
342   return tg;
343 }
344
345
346 SCM
347 Context_def::clone_scm () const
348 {
349   Context_def * t = new Context_def (*this);
350
351   SCM x = t->self_scm ();
352   scm_gc_unprotect_object (x);
353   return x;
354 }
355
356 SCM
357 Context_def::make_scm ()
358 {
359   Context_def* t = new Context_def;
360
361   SCM x  =t->self_scm ();
362   scm_gc_unprotect_object (x);
363   return x;
364 }
365
366 void
367 Context_def::apply_default_property_operations (Context *tg)
368 {
369   apply_property_operations (tg , property_ops_);
370 }
371
372 SCM
373 Context_def::to_alist () const
374 {
375   SCM l = SCM_EOL;
376
377   l = scm_cons (scm_cons (ly_symbol2scm ("consists"),
378                         get_translator_names (SCM_EOL)), l);
379   l = scm_cons (scm_cons (ly_symbol2scm ("description"),  description_), l);
380   l = scm_cons (scm_cons (ly_symbol2scm ("aliases"),  context_aliases_), l);
381   l = scm_cons (scm_cons (ly_symbol2scm ("accepts"),  get_accepted (SCM_EOL)), l);
382   l = scm_cons (scm_cons (ly_symbol2scm ("property-ops"),  property_ops_), l);
383   l = scm_cons (scm_cons (ly_symbol2scm ("context-name"),  context_name_), l);
384
385   if (is_symbol (translator_group_type_))
386     l = scm_cons (scm_cons (ly_symbol2scm ("group-type"),  translator_group_type_), l);    
387
388   return l;  
389 }
390