use datatypes::*;
number -> u32
= n:$([1-9][0-9]*) { n.parse().unwrap() }
space
= [ \t]+
pub tune_book -> TuneBook
= h:file_header? ts:tune* { TuneBook::new(h, ts) } /
!. { TuneBook::new(None, vec![]) }
pub file_header -> FileHeader
= fields:info_field* [\n] { FileHeader::new(fields) }
pub tune -> Tune
= h:tune_header b:tune_body? { Tune::new(h, b) }
pub tune_header -> TuneHeader
= "X:" n:number [\n]
t:info_field<'T'>
extra:info_field_non_special*
k:info_field<'K'> {
let mut info = vec![InfoField::new('X', n.to_string()), t];
for field in extra.into_iter() { info.push(field); }
info.push(k);
TuneHeader::new(info)
}
info_field<N> = name:$(N) ":" t:$((![\n].)*) [\n] {
InfoField::new(
name.chars().next().unwrap(),
t.to_string()
)
}
info_field -> InfoField
= info_field<[A-Za-z]>
info_field_non_special -> InfoField
= info_field<![KX][A-Za-z]>
pub tune_body -> TuneBody
= m:music_line+ { TuneBody::new(m) } /
[\n] { TuneBody::new(vec![]) }
pub music_line -> MusicLine
= s:music_symbol+ music_line_end { MusicLine::new(s) }
pub music_symbol -> MusicSymbol
= n:note "`"* { n } /
r:rest { r } /
c:chord { c } /
b:bar { b } /
e:ending { e } /
g:grace_notes { g } /
t:tuplet { t } /
space { MusicSymbol::VisualBreak() }
pub note -> MusicSymbol
= d:decoration? a:accidental? n:$([a-gA-G]) o:octave? l:length? {
MusicSymbol::new_note(
d, a, n.chars().next().unwrap(), o.unwrap_or(1), l.unwrap_or(1.0)
)
}
pub bar -> MusicSymbol
= b:$([:|[\]]+) { MusicSymbol::Bar(b.to_string()) }
music_line_end
= [\n] / !.
decoration -> Decoration
= d:decoration_symbol space? { d }
decoration_symbol -> Decoration
= "." { Decoration::Staccato() } /
"~" { Decoration::Roll() } /
"H" { Decoration::Fermata() } /
"L" { Decoration::Accent() } /
"M" { Decoration::LowerMordent() } /
"O" { Decoration::Coda() } /
"P" { Decoration::UpperMordent() } /
"S" { Decoration::Segno() } /
"T" { Decoration::Trill() } /
"u" { Decoration::UpBow() } /
"v" { Decoration::DownBow() } /
"!" d:$((![\n!].)+) "!" { Decoration::Unresolved(d.to_string()) }
accidental -> Accidental
= "^^" { Accidental::DoubleSharp() } /
"__" { Accidental::DoubleFlat() } /
"^" { Accidental::Sharp() } /
"_" { Accidental::Flat() } /
"=" { Accidental::Natural() }
octave -> i8
= p:$([,']+) {
let mut octave = 1;
for c in p.chars() {
match c {
',' => octave -= 1,
'\'' => octave += 1,
_ => panic!("Parser malfunctioned. Unexpected octave identifier")
}
}
octave
}
length -> f32
= "/" n:number { 1.0 / (n as f32) } /
s:$("/"+) { 1.0 / (s.len() as f32).exp2() } /
n1:number "/" n2:number { (n1 as f32) / (n2 as f32) } /
n:number { n as f32 }
pub rest -> MusicSymbol
= "z" n:number? { MusicSymbol::Rest(Rest::Note(n.unwrap_or(1))) } /
"Z" n:number? { MusicSymbol::Rest(Rest::Measure(n.unwrap_or(1))) } /
"x" n:number? { MusicSymbol::Rest(Rest::NoteHidden(n.unwrap_or(1))) } /
"X" n:number? { MusicSymbol::Rest(Rest::MeasureHidden(n.unwrap_or(1))) }
pub ending -> MusicSymbol
= "[" n:number space? { MusicSymbol::Ending(n) }
pub chord -> MusicSymbol
= d:decoration? "[" n:note+ "]" l:length? {
MusicSymbol::Chord {
decoration: d,
notes: n,
length: l.unwrap_or(1f32)
}
}
pub grace_notes -> MusicSymbol
= "{" a:"/"? n:note* "}" {
MusicSymbol::GraceNotes {
acciaccatura: a,
notes: n
}
}
pub tuplet -> MusicSymbol
= "(" p:number space? n:note*<{ p as usize }> {?
MusicSymbol::tuplet_with_defaults(p, None, None, n)
} /
"(" p:number ":" q:number? ":" r:number? space? n:note*<{ p as usize }> {?
MusicSymbol::tuplet_with_defaults(p, q, r, n)
} /
"(" p:number ":" q:number space? n:note*<{ p as usize }> {?
MusicSymbol::tuplet_with_defaults(p, Some(q), None, n)
}