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