1 /* 2 This file is part of LilyPond, the GNU music typesetter. 3 4 Copyright (C) 1997--2021 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 #ifndef MUSIC_ITERATOR_HH 21 #define MUSIC_ITERATOR_HH 22 23 #include "diagnostics.hh" 24 #include "moment.hh" 25 #include "virtual-methods.hh" 26 #include "context-handle.hh" 27 28 #include <functional> 29 30 /** 31 --- 32 33 Music_iterator is an object type that traverses the Music structure and 34 reports the events it finds to interpretation contexts. It is not yet 35 user-serviceable. 36 37 38 --- 39 40 Conceptually, a music-iterator traverses a queue of pending musical events. 41 This way of viewing and traversing music-expressions does not require an 42 actual queue. 43 44 45 ok () -- processing is incomplete: the queue still holds events or the 46 iterator wants to continue regardless 47 48 pending_moment () -- the time of the next event in the queue (+infinity 49 once the queue is empty) 50 51 process (M) -- process all at M (Precondition: no events exist 52 before M, ok () holds). Side-effects: 53 54 * This removes all events at M from the pending queue. 55 56 * Typically this reports the music to an interpretation context, 57 thus changing the state of the interpretation context. 58 59 run_always () -- when true, process (M) should be called even if M is 60 earlier than pending_moment (); when false, process (M) should not be 61 called until M reaches pending_moment () 62 63 TODO: 64 65 merge pending_moment and process? 66 */ 67 class Music_iterator : public Smob<Music_iterator>, public Diagnostics 68 { 69 public: 70 int print_smob (SCM, scm_print_state *) const; 71 SCM mark_smob () const; 72 static const char *const type_p_name_; 73 virtual ~Music_iterator (); 74 Input *origin () const override; 75 76 VIRTUAL_CLASS_NAME (Music_iterator); 77 private: 78 Music_iterator (Music_iterator const &) = delete; 79 Music_iterator &operator = (Music_iterator const &) = delete; 80 81 public: music_get_length() const82 const Moment &music_get_length () const { return music_length_; } 83 // music_start_mom () is calculated relative to the time where the 84 // iterator occurs in the music stream, so it will usually be 85 // non-zero only for expressions starting with grace notes. music_start_mom() const86 const Moment &music_start_mom () const { return start_mom_; } 87 void report_event (Music *); 88 89 // N.B. Subclasses can modify the behavior of these to address a child 90 // iterator. Where it is important to avoid that, use get_own_context () and 91 // set_own_context () instead. get_context() const92 virtual Context *get_context () const { return get_own_context (); } set_context(Context * c)93 virtual void set_context (Context *c) { set_own_context (c); } 94 95 // Circumvent the virtual get_context () and set_context () to address the 96 // context of this very iterator. get_own_context() const97 Context *get_own_context () const { return handle_.get_context (); } set_own_context(Context * c)98 void set_own_context (Context *c) { handle_.set_context (c); } 99 100 // Replace this iterator's references to one context with another. This is 101 // not recursive. Subclasses that track multiple contexts should override 102 // this to consider them all. 103 virtual void substitute_context (Context *from, Context *to); 104 105 // Create an iterator that has no parent. create_top_iterator(Music * mus)106 static SCM create_top_iterator (Music *mus) 107 { 108 return create_iterator (nullptr, mus); 109 } 110 111 // Create an iterator that has this iterator as its parent. create_child(Music * mus)112 SCM create_child (Music *mus) 113 { 114 return create_iterator (this, mus); 115 } 116 117 void init_context (Context *); 118 void quit (); 119 120 virtual Moment pending_moment () const; ok() const121 bool ok () const 122 { 123 return (pending_moment () < Moment::infinity ()) 124 || run_always (); 125 } 126 virtual bool run_always () const; 127 // process is called with a time relative to the iterator start, so 128 // usually the last processed moment is the same as music_get_length. 129 virtual void process (Moment until); 130 virtual void derived_mark () const; 131 DECLARE_SCHEME_CALLBACK (constructor, ()); 132 133 Music *get_music () const; 134 135 // Call the given function on this iterator and then on all of its children. 136 // 137 // Subclasses with child iterators must override this method, call the 138 // inherited implementation first, and then call preorder_walk for each 139 // child. 140 virtual void preorder_walk(const std::function<void (Music_iterator *)> & visit)141 preorder_walk (const std::function <void (Music_iterator *)> &visit) 142 { 143 if (visit) 144 visit (this); 145 } 146 get_parent() const147 Music_iterator *get_parent () const { return parent_; } 148 149 // Scoped search for music by type: look in this iterator's music, then 150 // search the ancestors up to the top. Return the first iterator whose music 151 // has the given type (null if none does). 152 Music_iterator *find_above_by_music_type (SCM type_sym) const; 153 154 // Scoped property access: look in this iterator's music, then search the 155 // ancestors up to the top. internal_get_property(SCM name_sym) const156 SCM internal_get_property (SCM name_sym) const 157 { 158 SCM value = SCM_EOL; 159 internal_where_defined (name_sym, &value); 160 return value; 161 } 162 163 // Scoped property access: look in this iterator's music, then search the 164 // ancestors up to the top. Return the iterator whose music has the named 165 // property (null if none does). Optionally get the value of the property. 166 Music_iterator *internal_where_defined (SCM name_sym, SCM *value) const; internal_where_defined(SCM name_sym) const167 Music_iterator *internal_where_defined (SCM name_sym) const 168 { 169 SCM value; 170 return internal_where_defined (name_sym, &value); 171 } 172 173 // Scoped search for taggged music: look in this iterator's music, then 174 // search the ancestors up to the top. Return the first iterator whose music 175 // is tagged with the given tag. If none is found, return this iterator. 176 Music_iterator *where_tagged (SCM tag_sym) const; 177 178 protected: 179 Music_iterator (); 180 181 // During the staged initialization of this iterator, this method is called 182 // after the iterator has received its music, but before it receives its 183 // context. This is the first chance to initialize state that depends on 184 // music properties, and the last chance to initialize state required for 185 // timing. When this method is overridden, it is usually because the 186 // iterator manages child iterators, which must be created to contribute to 187 // timing calculations. create_children()188 virtual void create_children () {} 189 190 // During the staged initialization of this iterator, this method is called 191 // after the iterator's own context has been initialized. It must initialize 192 // the contexts of any child iterators. 193 // 194 // Think twice before reading context properties here. Other iterators' 195 // process () methods may run after this call and before this iterator's 196 // process () method runs (and may change the context properties). create_contexts()197 virtual void create_contexts () {} 198 199 void descend_to_bottom_context (); 200 void descend_to_child (Context *); 201 void descend_to_user_accessible_context (); 202 203 virtual void do_quit (); 204 205 private: 206 static SCM create_iterator (Music_iterator *parent, Music *mus); 207 208 private: 209 Music_iterator *parent_ = nullptr; 210 Context_handle handle_; 211 Music *music_ = nullptr; 212 Moment music_length_; 213 Moment start_mom_; 214 }; 215 216 bool is_child_context (Context *me, Context *child); 217 218 #define IMPLEMENT_CTOR_CALLBACK(Class) \ 219 LY_DEFINE_MEMBER_FUNCTION (Class, constructor, \ 220 mangle_cxx_identifier (#Class "::constructor").c_str(), \ 221 0, 0, 0, \ 222 (), \ 223 "") \ 224 { \ 225 Class *c = (new Class); \ 226 return c->unprotect (); \ 227 } 228 229 #endif // MUSIC_ITERATOR_HH 230