Permalink
Browse files

Allow [ABC] chords to have durations and "is tied" flags. This goes a…

…gainst the "draft 2.0" ABC grammar we've been working from, but matches the text of the "official" ABC 2.0 standard -- not to mention the Anthony Francis project ABC files.
  • Loading branch information...
1 parent 5dca9b7 commit 83d7ac72c5c94209f6571a349c43ed1dc7284b99 @colomon committed May 15, 2012
Showing with 53 additions and 4 deletions.
  1. +1 −1 lib/ABC/Actions.pm
  2. +1 −1 lib/ABC/Grammar.pm
  3. +3 −2 lib/ABC/Stem.pm
  4. +26 −0 t/01-regexes.t
  5. +22 −0 t/05-actions.t
View
2 lib/ABC/Actions.pm
@@ -46,7 +46,7 @@ class ABC::Actions {
if @( $<mnote> ) == 1 {
make $<mnote>[0].ast;
} else {
- make ABC::Stem.new(@( $<mnote> )>>.ast);
+ make ABC::Stem.new(@( $<mnote> )>>.ast, $<note_length>.ast, ?$<tie>);
}
}
View
2 lib/ABC/Grammar.pm
@@ -18,7 +18,7 @@ grammar ABC::Grammar
regex note_length_denominator { '/' <bottom=number>? }
regex note_length { <top=number>? <note_length_denominator>? }
regex mnote { <pitch> <note_length> <tie>? }
- regex stem { <mnote> | [ '[' <mnote>+ ']' ] }
+ regex stem { <mnote> | [ '[' <mnote>+ ']' <note_length> <tie>? ] }
regex rest_type { <[x..z]> }
regex rest { <rest_type> <note_length> }
View
5 lib/ABC/Stem.pm
@@ -4,9 +4,10 @@ use ABC::Duration;
class ABC::Stem does ABC::Duration {
has @.notes;
+ has $.is-tie;
- method new(@notes) {
+ method new(@notes, ABC::Duration $duration, $is-tie) {
die "Stem must have at least one note" if +@notes == 0;
- self.bless(*, :@notes, :ticks(@notes>>.ticks.max));
+ self.bless(*, :@notes, :ticks(@notes>>.ticks.max * $duration.ticks), :$is-tie);
}
}
View
26 t/01-regexes.t
@@ -200,6 +200,32 @@ use ABC::Grammar;
is $match<stem>[2], "c", 'third note is c';
}
+{
+ my $match = ABC::Grammar.parse("[a2bc]3", :rule<stem>);
+ isa_ok $match, Match, 'Got a match';
+ ok $match, '"[a2bc]3" is a stem';
+ is ~$match, "[a2bc]3", '"[a2bc]3" was the portion matched';
+ is +@( $match<mnote> ), 3, 'Three notes matched';
+ is $match<mnote>[0], "a2", 'first note is a2';
+ is $match<mnote>[1], "b", 'second note is b';
+ is $match<mnote>[2], "c", 'third note is c';
+ is $match<note_length>, "3", 'correct duration';
+ nok ?$match<tie>, 'not tied';
+}
+
+{
+ my $match = ABC::Grammar.parse("[a2bc]3-", :rule<stem>);
+ isa_ok $match, Match, 'Got a match';
+ ok $match, '"[a2bc]3-" is a stem';
+ is ~$match, "[a2bc]3-", '"[a2bc]3-" was the portion matched';
+ is +@( $match<mnote> ), 3, 'Three notes matched';
+ is $match<mnote>[0], "a2", 'first note is a2';
+ is $match<mnote>[1], "b", 'second note is b';
+ is $match<mnote>[2], "c", 'third note is c';
+ is $match<note_length>, "3", 'correct duration';
+ ok ?$match<tie>, 'tied';
+}
+
# (3 is the only case that works currently. :(
# {
# my $match = ABC::Grammar.parse("(2abcd", :rule<tuple>);
View
22 t/05-actions.t
@@ -90,6 +90,28 @@ use ABC::Chord;
}
{
+ my $match = ABC::Grammar.parse("[a2bc]3", :rule<stem>, :actions(ABC::Actions.new));
+ ok $match, 'element recognized';
+ isa_ok $match.ast, ABC::Stem, '$match.ast is an ABC::Stem';
+ is $match.ast.notes[0], "a2", "Pitch 1 a";
+ is $match.ast.notes[1], "b", "Pitch 2 b";
+ is $match.ast.notes[2], "c", "Pitch 3 c";
+ is $match.ast.ticks, 6, "Duration 6 ticks";
+ nok $match.ast.is-tie, "Not tied";
+}
+
+{
+ my $match = ABC::Grammar.parse("[a2bc]/-", :rule<stem>, :actions(ABC::Actions.new));
+ ok $match, 'element recognized';
+ isa_ok $match.ast, ABC::Stem, '$match.ast is an ABC::Stem';
+ is $match.ast.notes[0], "a2", "Pitch 1 a";
+ is $match.ast.notes[1], "b", "Pitch 2 b";
+ is $match.ast.notes[2], "c", "Pitch 3 c";
+ is $match.ast.ticks, 1, "Duration 1 tick";
+ ok $match.ast.is-tie, "Tied";
+}
+
+{
my $match = ABC::Grammar.parse("z/", :rule<rest>, :actions(ABC::Actions.new));
ok $match, 'rest recognized';
isa_ok $match.ast, ABC::Rest, '$match.ast is an ABC::Rest';

0 comments on commit 83d7ac7

Please sign in to comment.