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