use v6; use Test; use ABC::Grammar; { my $match = ABC::Grammar.parse('"Cmin"', :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"Cmin" is a chord'; is $match, "Cmin", '"Cmin" is chord Cmin'; is $match[0], "C", '"Cmin" has base note C'; is $match[0], "min", '"Cmin" has chord_type "min"'; } { my $match = ABC::Grammar.parse('"1"', :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"1" is a chord or text'; is $match, "1", '"1" is text 1'; } { my $match = ABC::Grammar.parse("^A,", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"^A," is a pitch'; is $match, "A", '"^A," has base note A'; is $match, ",", '"^A," has octave ","'; is $match, "^", '"^A," has accidental "#"'; } { my $match = ABC::Grammar.parse("_B", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"_B" is a pitch'; is $match, "B", '"_B" has base note B'; is $match, Nil, '"_B" has no octave'; is $match, "_", '"_B" has accidental "_"'; } { my $match = ABC::Grammar.parse("C''", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"note" is a pitch'; is $match, "C", '"note" has base note C'; is $match, "''", '"note" has octave two-upticks'; is $match, Nil, '"note" has no accidental'; } { my $match = ABC::Grammar.parse("=d,,,", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"=d,,," is a pitch'; is $match, "d", '"=d,,," has base note d'; is $match, ",,,", '"=d,,," has octave ",,,"'; is $match, "=", '"=d,,," has accidental "="'; } { my $match = ABC::Grammar.parse("2", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"2" is a note length'; is $match, "2", '"2" has note length 2'; } { my $match = ABC::Grammar.parse("^^e2", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"^^e2" is a note'; is $match, "e", '"^^e2" has base note e'; is $match, Nil, '"^^e2" has no octave'; is $match, "^^", '"^^e2" has accidental "^^"'; is $match, "2", '"^^e2" has note length 2'; } { my $match = ABC::Grammar.parse("__f'/", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"__f/" is a note'; is $match, "f", '"__f/" has base note f'; is $match, "'", '"__f/" has octave tick'; is $match, "__", '"__f/" has accidental "__"'; is $match, "/", '"__f/" has note length /'; } { my $match = ABC::Grammar.parse("G,2/3", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"G,2/3" is a note'; is $match, "G", '"G,2/3" has base note G'; is $match, ",", '"G,2/3" has octave ","'; is $match, Nil, '"G,2/3" has no accidental'; is $match, "2/3", '"G,2/3" has note length 2/3'; } { my $match = ABC::Grammar.parse("z2/3", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"z2/3" is a rest'; is $match, "z", '"z2/3" has base rest z'; is $match, "2/3", '"z2/3" has note length 2/3'; } { my $match = ABC::Grammar.parse("y/3", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"y/3" is a rest'; is $match, "y", '"y/3" has base rest y'; is $match, "/3", '"y/3" has note length 2/3'; } { my $match = ABC::Grammar.parse("x", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"x" is a rest'; is $match, "x", '"x" has base rest x'; is $match, "", '"x" has no note length'; } { my $match = ABC::Grammar.parse("v", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"v" is an element'; is $match, "v", '"v" gracing is v'; } { my $match = ABC::Grammar.parse("T", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"T" is an element'; is $match, "T", '"T" gracing is T'; } { my $match = ABC::Grammar.parse("+trill+", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"+trill+" is an element'; is $match, "+trill+", '"+trill+" gracing is +trill+'; } { my $match = ABC::Grammar.parse("!trill!", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"!trill!" is an element'; is $match, "!trill!", '"!trill!" gracing is !trill!'; } { my $match = ABC::Grammar.parse("~", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"~" is an element'; is $match, "~", '"~" gracing is ~'; } { my $match = ABC::Grammar.parse("z/", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"z/" is an element'; is $match, "z", '"z/" has base rest z'; is $match, "/", '"z/" has length "/"'; } { my $match = ABC::Grammar.parse("(", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"(" is an element'; is $match, '(', '"(" is a slur begin'; } { my $match = ABC::Grammar.parse(")", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '")" is an element'; is $match, ')', '")" is a slur end'; } { my $match = ABC::Grammar.parse("_D,5/4", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"_D,5/4" is an element'; is $match[0], "D", '"_D,5/4" has base note D'; is $match[0], ",", '"_D,5/4" has octave ","'; is $match[0], "_", '"_D,5/4" is flat'; is $match[0], "5/4", '"_D,5/4" has note length 5/4'; } { my $match = ABC::Grammar.parse("A>^C'", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"A>^C" is a broken rhythm'; is $match[0][0], "A", 'first note is A'; is $match[0][0], Nil, 'first note has no octave'; is $match[0][0], Nil, 'first note has no accidental'; is $match[0][0], "", 'first note has no length'; is $match, ">", 'angle is >'; is $match[1][0], "C", 'second note is C'; is $match[1][0], "'", 'second note has octave tick'; is $match[1][0], "^", 'second note is sharp'; is $match[1][0], "", 'second note has no length'; } { my $match = ABC::Grammar.parse("d'+p+<<<+accent+_B", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"d+p+<<<+accent+_B" is a broken rhythm'; given $match { is .[0][0], "d", 'first note is d'; is .[0][0], "'", 'first note has an octave tick'; is .[0][0], Nil, 'first note has no accidental'; is .[0][0], "", 'first note has no length'; is .[0], "+p+", 'first gracing is +p+'; is ., "<<<", 'angle is <<<'; is .[0], "+accent+", 'second gracing is +accent+'; is .[1][0], "B", 'second note is B'; is .[1][0], Nil, 'second note has no octave'; is .[1][0], "_", 'second note is flat'; is .[1][0], "", 'second note has no length'; } } { my $match = ABC::Grammar.parse("(3abc", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"(3abc" is a tuplet'; is ~$match, "(3abc", '"(3abc" was the portion matched'; is +@( $match ), 3, 'Three notes matched'; is $match[0], "a", 'first note is a'; is $match[1], "b", 'second note is b'; is $match[2], "c", 'third note is c'; } { my $match = ABC::Grammar.parse("(3 ab c", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"(3 ab c" is a tuplet'; is ~$match, "(3 ab c", '"(3 ab c" was the portion matched'; is +@( $match ), 3, 'Three notes matched'; is $match[0], "a", 'first note is a'; is $match[1], "b", 'second note is b'; is $match[2], "c", 'third note is c'; } { my $match = ABC::Grammar.parse("(5abcde", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"(5abcde" is a tuplet'; is ~$match, "(5abcde", '"(5abcde" was the portion matched'; is +@( $match ), 5, 'Three notes matched'; is $match[0], "a", 'first note is a'; is $match[1], "b", 'second note is b'; is $match[2], "c", 'third note is c'; is $match[3], "d", 'fourth note is d'; is $match[4], "e", 'fifth note is e'; } { my $match = ABC::Grammar.parse("[a2bc]3", :rule); 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 ), 3, 'Three notes matched'; is $match[0], "a2", 'first note is a2'; is $match[1], "b", 'second note is b'; is $match[2], "c", 'third note is c'; is $match, "3", 'correct duration'; nok ?$match, 'not tied'; } { my $match = ABC::Grammar.parse("[a2bc]3-", :rule); 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 ), 3, 'Three notes matched'; is $match[0], "a2", 'first note is a2'; is $match[1], "b", 'second note is b'; is $match[2], "c", 'third note is c'; is $match, "3", 'correct duration'; ok ?$match, 'tied'; } { my $match = ABC::Grammar.parse("[A3 D3 ]", :rule); isa-ok $match, Match, 'Got a match'; ok $match, '"[A3 D3 ]" is a stem'; is ~$match, "[A3 D3 ]", '"[A3 D3 ]" was the portion matched'; is +@( $match ), 2, 'Two notes matched'; is $match[0], "A3", 'first note is A3'; is $match[1], "D3", 'second note is D3'; nok ?$match, 'not tied'; } # (3 is the only case that works currently. :( # { # my $match = ABC::Grammar.parse("(2abcd", :rule); # isa-ok $match, Match, '"(2ab" is a tuple'; # is ~$match, "(2ab", '"(2ab" was the portion matched'; # is $match[0], "a", 'first note is a'; # is $match[1], "b", 'second note is b'; # } for ':|:', '|:', '|', ':|', '::', '|]' { my $match = ABC::Grammar.parse($_, :rule); isa-ok $match, Match, 'Got a match'; ok $match, "barline $_ recognized"; is $match, $_, "barline $_ is correct"; } { my $match = ABC::Grammar.parse("g>ecgece/f/g/e/|", :rule); isa-ok $match, Match, 'Got a match'; ok $match, 'bar recognized'; is $match, "g>ecgece/f/g/e/|", "Entire bar was matched"; is $match.flatmap(~*), "g>e c g e c e/ f/ g/ e/", "Each element was matched"; is $match, "|", "Barline was matched"; } { my $match = ABC::Grammar.parse("g>ecg ec e/f/g/e/ |", :rule); isa-ok $match, Match, 'Got a match'; ok $match, 'bar recognized'; is $match, "g>ecg ec e/f/g/e/ |", "Entire bar was matched"; is $match.flatmap(~*), "g>e c g e c e/ f/ g/ e/ ", "Each element was matched"; is $match, "|", "Barline was matched"; } { my $line = "g>ecg ec e/f/g/e/ | d/c/B/A/ Gd BG B/c/d/B/ |"; my $match = ABC::Grammar.parse($line, :rule); isa-ok $match, Match, 'Got a match'; ok $match, 'line of music recognized'; is $match, $line, "Entire line was matched"; is $match[0], "g>ecg ec e/f/g/e/ |", "First bar is correct"; is $match[1], " d/c/B/A/ Gd BG B/c/d/B/ |", "Second bar is correct"; # say $match.perl; } { my $line = "g>ecg ec e/f/g/e/ |1 d/c/B/A/ Gd BG B/c/d/B/ |"; my $match = ABC::Grammar.parse($line, :rule); isa-ok $match, Match, 'Got a match'; ok $match, 'line of music recognized'; is $match, $line, "Entire line was matched"; is $match[0], "g>ecg ec e/f/g/e/ |", "First bar is correct"; is $match[1], "1 d/c/B/A/ Gd BG B/c/d/B/ |", "Second bar is correct, even with stupid hacky |1 ending marker"; # say $match.perl; } { my $line = "|A/B/c/A/ c>d e>deg | dB/A/ gB +trill+A2 +trill+e2 ::"; my $match = ABC::Grammar.parse($line, :rule); isa-ok $match, Match, 'Got a match'; ok $match, 'line of music recognized'; is $match, $line, "Entire line was matched"; is $match[0], "A/B/c/A/ c>d e>deg |", "First bar is correct"; is $match[1], " dB/A/ gB +trill+A2 +trill+e2 ::", "Second bar is correct"; is $match, "|", "Initial barline matched"; # say $match.perl; } { my $line = 'g>ecg ec e/f/g/e/ |[2-3 d/c/B/A/ {Gd} BG B/c/d/B/ |'; my $match = ABC::Grammar.parse($line, :rule); isa-ok $match, Match, 'Got a match'; ok $match, 'line of music recognized'; is $match, $line, "Entire line was matched"; is $match[0], "g>ecg ec e/f/g/e/ |", "First bar is correct"; is $match[1], '[2-3 d/c/B/A/ {Gd} BG B/c/d/B/ |', "Second bar is correct"; # say $match.perl; } { my $match = ABC::Grammar.parse("[K:F]", :rule); isa-ok $match, Match, 'Got a match'; ok $match, 'inline field recognized'; is $match, "[K:F]", "Entire string was matched"; is $match, "K", "Correct field name found"; is $match, "F", "Correct field value found"; } { my $match = ABC::Grammar.parse("[M:3/4]", :rule); isa-ok $match, Match, 'Got a match'; ok $match, 'inline field recognized'; is $match, "[M:3/4]", "Entire string was matched"; is $match, "M", "Correct field name found"; is $match, "3/4", "Correct field value found"; } { my $match = ABC::Grammar.parse(" % this is a comment", :rule); isa-ok $match, Match, 'Got a match'; ok $match, 'comment line recognized'; is $match, " % this is a comment", "Entire string was matched"; } { my $match = ABC::Grammar.parse("% this is a comment", :rule); isa-ok $match, Match, 'Got a match'; ok $match, 'comment line recognized'; is $match, "% this is a comment", "Entire string was matched"; } { my $line = "g>ecg ec e/f/g/e/ | d/c/B/A/ [K:F] Gd BG B/c/d/B/ |"; my $match = ABC::Grammar.parse($line, :rule); isa-ok $match, Match, 'Got a match'; ok $match, 'line of music recognized'; is $match, $line, "Entire line was matched"; is $match[0], "g>ecg ec e/f/g/e/ |", "First bar is correct"; is $match[1], " d/c/B/A/ [K:F] Gd BG B/c/d/B/ |", "Second bar is correct"; ok @( $match[1] ).grep("[K:F]"), "Key change got recognized"; # say $match.perl; } { my $line = "g>ecg ec e/f/g/e/ | d/c/B/A/ [M:C] Gd BG B/c/d/B/ |"; my $match = ABC::Grammar.parse($line, :rule); isa-ok $match, Match, 'Got a match'; ok $match, 'line of music recognized'; is $match, $line, "Entire line was matched"; is $match[0], "g>ecg ec e/f/g/e/ |", "First bar is correct"; is $match[1], " d/c/B/A/ [M:C] Gd BG B/c/d/B/ |", "Second bar is correct"; ok @( $match[1] ).grep("[M:C]"), "Meter change got recognized"; # say $match.perl; } { my $line = "| [K:F] Gd BG [B/c/d/B/]|"; my $match = ABC::Grammar.parse($line, :rule); isa-ok $match, Match, 'Got a match'; ok $match, 'line of music recognized'; is $match, $line, "Entire line was matched"; is $match[0][1], "[K:F]", "Key signature change is correctly captured"; # is $match[1], " d/c/B/A/ [K:F] Gd BG B/c/d/B/ |", "Second bar is correct"; } { my $line = 'E2 CE GCEG|c4 B3 ^F|(A2 G2) =F2 D2|C4 {B,C}E2 D>E|[1 (D4 C2) z2:|[2 (D4 C2) z3/2 [G/2D/2]|'; my $match = ABC::Grammar.parse($line, :rule); isa-ok $match, Match, 'Got a match'; ok $match, 'line of music recognized'; is $match, $line, "Entire line was matched"; is $match[5][0], "[2", "nth repeat works"; } { my $music = q«A/B/c/A/ +trill+c>d e>deg | GG +trill+B>c d/B/A/G/ B/c/d/B/ | A/B/c/A/ c>d e>deg | dB/A/ gB +trill+A2 +trill+e2 :: g>ecg ec e/f/g/e/ | d/c/B/A/ Gd BG B/c/d/B/ | g/f/e/d/ c/d/e/f/ gc e/f/g/e/ | dB/A/ gB +trill+A2 +trill+e2 :|»; my $match = ABC::Grammar.parse($music, :rule); isa-ok $match, Match, 'Got a match'; ok $match, 'music recognized'; is $match.elems, 4, "Four lines matched"; } { my $music = q«% Comment X:64 T:Cuckold Come Out o' the Amrey S:Northumbrian Minstrelsy M:4/4 L:1/8 K:D »; my $match = ABC::Grammar.parse($music, :rule
); isa-ok $match, Match, 'Got a match'; ok $match, 'header recognized'; is $match.elems, 6, "Six fields matched"; is $match.flatmap({ . }), "X T S M L K", "Got the right field names"; } { my $music = q«X:64 T:Cuckold Come Out o' the Amrey S:Northumbrian Minstrelsy M:4/4 L:1/8 K:D A/B/c/A/ +trill+c>d e>deg | GG +trill+B>c d/B/A/G/ B/c/d/B/ | A/B/c/A/ c>d e>deg | dB/A/ gB +trill+A2 +trill+e2 :: % test comment g>ecg ec e/f/g/e/ | d/c/B/A/ Gd BG B/c/d/B/ | g/f/e/d/ c/d/e/f/ gc e/f/g/e/ | dB/A/ gB +trill+A2 +trill+e2 :| »; my $match = ABC::Grammar.parse($music, :rule); isa-ok $match, Match, 'Got a match'; ok $match, 'tune recognized'; given $match
{ is ..elems, 6, "Six fields matched"; is ..flatmap({ . }), "X T S M L K", "Got the right field names"; } is $match.elems, 4, "Four lines matched"; } { my $music = q«X:1 T:Are You Coming From The Races? O:from the playing of Frank Maher M:2/4 L:1/8 R:Single K:D DE|:F2 F2|AF ED|E2 EF|ED DE|F2 F2|AF ED|E2 D2| |[1 D2 DE:|[2 D2 dc|:B2 Bc|BA FG|AB AF| AF dc|B2 Bc|BA FA|B2 A2|[1 A2 dc:|[2 A2 X:2 T:Bride's Jig O:from the playing of Frank Maher M:2/4 L:1/8 R:Single K:Edor |:B E2 G|FE D2|E>F GA|Bc BA|B E2 G|FE D2|E>F GE|A2 A2:| |:AB cd|e4|AB cB|BA FA|AB cd|e4|AB cB|A2 A2:| »; my $match = ABC::Grammar.parse($music, :rule); isa-ok $match, Match, 'Got a match'; ok $match, 'tune_file recognized'; is $match.elems, 2, 'found two tunes'; is $match[0].elems, 3; is $match[1].elems, 2; } { my $music = q«X:1 T:Are You Coming From The Races? O:from the playing of Frank Maher M:2/4 L:1/8 R:Single K:D DE|:F2 F2|AF ED|E2 EF|ED DE|F2 F2|AF ED|E2 D2| |[1 D2 DE:|[2 D2 dc|:B2 Bc|BA FG|AB AF| AF dc|B2 Bc|BA FA|B2 A2|[1 A2 dc:|[2 A2 X:2 T:Bride's Jig O:from the playing of Frank Maher M:2/4 L:1/8 R:Single K:Edor |:B E2 G|FE D2|E>F GA|Bc BA|B E2 G|FE D2|E>F GE|A2 A2:| |:AB cd|e4|AB cB|BA FA|AB cd|e4|AB cB|A2 A2:|»; my $match = ABC::Grammar.parse($music, :rule); isa-ok $match, Match, 'Got a match'; ok $match, 'tune_file recognized'; is $match.elems, 2, 'found two tunes'; is $match[0].elems, 3; is $match[1].elems, 2; } { my $music = q«X:1 T:Canon in D C:Pachelbel M:2/2 L:1/8 K:D "D" DFAd "A" CEAc|"Bm" B,DFB "F#m" A,CFA|"G" B,DGB "D" A,DFA|"G" B,DGB "A" CEAc| "D" f4 "A" e4|"Bm" d4 "F#m" c4|"G" B4 "D" A4|"G" B4 "A" c4| »; my $match = ABC::Grammar.parse($music, :rule); isa-ok $match, Match, 'Got a match'; ok $match, 'tune_file recognized'; is $match.elems, 1, 'found one tune'; is $match[0].elems, 2, "with two lines of music"; } done-testing;