1use crate::datatypes::*;
2
3peg::parser! {
4 pub grammar abc() for str {
50 pub rule tune_book() -> TuneBook =
51 c:ignored_line()* h:file_header()? ts:tune()* { TuneBook::new(c, h, ts) } /
52 ![_] { TuneBook::new(vec![], None, vec![]) }
53
54 pub rule ignored_line() -> IgnoredLine =
55 "\n" { IgnoredLine::EmptyLine } /
56 c:comment_line() { IgnoredLine::Comment(c) }
57
58 pub rule file_header() -> FileHeader =
59 l:header_line()* "\n" { FileHeader::new(l) }
60
61 pub rule tune() -> Tune =
62 h:tune_header() b:tune_body()? { Tune::new(h, b) }
63
64 pub rule tune_header() -> TuneHeader =
65 c1:comment_line()*
66 "X:" optional_space() n:number() optional_space() cx:inline_comment()? music_line_end()
67 c2:comment_line()*
68 t:info_field_header(<$("T")>) ct:inline_comment()? music_line_end()
69 extra:info_field_header_non_special()*
70 k:info_field_header(<$("K")>) ck:inline_comment()? music_line_end()
71 c3:comment_line()* {
72 let mut info = c1.into_iter().map(HeaderLine::Comment).collect::<Vec<_>>();
73 info.push(
74 HeaderLine::Field(
75 InfoField::new('X', n.to_string()),
76 cx.map(|s| Comment::Comment(s.to_string())),
77 )
78 );
79 info.extend(c2.into_iter().map(HeaderLine::Comment));
80 info.push(HeaderLine::Field(t, ct.map(|s| Comment::Comment(s.to_string()))));
81 info.extend(extra);
82 info.push(HeaderLine::Field(k, ck.map(|s| Comment::Comment(s.to_string()))));
83 info.extend(c3.into_iter().map(HeaderLine::Comment));
84 TuneHeader::new(info)
85 }
86
87 rule info_field_header<'a>(n: rule<&'a str>) -> InfoField =
88 name:n() ":" optional_space() t:$(([^ '\n' | '%'])*) {
89 InfoField::new(
90 name.chars().next().unwrap(),
91 t.to_string()
92 )
93 }
94
95 rule info_field_inline() -> InfoField =
96 name:$(['H'..='Y' | 'h'..='y' | '+']) ":" optional_space() t:$((!"]"!"\n"[_])*) {
97 InfoField::new(
98 name.chars().next().unwrap(),
99 t.to_string()
100 )
101 }
102
103 rule header_line() -> HeaderLine =
104 f:info_field_header(<$(['A'..='Z' | 'a'..='z' | '+'])>)
105 c:inline_comment()?
106 music_line_end() {
107 HeaderLine::Field(f, c.map(|s| Comment::Comment(s.to_string())))
108 } /
109 c:comment_line() { HeaderLine::Comment(c) }
110
111 rule info_field_header_non_special() -> HeaderLine =
112 f:info_field_header(<$(!['K' | 'X']['A'..='Z' | 'a'..='z' | '+'])>)
113 c:inline_comment()?
114 music_line_end() {
115 HeaderLine::Field(f, c.map(|s| Comment::Comment(s.to_string())))
116 } /
117 c:comment_line() { HeaderLine::Comment(c) }
118
119 pub rule tune_body() -> TuneBody =
120 l:tune_line()+ { TuneBody::new(l) } /
121 "\n" { TuneBody::new(vec![]) }
122
123 pub rule tune_line() -> TuneLine =
124 c:comment_line() { TuneLine::Comment(c) } /
125 m:music_line() { TuneLine::Music(m) } /
126 s:symbol_line() { TuneLine::Symbol(s) } /
127 l:lyric_line() { TuneLine::Lyric(l) } /
128 i:inline_field_line() { TuneLine::Music(i) }
129
130 pub rule music_line() -> MusicLine =
131 s:music_symbol()+ c:inline_comment()? music_line_end() {
132 let mut symbols = s;
133 if let Some(c) = c {
134 symbols.push(
135 MusicSymbol::Comment(Comment::Comment(c.to_string()))
136 );
137 }
138 MusicLine::new(symbols)
139 }
140
141 pub rule symbol_line() -> SymbolLine =
142 "s:" s:symbol_line_symbol()* music_line_end() {
143 SymbolLine::new(s)
144 }
145
146 pub rule lyric_line() -> LyricLine =
147 "w:" s:lyric_line_symbol()* music_line_end() {
148 LyricLine::new(s)
149 }
150
151 pub rule inline_field_line() -> MusicLine =
152 i:info_field_inline() music_line_end() {
153 MusicLine::new(vec![MusicSymbol::InlineField(i, false)])
154 }
155
156 pub rule music_symbol() -> MusicSymbol =
157 broken_rhythm() /
158 note() /
159 rest() /
160 spacer() /
161 chord() /
162 "[" i:info_field_inline() "]" { MusicSymbol::InlineField(i, true) } /
163 bar() /
164 beam() /
165 ending() /
166 grace_notes() /
167 tuplet() /
168 slur() /
169 d:decoration() { MusicSymbol::Decoration(d) } /
170 a:annotation() { MusicSymbol::Annotation(a) } /
171 music_space() /
172 reserved()
173
174 pub rule symbol_line_symbol() -> SymbolLineSymbol =
175 s:symbol_alignment() { SymbolLineSymbol::SymbolAlignment(s) } /
176 a:annotation() { SymbolLineSymbol::Annotation(a) } /
177 d:decoration() { SymbolLineSymbol::Decoration(d) } /
178 s:space() { SymbolLineSymbol::Space(s.to_string()) }
179
180 pub rule lyric_line_symbol() -> LyricSymbol =
181 s:symbol_alignment() { LyricSymbol::SymbolAlignment(s) } /
182 l:$([^ '-' | '_' | '*' | '~' | '\\' | '|' | ' ' | '\n']+) {
183 LyricSymbol::Syllable(l.to_string())
184 } /
185 s:space() { LyricSymbol::Space(s.to_string()) }
186
187 pub rule broken_rhythm() -> MusicSymbol =
192 b:(t:broken_rhythm_target() s:music_space()? {
193 match s {
194 Some(s) => vec![t, s],
195 None => vec![t],
196 }
197 })
198 r:$("<"*<1,3> / ">"*<1,3>)
199 a:(s:music_space()? t:(broken_rhythm() / broken_rhythm_target()) {
200 match s {
201 Some(s) => vec![s, t],
202 None => vec![t],
203 }
204 }) {
205 MusicSymbol::BrokenRhythm {
206 rhythm: r.to_string(),
207 before: b,
208 after: a,
209 }
210 }
211
212 pub rule broken_rhythm_target() -> MusicSymbol =
213 note() /
214 rest() /
215 chord() /
216 grace_notes()
217
218 pub rule note() -> MusicSymbol =
219 a:accidental()? n:note_uppercase() o:octave()? l:length()? t:tie()? {
220 MusicSymbol::new_note(
221 a, n, o.unwrap_or(1), l, t
222 )
223 } /
224 a:accidental()? n:note_lowercase() o:octave()? l:length()? t:tie()? {
225 MusicSymbol::new_note(
226 a, n, o.unwrap_or(1) + 1, l, t
227 )
228 }
229
230 pub rule bar() -> MusicSymbol =
231 b:$(
232 "."?
233 (
234 [':' | '|' | '\\' | ']'] /
235 "[" !['H'..='Y' | 'h'..='y' | '1'..='9']
236 )+
237 )
238 e:ending_number()?
239 { MusicSymbol::Bar(b.to_string(), e) }
240
241 pub rule beam() -> MusicSymbol =
242 b:$("`"+) { MusicSymbol::Beam(b.to_string()) }
243
244 pub rule slur() -> MusicSymbol =
245 "(" { MusicSymbol::Slur(Slur::Begin) } /
246 ".(" { MusicSymbol::Slur(Slur::BeginDotted) } /
247 ")" { MusicSymbol::Slur(Slur::End) }
248
249 pub rule rest() -> MusicSymbol =
250 "z" l:length()? { MusicSymbol::Rest(Rest::Note(l)) } /
251 "Z" l:length()? { MusicSymbol::Rest(Rest::Measure(l)) } /
252 "x" l:length()? { MusicSymbol::Rest(Rest::NoteHidden(l)) } /
253 "X" l:length()? { MusicSymbol::Rest(Rest::MeasureHidden(l)) }
254
255 pub rule spacer() -> MusicSymbol =
256 "y" { MusicSymbol::Spacer }
257
258 pub rule ending() -> MusicSymbol =
259 "[" i:ending_identifier() { MusicSymbol::Ending(i.to_string()) }
260
261 pub rule ending_identifier() -> String =
262 n1:ending_number() n2:("," n:ending_number() { n })* {
263 let mut s = n1;
264 for n in n2 {
265 s.push(',');
266 s.push_str(&n);
267 }
268 s
269 }
270
271 pub rule ending_number() -> String =
272 d1:number_digits() d2:("-" d:number_digits() { d } )? {
273 let mut s = d1.to_string();
274 if let Some(d2) = d2 {
275 s.push('-');
276 s.push_str(d2);
277 }
278 s
279 }
280
281 pub rule chord() -> MusicSymbol =
282 "[" n:chord_inner_symbol()+ "]" l:length()? t:tie()? {
283 MusicSymbol::Chord {
284 notes: n,
285 length: l,
286 tie: t,
287 }
288 }
289
290 pub rule chord_inner_symbol() -> MusicSymbol =
291 note() /
292 d:decoration() { MusicSymbol::Decoration(d) }
293
294 pub rule grace_notes() -> MusicSymbol =
295 "{" a:"/"? n:grace_notes_inner_symbol()+ "}" {
296 MusicSymbol::GraceNotes {
297 acciaccatura: a,
298 notes: n
299 }
300 }
301
302 pub rule grace_notes_inner_symbol() -> MusicSymbol =
303 broken_rhythm() /
304 note() /
305 music_space()
306
307 pub rule tuplet() -> MusicSymbol =
308 "("
309 p:digit_at_least_2()
310 q:(":" x:digit_at_least_1()? { x })?
311 r:(":" x:digit_at_least_1()? { x })? {
312 MusicSymbol::new_tuplet(p, q.flatten(), r.flatten())
313 }
314
315 pub rule music_space() -> MusicSymbol =
316 s:space() { MusicSymbol::Space(s.to_string()) }
317
318 pub rule reserved() -> MusicSymbol =
319 r:['#' | '*' | ';' | '?' | '@'] {
320 MusicSymbol::Reserved(r.to_string())
321 }
322
323 rule accidental() -> Accidental =
326 "^^" { Accidental::DoubleSharp } /
327 "__" { Accidental::DoubleFlat } /
328 "^" { Accidental::Sharp } /
329 "_" { Accidental::Flat } /
330 "=" { Accidental::Natural }
331
332 pub rule note_uppercase() -> Note =
333 "A" { Note::A } /
334 "B" { Note::B } /
335 "C" { Note::C } /
336 "D" { Note::D } /
337 "E" { Note::E } /
338 "F" { Note::F } /
339 "G" { Note::G }
340
341 pub rule note_lowercase() -> Note =
342 "a" { Note::A } /
343 "b" { Note::B } /
344 "c" { Note::C } /
345 "d" { Note::D } /
346 "e" { Note::E } /
347 "f" { Note::F } /
348 "g" { Note::G }
349
350 rule octave() -> i8 =
351 p:$([',' | '\'']+) {
352 let mut octave = 1;
353 for c in p.chars() {
354 match c {
355 ',' => octave -= 1,
356 '\'' => octave += 1,
357 _ => panic!("Parser malfunctioned. Unexpected octave identifier")
358 }
359 }
360 octave
361 }
362
363 rule tie() -> Tie =
364 ".-" { Tie::Dotted } /
365 "-" { Tie::Solid }
366
367 rule inline_comment() -> &'input str =
372 "%" c:$([^'\n']*) { c }
373
374 rule comment_line() -> Comment =
375 "%" c:inline_comment() music_line_end() {
376 Comment::StylesheetDirective(c.to_string())
377 } /
378 s:space() c:inline_comment() music_line_end() {
379 Comment::CommentLine(s.to_string(), c.to_string())
380 } /
381 c:inline_comment() music_line_end() {
382 Comment::CommentLine("".to_string(), c.to_string())
383 }
384
385 rule length() -> Length =
386 "/" n:number() {
387 Length::new(1.0 / (n as f32))
388 } /
389 s:$("/"+) {
390 Length::new(1.0 / (s.len() as f32).exp2())
391 } /
392 n1:number() "/" n2:number() {
393 Length::new((n1 as f32) / (n2 as f32))
394 } /
395 n:number() { Length::new(n as f32) }
396
397 pub rule annotation() -> Annotation =
398 "\"" p:placement()? s:$((!"\""[_])*) "\"" {
399 Annotation::new(p, s.to_string())
400 }
401
402 pub rule placement() -> Placement =
403 "^" { Placement::Above } /
404 "_" { Placement::Below } /
405 "<" { Placement::Left } /
406 ">" { Placement::Right } /
407 "@" { Placement::Auto }
408
409 rule decoration() -> Decoration =
410 "." { Decoration::Staccato } /
411 "~" { Decoration::Roll } /
412 "H" { Decoration::Fermata } /
413 "L" { Decoration::Accent } /
414 "M" { Decoration::LowerMordent } /
415 "O" { Decoration::Coda } /
416 "P" { Decoration::UpperMordent } /
417 "S" { Decoration::Segno } /
418 "T" { Decoration::Trill } /
419 "u" { Decoration::UpBow } /
420 "v" { Decoration::DownBow } /
421 "!" d:$((!['\n' | '!'][_])+) "!" {
422 Decoration::Unresolved(d.to_string())
423 }
424
425 pub rule symbol_alignment() -> SymbolAlignment =
426 "-" { SymbolAlignment::Break } /
427 "_" { SymbolAlignment::Extend } /
428 "*" { SymbolAlignment::Skip } /
429 "~" { SymbolAlignment::Space } /
430 "\\-" { SymbolAlignment::Hyphen } /
431 "|" { SymbolAlignment::Bar }
432
433 rule number() -> u32 =
438 n:number_digits() { n.parse().unwrap() }
439
440 rule number_digits() -> &'input str =
441 $(['1'..='9']['0'..='9']*)
442
443 rule digit_at_least_1() -> u32 =
444 n:$(['1'..='9']) { n.parse().unwrap() }
445
446 rule digit_at_least_2() -> u32 =
447 n:$(['2'..='9']) { n.parse().unwrap() }
448
449 rule space() -> &'input str =
450 s:$([' ' | '\t']+) { s }
451
452 rule optional_space() =
453 [' ' | '\t']*
454
455 rule music_line_end() =
456 "\n" / ![_]
457 }
458}