]> git.donarmstrong.com Git - lilypond.git/blob - lily/music-iterator.cc
c076b7ad65867e9e9b3cdb9266ae0748c1dd7586
[lilypond.git] / lily / music-iterator.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2012 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
6   LilyPond is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   LilyPond is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <cstdio>
21 using namespace std;
22
23 #include "warn.hh"
24 #include "music.hh"
25 #include "context.hh"
26 #include "event-iterator.hh"
27 #include "input.hh"
28 #include "international.hh"
29 #include "music-wrapper.hh"
30 #include "music-wrapper-iterator.hh"
31 #include "simple-music-iterator.hh"
32
33 #include "ly-smobs.icc"
34
35 Music_iterator::Music_iterator ()
36 {
37   music_ = 0;
38   smobify_self ();
39 }
40
41 Music_iterator::Music_iterator (Music_iterator const &)
42 {
43   assert (false);
44 }
45
46 Music_iterator::~Music_iterator ()
47 {
48 }
49
50 Context *
51 Music_iterator::get_outlet () const
52 {
53   return handle_.get_context ();
54 }
55
56 void
57 Music_iterator::set_context (Context *trans)
58 {
59   handle_.set_context (trans);
60 }
61
62 void
63 Music_iterator::construct_children ()
64 {
65 }
66
67 Moment
68 Music_iterator::pending_moment () const
69 {
70   return 0;
71 }
72
73 void
74 Music_iterator::process (Moment)
75 {
76 }
77
78 bool
79 Music_iterator::ok () const
80 {
81   return false;
82 }
83
84 SCM
85 Music_iterator::get_static_get_iterator (Music *m)
86 {
87   Music_iterator *p = 0;
88
89   SCM ctor = m->get_property ("iterator-ctor");
90   SCM iter = SCM_EOL;
91   if (ly_is_procedure (ctor))
92     {
93       iter = scm_call_0 (ctor);
94       p = unsmob_iterator (iter);
95     }
96   else
97     {
98       if (dynamic_cast<Music_wrapper *> (m))
99         p = new Music_wrapper_iterator;
100       else if (m->is_mus_type ("event"))
101         p = new Event_iterator;
102       else
103         p = new Simple_music_iterator;
104
105       iter = p->self_scm ();
106       p->unprotect ();
107     }
108
109   p->music_ = m;
110   assert (m);
111   p->music_length_ = m->get_length ();
112   p->start_mom_ = m->start_mom ();
113
114   return iter;
115 }
116
117 Moment
118 Music_iterator::music_get_length () const
119 {
120   return music_length_;
121 }
122
123 Moment
124 Music_iterator::music_start_mom ()const
125 {
126   return start_mom_;
127 }
128
129 void
130 Music_iterator::init_context (Music *m, Context *report)
131 {
132   music_ = m;
133   assert (m);
134   if (! get_outlet ())
135     set_context (report);
136 }
137
138 void
139 Music_iterator::substitute_outlet (Context *f, Context *t)
140 {
141   if (get_outlet () == f)
142     set_context (t);
143   derived_substitute (f, t);
144 }
145
146 void
147 Music_iterator::derived_substitute (Context *, Context *)
148 {
149 }
150
151 SCM
152 Music_iterator::get_iterator (Music *m) const
153 {
154   SCM ip = get_static_get_iterator (m);
155   Music_iterator *p = unsmob_iterator (ip);
156
157   p->init_context (m, get_outlet ());
158
159   p->construct_children ();
160   return ip;
161 }
162
163 /* Descend to a bottom context; implicitly create a new one if necessary */
164 void
165 Music_iterator::descend_to_bottom_context ()
166 {
167   assert (get_outlet ());
168   if (!get_outlet ()->is_bottom_context ())
169     set_context (get_outlet ()->get_default_interpreter ());
170 }
171
172 void
173 Music_iterator::report_event (Music *m)
174 {
175   descend_to_bottom_context ();
176
177   /*
178     FIXME: then don't do it.
179   */
180   if (!m->is_mus_type ("event"))
181     m->origin ()->programming_error ("Sending non-event to context");
182
183   m->send_to_context (get_outlet ());
184 }
185
186 IMPLEMENT_CTOR_CALLBACK (Music_iterator);
187
188 Music *
189 Music_iterator::get_music () const
190 {
191   return music_;
192 }
193
194 /****************************************************************/
195
196 IMPLEMENT_TYPE_P (Music_iterator, "ly:iterator?");
197 IMPLEMENT_SMOBS (Music_iterator);
198 IMPLEMENT_DEFAULT_EQUAL_P (Music_iterator);
199
200 SCM
201 Music_iterator::mark_smob (SCM smob)
202 {
203   Music_iterator *mus = (Music_iterator *)SCM_CELL_WORD_1 (smob);
204
205   mus->derived_mark ();
206   /*
207     Careful with GC, although we intend the following as pointers
208     only, we _must_ mark them.
209   */
210   if (mus->get_outlet ())
211     scm_gc_mark (mus->get_outlet ()->self_scm ());
212   if (mus->music_)
213     scm_gc_mark (mus->music_->self_scm ());
214
215   return SCM_EOL;
216 }
217
218 int
219 Music_iterator::print_smob (SCM sm, SCM port, scm_print_state *)
220 {
221   char s[1000];
222
223   Music_iterator *iter = unsmob_iterator (sm);
224   sprintf (s, "#<%s>", iter->class_name ());
225   scm_puts (s, port);
226   return 1;
227 }
228
229 void
230 Music_iterator::derived_mark ()const
231 {
232 }
233
234 void
235 Music_iterator::quit ()
236 {
237   do_quit ();
238   handle_.set_context (0);
239 }
240
241 void
242 Music_iterator::do_quit ()
243 {
244 }
245
246 bool
247 Music_iterator::run_always ()const
248 {
249   return false;
250 }
251
252 bool
253 is_child_context (Context *me, Context *child)
254 {
255   while (child && child != me)
256     child = child->get_parent_context ();
257
258   return child == me;
259 }
260
261 /*
262   move to context of child iterator if it is deeper down in the
263   hierarchy.
264 */
265 void
266 Music_iterator::descend_to_child (Context *child_report)
267 {
268   Context *me_report = get_outlet ();
269   if (is_child_context (me_report, child_report))
270     set_context (child_report);
271 }