]> git.donarmstrong.com Git - lilypond.git/blob - lily/translator-def.cc
8c8c459bc5bff7a4e65bae7475c80f66b1dccbbb
[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->type_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->type_aliases_);
35   scm_gc_mark (me->consists_name_list_);
36   scm_gc_mark (me->accepts_name_list_);
37   scm_gc_mark (me->end_consists_name_list_);
38   scm_gc_mark (me->property_ops_);  
39   scm_gc_mark (me->translator_group_type_);
40   return me->type_name_;
41 }
42
43
44 Translator_def::Translator_def ()
45 {
46   type_aliases_ = SCM_EOL;
47   translator_group_type_ = SCM_EOL;
48   accepts_name_list_ = SCM_EOL;   
49   consists_name_list_ = SCM_EOL;
50   end_consists_name_list_ = SCM_EOL;
51   property_ops_ = SCM_EOL;
52   type_name_ = SCM_EOL;
53
54   smobify_self();
55   
56 }
57
58 Translator_def::~Translator_def ()
59 {
60 }
61
62 Translator_def::Translator_def (Translator_def const & s)
63   : Input (s)
64 {
65   type_aliases_ = SCM_EOL;
66   translator_group_type_ = SCM_EOL;
67   accepts_name_list_ = SCM_EOL;   
68   consists_name_list_ = SCM_EOL;
69   end_consists_name_list_ = SCM_EOL;
70   property_ops_ = SCM_EOL;
71   type_name_ = SCM_EOL;
72
73   
74   smobify_self();
75   consists_name_list_ = scm_list_copy (s.consists_name_list_);
76   end_consists_name_list_ = scm_list_copy (s.end_consists_name_list_);
77   accepts_name_list_ = scm_list_copy (s.accepts_name_list_);
78   property_ops_ = scm_list_copy (s.property_ops_);
79   type_aliases_ = scm_list_copy (s.type_aliases_);
80   translator_group_type_ = s.translator_group_type_;
81   type_name_ = s.type_name_;
82 }
83
84
85
86 void
87 Translator_def::set_acceptor (SCM name, bool add)
88 {
89   if (add)
90     this->accepts_name_list_ = gh_cons (name, this->accepts_name_list_);
91   else
92     this->accepts_name_list_ = scm_delete_x (name, this->accepts_name_list_);
93 }
94
95
96 SCM
97 Translator_def::modify_definition (SCM list, SCM str, bool add)
98 {
99   String s = ly_scm2string (str);
100   if (!get_translator (s))
101     error (_ ("Program has no such type"));
102
103   if (add)
104     {
105       if (scm_memq (str, list) != SCM_BOOL_F)
106         {
107           warning (_f ("Already contains: `%s'", s));
108           warning (_f ("Not adding translator: `%s'", s));
109         }
110       else
111         list= gh_cons (str, list);
112     }
113   else
114     {
115       list = scm_delete_x (str, list);
116     }
117   return list;
118 }
119
120
121
122 void
123 Translator_def::remove_element (SCM s)
124 {
125   this->end_consists_name_list_ = modify_definition (this->end_consists_name_list_, s, false);
126   this->consists_name_list_ = modify_definition (this->consists_name_list_, s, false);
127 }
128
129 void
130 Translator_def::add_element (SCM s)
131 {
132   this->consists_name_list_ = modify_definition (this->consists_name_list_, s, true);
133 }
134
135 void
136 Translator_def::add_last_element (SCM s)
137 {
138   this->end_consists_name_list_ = modify_definition (this->end_consists_name_list_, s, true);
139 }
140 void
141 Translator_def::add_push_property (SCM props, SCM syms,  SCM vals)
142 {
143   this->property_ops_ = gh_cons (scm_list_n (ly_symbol2scm ("push"), props, syms, vals, SCM_UNDEFINED),
144                                  this->property_ops_);
145 }
146
147 void
148 Translator_def::add_pop_property (SCM props, SCM syms)
149 {
150   this->property_ops_ = gh_cons (scm_list_n (ly_symbol2scm ("push"), props, syms, SCM_UNDEFINED),
151                                  this->property_ops_);
152 }
153
154
155
156 /*
157   Do it. SYM is single symbol. VAL is SCM_UNDEFINED in case of a pop
158 */
159 void
160 Translator_def::apply_pushpop_property (Translator_group* me,SCM sym, SCM eprop, SCM val)
161 {
162   dynamic_cast<Translator_group*> (me)
163     ->execute_single_pushpop_property (sym, eprop, val);
164 }
165
166
167
168 Link_array<Translator_def>
169 Translator_def::path_to_acceptable_translator (SCM type_string, Music_output_def* odef) const
170 {
171   assert (gh_string_p (type_string));
172   
173   Link_array<Translator_def> accepteds;
174   for (SCM s = accepts_name_list_; gh_pair_p (s); s = ly_cdr (s))
175     {
176       Translator_def *t = unsmob_translator_def (odef->find_translator (ly_car (s)));
177       if (!t)
178         continue;
179       accepteds.push (t);
180     }
181
182   Link_array<Translator_def> best_result;
183   for (int i=0; i < accepteds.size (); i++)
184     {
185
186       /*
187         don't check aliases, because \context Staff should not create RhythmicStaff.
188       */
189       if (gh_equal_p (accepteds[i]->type_name_, type_string))
190         {
191           best_result.push (accepteds[i]);
192           return best_result;
193         }
194     }
195       
196   int best_depth= INT_MAX;
197   for (int i=0; i < accepteds.size (); i++)
198     {
199       Translator_def * g = accepteds[i];
200
201       Link_array<Translator_def> result
202         = g->path_to_acceptable_translator (type_string, odef);
203       if (result.size () && result.size () < best_depth)
204         {
205           result.insert (g,0);
206           best_result = result;
207         }
208     }
209
210   return best_result;
211 }
212
213 IMPLEMENT_SMOBS (Translator_def);
214 IMPLEMENT_DEFAULT_EQUAL_P (Translator_def);
215
216
217 static SCM
218 trans_list (SCM namelist, Translator_group*tg)
219 {
220   SCM l = SCM_EOL;
221   for (SCM s = namelist; gh_pair_p (s) ; s = ly_cdr (s))
222     {
223       Translator * t = get_translator (ly_scm2string (ly_car (s)));
224       if (!t)
225         warning (_f ("can't find: `%s'", s));
226       else
227         {
228           Translator * tr = t->clone ();
229           SCM str = tr->self_scm ();
230           l = gh_cons (str, l);
231
232           tr->daddy_trans_ = tg;
233           tr->output_def_  = tg->output_def_;
234
235           scm_gc_unprotect_object (str);
236         }
237     }
238   return l; 
239 }
240
241
242 Translator_group *
243 Translator_def::instantiate (Music_output_def* md)
244 {
245   Translator * g = get_translator (ly_scm2string (translator_group_type_));
246   g = g->clone (); 
247
248   Translator_group *tg = dynamic_cast<Translator_group*> (g);
249   tg->output_def_ = md;
250   tg->definition_ = self_scm ();
251   tg->type_string_ = ly_scm2string (type_name_);
252
253   /*
254     TODO: ugh. we're reversing CONSISTS_NAME_LIST_ here
255    */
256   SCM l1 = trans_list (consists_name_list_, tg);
257   SCM l2 =trans_list (end_consists_name_list_,tg);
258   l1 = scm_reverse_x (l1, l2);
259   
260   tg->simple_trans_list_ = l1;
261   
262   return tg;
263 }
264
265
266 void
267 Translator_def::apply_property_operations (Translator_group*tg)
268 {
269   SCM correct_order = scm_reverse (property_ops_); // pity of the mem.
270   for (SCM s = correct_order; gh_pair_p (s); s = ly_cdr (s))
271     {
272       SCM entry = ly_car (s);
273       SCM type = ly_car (entry);
274       entry = ly_cdr (entry); 
275       
276       if (type == ly_symbol2scm ("push"))
277         {
278           SCM val = ly_cddr (entry);
279           val = gh_pair_p (val) ? ly_car (val) : SCM_UNDEFINED;
280
281           apply_pushpop_property (tg, ly_car (entry), ly_cadr (entry), val);
282         }
283       else if (type == ly_symbol2scm ("assign"))
284         {
285           tg->internal_set_property (ly_car (entry), ly_cadr (entry));
286         }
287     }
288 }
289
290 SCM
291 Translator_def::clone_scm () const
292 {
293   Translator_def * t = new Translator_def (*this);
294   scm_gc_unprotect_object (t->self_scm());
295   return t->self_scm();
296 }
297
298 SCM
299 Translator_def::make_scm ()
300 {
301   Translator_def* t = new Translator_def;
302   scm_gc_unprotect_object (t->self_scm());
303   return t->self_scm();
304 }
305
306 void
307 Translator_def::add_property_assign (SCM nm, SCM val)
308 {
309   this->property_ops_ = gh_cons (scm_list_n (ly_symbol2scm ("assign"), scm_string_to_symbol (nm), val, SCM_UNDEFINED),
310                                  this->property_ops_);
311 }
312
313 /*
314   Default child context as a SCM string, or something else if there is
315   none.
316 */
317 SCM
318 Translator_def::default_child_context_name ()
319 {
320   SCM d = accepts_name_list_;
321   return gh_pair_p (d) ? ly_car (scm_last_pair (d)) : SCM_EOL;
322 }
323
324 SCM
325 Translator_def::to_alist () const
326 {
327   SCM l = SCM_EOL;
328   
329   l = gh_cons (gh_cons (ly_symbol2scm ("consists"),  consists_name_list_), l);
330   l = gh_cons (gh_cons (ly_symbol2scm ("end-consists"),  end_consists_name_list_), l);
331   l = gh_cons (gh_cons (ly_symbol2scm ("accepts"),  accepts_name_list_), l);
332   l = gh_cons (gh_cons (ly_symbol2scm ("property-ops"),  property_ops_), l);
333   l = gh_cons (gh_cons (ly_symbol2scm ("type-name"),  type_name_), l); // junkme.
334   l = gh_cons (gh_cons (ly_symbol2scm ("group-type"),  translator_group_type_), l);    
335
336   return l;  
337 }