abc_parser/
lib.rs

1//! # ABC Parser (WIP)
2//!
3//! An ABC music notation parser for Rust based on the
4//! [2.1 Standard](http://abcnotation.com/wiki/abc:standard:v2.1). This crate is currently a work
5//! in progress and not fully compliant. For full documentation on which parts of the standard
6//! are implemented, take a look at the tests.
7//!
8//! For parsing examples see [abc](abc/index.html) module.
9
10pub mod datatypes;
11mod grammar;
12
13pub use grammar::abc;
14
15#[cfg(test)]
16mod tests {
17    use super::*;
18    use datatypes::*;
19
20    fn make_tune_header(x: &str, t: &str, k: &str) -> TuneHeader {
21        TuneHeader::new(vec![
22            InfoField::new('X', x.to_string()),
23            InfoField::new('T', t.to_string()),
24            InfoField::new('K', k.to_string()),
25        ])
26    }
27
28    #[test]
29    fn empty_tunebook() {
30        let t = abc::tune_book("").unwrap();
31        assert_eq!(t, TuneBook::new(None, vec![]));
32    }
33
34    #[test]
35    fn tune_book() {
36        let t = abc::tune_book("X:1\nT:Some Title\nK:G\n").unwrap();
37        assert_eq!(
38            t,
39            TuneBook::new(
40                None,
41                vec![Tune::new(make_tune_header("1", "Some Title", "G"), None)]
42            )
43        );
44    }
45
46    #[test]
47    fn invalid_tune() {
48        abc::tune("a").unwrap_err();
49    }
50
51    #[test]
52    fn empty_tune_no_body() {
53        let t = abc::tune("X:1\nT:Some Title\nK:G\n").unwrap();
54        assert_eq!(t, Tune::new(make_tune_header("1", "Some Title", "G"), None));
55    }
56
57    #[test]
58    fn empty_tune_empty_body() {
59        let t = abc::tune("X:1\nT:Some Title\nK:G\n\n").unwrap();
60        assert_eq!(
61            t,
62            Tune::new(
63                make_tune_header("1", "Some Title", "G"),
64                Some(TuneBody::new(vec![]))
65            )
66        );
67    }
68
69    #[test]
70    fn tune_header() {
71        let t = abc::tune_header("X:1\nT:Some Title\nK:G\n").unwrap();
72        assert_eq!(t, make_tune_header("1", "Some Title", "G"));
73    }
74
75    #[test]
76    fn tune_header_unicode() {
77        let t = abc::tune_header("X:1\nT:S©ome ©Title©\nK:G\n").unwrap();
78        assert_eq!(t, make_tune_header("1", "S©ome ©Title©", "G"));
79    }
80
81    #[test]
82    fn tune_header_extra_fields() {
83        let t = abc::tune_header("X:1\nT:Some Title\nO:England\nK:G\n").unwrap();
84        assert_eq!(
85            t,
86            TuneHeader::new(vec![
87                InfoField::new('X', "1".to_string()),
88                InfoField::new('T', "Some Title".to_string()),
89                InfoField::new('O', "England".to_string()),
90                InfoField::new('K', "G".to_string())
91            ])
92        );
93    }
94
95    #[test]
96    fn file_header() {
97        let t = abc::tune_book("O:Some origin info\n\nX:1\nT:Some Title\nK:G\n").unwrap();
98        assert_eq!(
99            t,
100            TuneBook::new(
101                Some(FileHeader::new(vec![InfoField::new(
102                    'O',
103                    "Some origin info".to_string()
104                )])),
105                vec![Tune::new(make_tune_header("1", "Some Title", "G"), None)]
106            )
107        );
108    }
109
110    #[test]
111    fn music_line_empty_1() {
112        abc::music_line("").unwrap_err();
113    }
114    #[test]
115    fn music_line_empty_2() {
116        abc::music_line("\n").unwrap_err();
117    }
118
119    #[test]
120    fn body_with_music() {
121        let b = abc::tune_body("A").unwrap();
122        assert_eq!(
123            b,
124            TuneBody::new(vec![MusicLine::new(vec![MusicSymbol::note(Note::A)])])
125        )
126    }
127
128    #[test]
129    fn body_with_music_2() {
130        let b = abc::tune_body("A\n").unwrap();
131        assert_eq!(
132            b,
133            TuneBody::new(vec![MusicLine::new(vec![MusicSymbol::note(Note::A)])])
134        )
135    }
136
137    #[test]
138    fn music_line() {
139        let m = abc::music_line("A\n").unwrap();
140        assert_eq!(m, MusicLine::new(vec![MusicSymbol::note(Note::A)]))
141    }
142
143    #[test]
144    fn music_line_2() {
145        let m = abc::music_line("A").unwrap();
146        assert_eq!(m, MusicLine::new(vec![MusicSymbol::note(Note::A)]))
147    }
148
149    #[test]
150    fn music_line_multiple_notes() {
151        let m = abc::music_line("AB cd").unwrap();
152        assert_eq!(
153            m,
154            MusicLine::new(vec![
155                MusicSymbol::note(Note::A),
156                MusicSymbol::note(Note::B),
157                MusicSymbol::VisualBreak,
158                MusicSymbol::new_note(vec![], None, Note::C, 2, 1.0, None),
159                MusicSymbol::new_note(vec![], None, Note::D, 2, 1.0, None)
160            ])
161        )
162    }
163
164    #[test]
165    fn music_line_chord() {
166        let m = abc::music_line("!f! [F=AC]3/2[GBD] H[CEG]2").unwrap();
167        assert_eq!(
168            m,
169            MusicLine::new(vec![
170                MusicSymbol::Chord {
171                    decorations: vec![Decoration::Unresolved("f".to_string())],
172                    notes: vec![
173                        MusicSymbol::note(Note::F),
174                        MusicSymbol::new_note(
175                            vec![],
176                            Some(Accidental::Natural),
177                            Note::A,
178                            1,
179                            1.0,
180                            None
181                        ),
182                        MusicSymbol::note(Note::C)
183                    ],
184                    length: 3.0 / 2.0
185                },
186                MusicSymbol::Chord {
187                    decorations: vec![],
188                    notes: vec![
189                        MusicSymbol::note(Note::G),
190                        MusicSymbol::note(Note::B),
191                        MusicSymbol::note(Note::D)
192                    ],
193                    length: 1f32
194                },
195                MusicSymbol::VisualBreak,
196                MusicSymbol::Chord {
197                    decorations: vec![Decoration::Fermata],
198                    notes: vec![
199                        MusicSymbol::note(Note::C),
200                        MusicSymbol::note(Note::E),
201                        MusicSymbol::note(Note::G)
202                    ],
203                    length: 2.0
204                }
205            ])
206        );
207    }
208
209    #[test]
210    fn music_line_backticks() {
211        let m = abc::music_line("A2``B``C").unwrap();
212        assert_eq!(
213            m,
214            MusicLine::new(vec![
215                MusicSymbol::note_from_length(Note::A, 2.0),
216                MusicSymbol::note(Note::B),
217                MusicSymbol::note(Note::C)
218            ])
219        )
220    }
221
222    #[test]
223    fn note() {
224        let s = abc::music_symbol("A").unwrap();
225        assert_eq!(s, MusicSymbol::note(Note::A))
226    }
227
228    macro_rules! assert_note_len {
229        ($input:tt, $expected:expr) => {
230            assert_eq!(
231                abc::music_symbol($input).unwrap(),
232                MusicSymbol::note_from_length(Note::A, $expected)
233            );
234        };
235    }
236
237    #[test]
238    fn note_length_1() {
239        assert_note_len!("A3", 3f32);
240    }
241    #[test]
242    fn note_length_2() {
243        assert_note_len!("A9001", 9001f32)
244    }
245    #[test]
246    fn note_length_3() {
247        assert_note_len!("A/2", 0.5)
248    }
249    #[test]
250    fn note_length_4() {
251        assert_note_len!("A/", 0.5)
252    }
253    #[test]
254    fn note_length_5() {
255        assert_note_len!("A/4", 0.25)
256    }
257    #[test]
258    fn note_length_6() {
259        assert_note_len!("A//", 0.25)
260    }
261    #[test]
262    fn note_length_7() {
263        assert_note_len!("A3/2", 3.0 / 2.0)
264    }
265    #[test]
266    fn note_length_8() {
267        assert_note_len!("A6821/962", 6821.0 / 962.0)
268    }
269
270    #[test]
271    fn note_length_invalid_1() {
272        abc::music_symbol("A0").unwrap_err();
273    }
274    #[test]
275    fn note_length_invalid_2() {
276        abc::music_symbol("A-1").unwrap_err();
277    }
278
279    #[test]
280    fn note_invalid_1() {
281        abc::music_symbol("H").unwrap_err();
282    }
283    #[test]
284    fn note_invalid_2() {
285        abc::music_symbol("h").unwrap_err();
286    }
287    #[test]
288    fn note_invalid_3() {
289        abc::music_symbol("Y").unwrap_err();
290    }
291    #[test]
292    fn note_invalid_4() {
293        abc::music_symbol("y").unwrap_err();
294    }
295    #[test]
296    fn note_invalid_5() {
297        abc::music_symbol("m").unwrap_err();
298    }
299    #[test]
300    fn note_invalid_6() {
301        abc::music_symbol("T").unwrap_err();
302    }
303
304    macro_rules! assert_bar {
305        ($bar:tt) => {
306            assert_eq!(
307                abc::music_symbol($bar).unwrap(),
308                MusicSymbol::Bar($bar.to_string())
309            )
310        };
311    }
312
313    #[test]
314    fn bar_1() {
315        assert_bar!("|")
316    }
317    #[test]
318    fn bar_2() {
319        assert_bar!("|]")
320    }
321    #[test]
322    fn bar_3() {
323        assert_bar!("||")
324    }
325    #[test]
326    fn bar_4() {
327        assert_bar!("[|")
328    }
329    #[test]
330    fn bar_5() {
331        assert_bar!("|:")
332    }
333    #[test]
334    fn bar_6() {
335        assert_bar!(":|")
336    }
337    #[test]
338    fn bar_7() {
339        assert_bar!("::")
340    }
341    #[test]
342    fn bar_8() {
343        assert_bar!("[|]")
344    }
345
346    macro_rules! assert_dec {
347        ($input:tt, $expected:expr) => {
348            assert_eq!(
349                abc::music_symbol($input).unwrap(),
350                MusicSymbol::new_note($expected, None, Note::A, 1, 1.0, None)
351            );
352        };
353    }
354
355    #[test]
356    fn decoration_1() {
357        assert_dec!(".A", vec![Decoration::Staccato])
358    }
359    #[test]
360    fn decoration_2() {
361        assert_dec!("~A", vec![Decoration::Roll])
362    }
363    #[test]
364    fn decoration_3() {
365        assert_dec!("HA", vec![Decoration::Fermata])
366    }
367    #[test]
368    fn decoration_4() {
369        assert_dec!("LA", vec![Decoration::Accent])
370    }
371    #[test]
372    fn decoration_5() {
373        assert_dec!("MA", vec![Decoration::LowerMordent])
374    }
375    #[test]
376    fn decoration_6() {
377        assert_dec!("OA", vec![Decoration::Coda])
378    }
379    #[test]
380    fn decoration_7() {
381        assert_dec!("PA", vec![Decoration::UpperMordent])
382    }
383    #[test]
384    fn decoration_8() {
385        assert_dec!("SA", vec![Decoration::Segno])
386    }
387    #[test]
388    fn decoration_9() {
389        assert_dec!("TA", vec![Decoration::Trill])
390    }
391    #[test]
392    fn decoration_10() {
393        assert_dec!("uA", vec![Decoration::UpBow])
394    }
395    #[test]
396    fn decoration_11() {
397        assert_dec!("vA", vec![Decoration::DownBow])
398    }
399    #[test]
400    fn decoration_12() {
401        assert_dec!(
402            "!somedec!A",
403            vec![Decoration::Unresolved("somedec".to_string())]
404        )
405    }
406
407    #[test]
408    fn multiple_decorations() {
409        assert_dec!("v.A", vec![Decoration::DownBow, Decoration::Staccato]);
410    }
411
412    #[test]
413    fn decoration_invalid() {
414        abc::music_symbol("!A").unwrap_err();
415    }
416
417    macro_rules! assert_acc {
418        ($input:tt, $expected:expr) => {
419            assert_eq!(
420                abc::music_symbol($input).unwrap(),
421                MusicSymbol::new_note(vec![], Some($expected), Note::A, 1, 1.0, None)
422            )
423        };
424    }
425
426    #[test]
427    fn accidental_1() {
428        assert_acc!("^A", Accidental::Sharp)
429    }
430    #[test]
431    fn accidental_2() {
432        assert_acc!("_A", Accidental::Flat)
433    }
434    #[test]
435    fn accidental_3() {
436        assert_acc!("=A", Accidental::Natural)
437    }
438    #[test]
439    fn accidental_4() {
440        assert_acc!("^^A", Accidental::DoubleSharp)
441    }
442    #[test]
443    fn accidental_5() {
444        assert_acc!("__A", Accidental::DoubleFlat)
445    }
446
447    #[test]
448    fn accidental_invalid_1() {
449        abc::music_symbol("^^^A").unwrap_err();
450    }
451    #[test]
452    fn accidental_invalid_2() {
453        abc::music_symbol("___A").unwrap_err();
454    }
455    #[test]
456    fn accidental_invalid_3() {
457        abc::music_symbol("_^_A").unwrap_err();
458    }
459    #[test]
460    fn accidental_invalid_4() {
461        abc::music_symbol("^_A").unwrap_err();
462    }
463
464    macro_rules! assert_oct {
465        ($input:tt, $expected:expr) => {
466            assert_eq!(
467                abc::music_symbol($input).unwrap(),
468                MusicSymbol::new_note(vec![], None, Note::A, $expected, 1.0, None)
469            );
470        };
471    }
472
473    #[test]
474    fn octave_1() {
475        assert_oct!("A,", 0)
476    }
477    #[test]
478    fn octave_2() {
479        assert_oct!("A'", 2)
480    }
481    #[test]
482    fn octave_3() {
483        assert_oct!("A,,,", -2)
484    }
485    #[test]
486    fn octave_4() {
487        assert_oct!("A''''", 5)
488    }
489    #[test]
490    fn octave_5() {
491        assert_oct!("A,'", 1)
492    }
493    #[test]
494    fn octave_6() {
495        assert_oct!("A,'',,','", 1)
496    }
497
498    #[test]
499    fn tie() {
500        assert_eq!(
501            abc::music_line("A-A").unwrap(),
502            MusicLine::new(vec![
503                MusicSymbol::new_note(vec![], None, Note::A, 1, 1.0, Some(Tie::Solid)),
504                MusicSymbol::new_note(vec![], None, Note::A, 1, 1.0, None)
505            ])
506        );
507    }
508
509    #[test]
510    fn tie_across_bars() {
511        assert_eq!(
512            abc::music_line("abc-|cba").unwrap(),
513            MusicLine::new(vec![
514                MusicSymbol::new_note(vec![], None, Note::A, 2, 1.0, None),
515                MusicSymbol::new_note(vec![], None, Note::B, 2, 1.0, None),
516                MusicSymbol::new_note(vec![], None, Note::C, 2, 1.0, Some(Tie::Solid)),
517                MusicSymbol::Bar("|".to_string()),
518                MusicSymbol::new_note(vec![], None, Note::C, 2, 1.0, None),
519                MusicSymbol::new_note(vec![], None, Note::B, 2, 1.0, None),
520                MusicSymbol::new_note(vec![], None, Note::A, 2, 1.0, None),
521            ])
522        );
523    }
524
525    #[test]
526    fn tie_with_length() {
527        assert_eq!(
528            abc::music_line("c4-c4").unwrap(),
529            MusicLine::new(vec![
530                MusicSymbol::new_note(vec![], None, Note::C, 2, 4.0, Some(Tie::Solid)),
531                MusicSymbol::new_note(vec![], None, Note::C, 2, 4.0, None)
532            ])
533        );
534    }
535
536    #[test]
537    fn tie_dotted() {
538        assert_eq!(
539            abc::music_line("C.-C").unwrap(),
540            MusicLine::new(vec![
541                MusicSymbol::new_note(vec![], None, Note::C, 1, 1.0, Some(Tie::Dotted)),
542                MusicSymbol::new_note(vec![], None, Note::C, 1, 1.0, None)
543            ])
544        );
545    }
546
547    #[test]
548    fn invalid_tie() {
549        assert!(abc::music_line("c4 -c4").is_err());
550        assert!(abc::music_line("abc|-cba").is_err());
551    }
552
553    macro_rules! assert_rst {
554        ($input:tt, $expected:expr) => {
555            assert_eq!(
556                abc::music_symbol($input).unwrap(),
557                MusicSymbol::Rest($expected)
558            )
559        };
560    }
561
562    #[test]
563    fn rest_1() {
564        assert_rst!("z", Rest::Note(1))
565    }
566    #[test]
567    fn rest_2() {
568        assert_rst!("x", Rest::NoteHidden(1))
569    }
570    #[test]
571    fn rest_3() {
572        assert_rst!("Z", Rest::Measure(1))
573    }
574    #[test]
575    fn rest_4() {
576        assert_rst!("X", Rest::MeasureHidden(1))
577    }
578    #[test]
579    fn rest_5() {
580        assert_rst!("z3", Rest::Note(3))
581    }
582    #[test]
583    fn rest_6() {
584        assert_rst!("Z10", Rest::Measure(10))
585    }
586    #[test]
587    fn rest_7() {
588        assert_rst!("x7", Rest::NoteHidden(7))
589    }
590    #[test]
591    fn rest_8() {
592        assert_rst!("X900", Rest::MeasureHidden(900))
593    }
594
595    #[ignore]
596    #[test]
597    fn endings_general() {
598        let m = abc::music_line("f|[1 d:|[2 d2 B|]").unwrap();
599        assert_eq!(
600            m,
601            MusicLine::new(vec![
602                MusicSymbol::new_note(vec![], None, Note::F, 2, 1.0, None),
603                MusicSymbol::Bar("|".to_string()),
604                MusicSymbol::Ending(1),
605                MusicSymbol::new_note(vec![], None, Note::D, 2, 1.0, None),
606                MusicSymbol::Bar(":|".to_string()),
607                MusicSymbol::Ending(2),
608                MusicSymbol::new_note(vec![], None, Note::D, 2, 2.0, None),
609                MusicSymbol::VisualBreak,
610                MusicSymbol::note(Note::B),
611                MusicSymbol::Bar("|]".to_string())
612            ])
613        );
614    }
615
616    #[test]
617    fn endings_1() {
618        assert_eq!(abc::ending("[1").unwrap(), MusicSymbol::Ending(1))
619    }
620    #[test]
621    fn endings_2() {
622        assert_eq!(abc::ending("[2").unwrap(), MusicSymbol::Ending(2))
623    }
624    #[test]
625    fn endings_3() {
626        assert_eq!(abc::ending("[87654").unwrap(), MusicSymbol::Ending(87654))
627    }
628
629    #[ignore]
630    #[test]
631    fn ending_after_bar() {
632        let m = abc::music_line("|[1").unwrap();
633        assert_eq!(
634            m,
635            MusicLine::new(vec![
636                MusicSymbol::Bar("|".to_string()),
637                MusicSymbol::Ending(1)
638            ])
639        )
640    }
641
642    #[test]
643    fn chord_1() {
644        let c = abc::music_symbol("[CEG]").unwrap();
645        assert_eq!(
646            c,
647            MusicSymbol::Chord {
648                decorations: vec![],
649                notes: vec![
650                    MusicSymbol::note(Note::C),
651                    MusicSymbol::note(Note::E),
652                    MusicSymbol::note(Note::G)
653                ],
654                length: 1.0
655            }
656        );
657    }
658
659    #[test]
660    fn chord_2() {
661        let c = abc::music_symbol("[C2E2G2]3").unwrap();
662        assert_eq!(
663            c,
664            MusicSymbol::Chord {
665                decorations: vec![],
666                notes: vec![
667                    MusicSymbol::note_from_length(Note::C, 2.0),
668                    MusicSymbol::note_from_length(Note::E, 2.0),
669                    MusicSymbol::note_from_length(Note::G, 2.0)
670                ],
671                length: 3.0
672            }
673        );
674    }
675
676    #[test]
677    fn grace_notes_1() {
678        let g = abc::music_symbol("{GdGe}").unwrap();
679        assert_eq!(
680            g,
681            MusicSymbol::GraceNotes {
682                acciaccatura: None,
683                notes: vec![
684                    MusicSymbol::note(Note::G),
685                    MusicSymbol::new_note(vec![], None, Note::D, 2, 1.0, None),
686                    MusicSymbol::note(Note::G),
687                    MusicSymbol::new_note(vec![], None, Note::E, 2, 1.0, None)
688                ]
689            }
690        )
691    }
692
693    #[test]
694    fn grace_notes_2() {
695        let g = abc::music_symbol("{/g}").unwrap();
696        assert_eq!(
697            g,
698            MusicSymbol::GraceNotes {
699                acciaccatura: Some(()),
700                notes: vec![MusicSymbol::new_note(vec![], None, Note::G, 2, 1.0, None)]
701            }
702        )
703    }
704
705    macro_rules! assert_tup {
706        ($input:tt, $p:expr, $q:expr, $r:expr, $($expected:expr), *) => {
707            assert_eq!(
708                abc::music_symbol($input).unwrap(),
709                MusicSymbol::Tuplet {
710                    p: $p,
711                    q: $q,
712                    r: $r,
713                    notes: vec![
714                        $(
715                            MusicSymbol::note($expected),
716                        )*
717                    ]
718                }
719            )
720        };
721    }
722
723    #[test]
724    fn tuplet_1() {
725        assert_tup!("(2AB", 2, 3, 2, Note::A, Note::B)
726    }
727    #[test]
728    fn tuplet_2() {
729        assert_tup!("(2 AB", 2, 3, 2, Note::A, Note::B)
730    }
731    #[test]
732    fn tuplet_3() {
733        assert_tup!("(3ABC", 3, 2, 3, Note::A, Note::B, Note::C)
734    }
735    #[test]
736    fn tuplet_4() {
737        assert_tup!("(3::ABC", 3, 2, 3, Note::A, Note::B, Note::C)
738    }
739    #[test]
740    fn tuplet_5() {
741        assert_tup!("(3:2ABC", 3, 2, 3, Note::A, Note::B, Note::C)
742    }
743    #[test]
744    fn tuplet_6() {
745        assert_tup!("(3:2:3ABC", 3, 2, 3, Note::A, Note::B, Note::C)
746    }
747    #[test]
748    fn tuplet_7() {
749        assert_tup!(
750            "(9ABCDEFGAB",
751            9,
752            0,
753            9,
754            Note::A,
755            Note::B,
756            Note::C,
757            Note::D,
758            Note::E,
759            Note::F,
760            Note::G,
761            Note::A,
762            Note::B
763        )
764    }
765}