abc_parser/
grammar.rs

1use datatypes::*;
2
3peg::parser! {
4/// Module generated by [rust_peg](https://crates.io/crates/peg)
5///
6/// Each function corresponds to a rule in the grammar and can be called with an input string
7/// to begin parsing that type of ABC object.
8///
9/// # Examples
10/// Usually you will want to parse whole ABC files in which case you will want to use
11/// `abc::tune_book`.
12/// ```
13/// use abc_parser::datatypes::*;
14/// use abc_parser::abc;
15///
16/// let parsed = abc::tune_book("X:1\nT:Example\nK:D\n").unwrap();
17/// assert_eq!(
18///     parsed,
19///     TuneBook::new(None, vec![
20///         Tune::new(
21///             TuneHeader::new(vec![
22///                 InfoField::new('X', "1".to_string()),
23///                 InfoField::new('T', "Example".to_string()),
24///                 InfoField::new('K', "D".to_string())
25///             ]),
26///             None
27///         )
28///     ])
29/// )
30/// ```
31/// If you know that you will only be parsing one tune you can use `abc::tune`.
32/// ```
33/// use abc_parser::datatypes::*;
34/// use abc_parser::abc;
35///
36/// let parsed = abc::tune("X:1\nT:Example\nK:D\n").unwrap();
37/// assert_eq!(
38///     parsed,
39///     Tune::new(
40///         TuneHeader::new(vec![
41///             InfoField::new('X', "1".to_string()),
42///             InfoField::new('T', "Example".to_string()),
43///             InfoField::new('K', "D".to_string())
44///         ]),
45///         None
46///     )
47/// )
48/// ```
49pub grammar abc() for str {
50    rule number() -> u32
51        = n:$(['1'..='9']['0'..='9']*) { n.parse().unwrap() }
52
53    rule space()
54        = [' ' | '\t']+
55
56    rule optional_space()
57        = [' ' | '\t']*
58
59    pub rule tune_book() -> TuneBook
60        = h:file_header()? ts:tune()* { TuneBook::new(h, ts) } /
61          ![_] { TuneBook::new(None, vec![]) }
62
63    pub rule file_header() -> FileHeader
64        = fields:info_field_any()* "\n" { FileHeader::new(fields) }
65
66    pub rule tune() -> Tune
67        = h:tune_header() b:tune_body()? { Tune::new(h, b) }
68
69    pub rule tune_header() -> TuneHeader
70        = "X:" optional_space() n:number() "\n"
71          t:info_field(<$("T")>)
72          extra:info_field_non_special()*
73          k:info_field(<$("K")>) {
74            let mut info = vec![InfoField::new('X', n.to_string()), t];
75            for field in extra.into_iter() { info.push(field); }
76            info.push(k);
77            TuneHeader::new(info)
78        }
79
80    rule info_field<'a>(n: rule<&'a str>) -> InfoField
81        = name:n() ":" optional_space() t:$((!"\n"[_])*) "\n" {
82        InfoField::new(
83            name.chars().next().unwrap(),
84            t.to_string()
85        )
86    }
87
88    rule info_field_any() -> InfoField
89        = info_field(<$(['A'..='Z' | 'a'..='z'])>)
90
91    rule info_field_non_special() -> InfoField
92        = info_field(<$(!['K' | 'X']['A'..='Z' | 'a'..='z'])>)
93
94    pub rule tune_body() -> TuneBody
95        = m:music_line()+ { TuneBody::new(m) } /
96          "\n" { TuneBody::new(vec![]) }
97
98    pub rule music_line() -> MusicLine
99        = s:music_symbol()+ music_line_end() { MusicLine::new(s) }
100
101    pub rule music_symbol() -> MusicSymbol
102        = n:note() "`"* { n } /
103          r:rest() { r } /
104          c:chord() { c } /
105          b:bar() { b } /
106          e:ending() { e } /
107          g:grace_notes() { g } /
108          t:tuplet() { t } /
109          space() { MusicSymbol::VisualBreak }
110
111    pub rule note() -> MusicSymbol
112        = d:decorations() a:accidental()? n:note_uppercase() o:octave()? l:length()? t:tie()? {
113            MusicSymbol::new_note(
114                d, a, n, o.unwrap_or(1), l.unwrap_or(1.0), t
115            )
116        } /
117        d:decorations() a:accidental()? n:note_lowercase() o:octave()? l:length()? t:tie()? {
118            MusicSymbol::new_note(
119                d, a, n, o.unwrap_or(1) + 1, l.unwrap_or(1.0), t
120            )
121        }
122
123    pub rule note_uppercase() -> Note
124        = "A" { Note::A } /
125          "B" { Note::B } /
126          "C" { Note::C } /
127          "D" { Note::D } /
128          "E" { Note::E } /
129          "F" { Note::F } /
130          "G" { Note::G }
131
132    pub rule note_lowercase() -> Note
133        = "a" { Note::A } /
134          "b" { Note::B } /
135          "c" { Note::C } /
136          "d" { Note::D } /
137          "e" { Note::E } /
138          "f" { Note::F } /
139          "g" { Note::G }
140
141    rule tie() -> Tie
142        = ".-" { Tie::Dotted } /
143          "-" { Tie::Solid }
144
145    pub rule bar() -> MusicSymbol
146        = b:$([':' | '|' | '[' | '\\' | ']']+) { MusicSymbol::Bar(b.to_string()) }
147
148    rule music_line_end()
149        = "\n" / ![_]
150
151    rule decorations() -> Vec<Decoration>
152        = decoration()*
153
154    rule decoration() -> Decoration
155        = d:decoration_symbol() space()? { d }
156
157    rule decoration_symbol() -> Decoration
158        = "." { Decoration::Staccato } /
159          "~" { Decoration::Roll } /
160          "H" { Decoration::Fermata } /
161          "L" { Decoration::Accent } /
162          "M" { Decoration::LowerMordent } /
163          "O" { Decoration::Coda } /
164          "P" { Decoration::UpperMordent } /
165          "S" { Decoration::Segno } /
166          "T" { Decoration::Trill } /
167          "u" { Decoration::UpBow } /
168          "v" { Decoration::DownBow } /
169          "!" d:$((!['\n' | '!'][_])+) "!" { Decoration::Unresolved(d.to_string()) }
170
171    rule accidental() -> Accidental
172        = "^^" { Accidental::DoubleSharp } /
173          "__" { Accidental::DoubleFlat } /
174          "^" { Accidental::Sharp } /
175          "_" { Accidental::Flat } /
176          "=" { Accidental::Natural }
177
178    rule octave() -> i8
179        = p:$([',' | '\'']+) {
180            let mut octave = 1;
181            for c in p.chars() {
182                match c {
183                    ',' => octave -= 1,
184                    '\'' => octave += 1,
185                    _ => panic!("Parser malfunctioned. Unexpected octave identifier")
186                }
187            }
188            octave
189        }
190
191    rule length() -> f32
192        = "/" n:number() { 1.0 / (n as f32) } /
193          s:$("/"+) { 1.0 / (s.len() as f32).exp2() } /
194          n1:number() "/" n2:number() { (n1 as f32) / (n2 as f32) } /
195          n:number() { n as f32 }
196
197    pub rule rest() -> MusicSymbol
198        = "z" n:number()? { MusicSymbol::Rest(Rest::Note(n.unwrap_or(1))) } /
199          "Z" n:number()? { MusicSymbol::Rest(Rest::Measure(n.unwrap_or(1))) } /
200          "x" n:number()? { MusicSymbol::Rest(Rest::NoteHidden(n.unwrap_or(1))) } /
201          "X" n:number()? { MusicSymbol::Rest(Rest::MeasureHidden(n.unwrap_or(1))) }
202
203    pub rule ending() -> MusicSymbol
204        = "[" n:number() space()? { MusicSymbol::Ending(n) }
205
206    pub rule chord() -> MusicSymbol
207        = d:decorations() "[" n:note()+ "]" l:length()? {
208            MusicSymbol::Chord {
209                decorations: d,
210                notes: n,
211                length: l.unwrap_or(1f32)
212            }
213        }
214
215    pub rule grace_notes() -> MusicSymbol
216        = "{" a:"/"? n:note()* "}" {
217            MusicSymbol::GraceNotes {
218                acciaccatura: a,
219                notes: n
220            }
221        }
222
223    pub rule tuplet() -> MusicSymbol
224        = "(" p:number() space()? n:note()*<{ p as usize }> {?
225              MusicSymbol::tuplet_with_defaults(p, None, None, n)
226          } /
227          "(" p:number() ":" q:number()? ":" r:number()? space()? n:note()*<{ p as usize }> {?
228              MusicSymbol::tuplet_with_defaults(p, q, r, n)
229          } /
230          "(" p:number() ":" q:number() space()? n:note()*<{ p as usize }> {?
231              MusicSymbol::tuplet_with_defaults(p, Some(q), None, n)
232          }
233}}