1 /*
2 This file is part of LilyPond, the GNU music typesetter.
3
4 Copyright (C) 1997--2020 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 "music-iterator.hh"
21
22 #include "warn.hh"
23 #include "music.hh"
24 #include "context.hh"
25 #include "event-iterator.hh"
26 #include "input.hh"
27 #include "international.hh"
28 #include "ly-smob-list.hh"
29 #include "music-wrapper.hh"
30 #include "music-wrapper-iterator.hh"
31 #include "simple-music-iterator.hh"
32
33 #include <cstdio>
34
Music_iterator()35 Music_iterator::Music_iterator ()
36 {
37 music_ = 0;
38 smobify_self ();
39 }
40
~Music_iterator()41 Music_iterator::~Music_iterator ()
42 {
43 }
44
45 Moment
pending_moment() const46 Music_iterator::pending_moment () const
47 {
48 return Moment (Rational::infinity ());
49 }
50
51 void
process(Moment)52 Music_iterator::process (Moment)
53 {
54 }
55
56 SCM
get_static_get_iterator(Music * m)57 Music_iterator::get_static_get_iterator (Music *m)
58 {
59 Music_iterator *p = 0;
60
61 SCM ctor = get_property (m, "iterator-ctor");
62 SCM iter = SCM_EOL;
63 if (ly_is_procedure (ctor))
64 {
65 iter = scm_call_0 (ctor);
66 p = unsmob<Music_iterator> (iter);
67 }
68 else
69 {
70 if (dynamic_cast<Music_wrapper *> (m))
71 p = new Music_wrapper_iterator;
72 else if (m->is_mus_type ("event"))
73 p = new Event_iterator;
74 else
75 p = new Simple_music_iterator;
76
77 iter = p->self_scm ();
78 p->unprotect ();
79 }
80
81 p->music_ = m;
82 assert (m);
83 p->music_length_ = m->get_length ();
84 p->start_mom_ = m->start_mom ();
85
86 p->create_children ();
87
88 return iter;
89 }
90
91 void
init_context(Context * report)92 Music_iterator::init_context (Context *report)
93 {
94 if (!get_own_context ())
95 {
96 set_own_context (report);
97 create_contexts ();
98 }
99 else
100 {
101 programming_error ("context already initialized; skipping");
102 }
103 }
104
105 void
substitute_context(Context * f,Context * t)106 Music_iterator::substitute_context (Context *f, Context *t)
107 {
108 if (f != t)
109 {
110 if (get_own_context () == f)
111 set_own_context (t);
112 derived_substitute (f, t);
113 }
114 }
115
116 void
derived_substitute(Context *,Context *)117 Music_iterator::derived_substitute (Context *, Context *)
118 {
119 }
120
121 /* Descend to a bottom context; implicitly create a new one if necessary */
122 void
descend_to_bottom_context()123 Music_iterator::descend_to_bottom_context ()
124 {
125 assert (get_context ());
126 if (!get_context ()->is_bottom_context ())
127 set_context (get_context ()->get_default_interpreter ());
128 }
129
130 /* Concretely: If the current context is Global, descend to Score. */
131 void
descend_to_user_accessible_context()132 Music_iterator::descend_to_user_accessible_context ()
133 {
134 auto c = get_context ();
135 assert (c);
136 if (!c->is_accessible_to_user ())
137 {
138 c = c->get_user_accessible_interpreter ();
139 if (c)
140 set_context (c);
141 else
142 programming_error ("cannot find an accessible context");
143 }
144 }
145
146 void
report_event(Music * m)147 Music_iterator::report_event (Music *m)
148 {
149 descend_to_bottom_context ();
150
151 /*
152 FIXME: then don't do it.
153 */
154 if (!m->is_mus_type ("event"))
155 m->programming_error ("Sending non-event to context");
156
157 m->send_to_context (get_context ());
158 }
159
160 IMPLEMENT_CTOR_CALLBACK (Music_iterator);
161
162 Music *
get_music() const163 Music_iterator::get_music () const
164 {
165 return music_;
166 }
167
168 Input *
origin() const169 Music_iterator::origin () const
170 {
171 if (Music *m = get_music ())
172 return m->origin ();
173 return nullptr;
174 }
175
176 /****************************************************************/
177
178 const char *const Music_iterator::type_p_name_ = "ly:iterator?";
179
180 SCM
mark_smob() const181 Music_iterator::mark_smob () const
182 {
183 derived_mark ();
184 /*
185 Careful with GC, although we intend the following as pointers
186 only, we _must_ mark them.
187 */
188 if (get_own_context ())
189 scm_gc_mark (get_own_context ()->self_scm ());
190 if (music_)
191 scm_gc_mark (music_->self_scm ());
192
193 return SCM_EOL;
194 }
195
196 int
print_smob(SCM port,scm_print_state *) const197 Music_iterator::print_smob (SCM port, scm_print_state *) const
198 {
199 char s[1000];
200
201 sprintf (s, "#<%s>", class_name ());
202 scm_puts (s, port);
203 return 1;
204 }
205
206 void
derived_mark() const207 Music_iterator::derived_mark ()const
208 {
209 }
210
211 void
quit()212 Music_iterator::quit ()
213 {
214 do_quit ();
215 set_own_context (nullptr);
216 }
217
218 void
do_quit()219 Music_iterator::do_quit ()
220 {
221 }
222
223 bool
run_always() const224 Music_iterator::run_always ()const
225 {
226 return false;
227 }
228
229 bool
is_child_context(Context * me,Context * child)230 is_child_context (Context *me, Context *child)
231 {
232 while (child && child != me)
233 child = child->get_parent ();
234
235 return child == me;
236 }
237
238 /*
239 move to context of child iterator if it is deeper down in the
240 hierarchy.
241 */
242 void
descend_to_child(Context * child_report)243 Music_iterator::descend_to_child (Context *child_report)
244 {
245 Context *me_report = get_context ();
246 if (is_child_context (me_report, child_report))
247 set_context (child_report);
248 }
249