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