Help language development. Donate to The Perl Foundation
use v6; use Test; use ABC::Grammar; { my $match = ABC::Grammar.parse('"Cmin"', :rule<chord_or_text>); isa-ok $match, Match, 'Got a match'; ok $match, '"Cmin" is a chord'; is $match<chord>, "Cmin", '"Cmin" is chord Cmin'; is $match<chord>[0]<basenote>, "C", '"Cmin" has base note C'; is $match<chord>[0]<chord_type>, "min", '"Cmin" has chord_type "min"'; } { my $match = ABC::Grammar.parse('"1"', :rule<chord_or_text>); isa-ok $match, Match, 'Got a match'; ok $match, '"1" is a chord or text'; is $match<text_expression>, "1", '"1" is text 1'; } { my $match = ABC::Grammar.parse("^A,", :rule<pitch>); isa-ok $match, Match, 'Got a match'; ok $match, '"^A," is a pitch'; is $match<basenote>, "A", '"^A," has base note A'; is $match<octave>, ",", '"^A," has octave ","'; is $match<accidental>, "^", '"^A," has accidental "#"'; } { my $match = ABC::Grammar.parse("_B", :rule<pitch>); isa-ok $match, Match, 'Got a match'; ok $match, '"_B" is a pitch'; is $match<basenote>, "B", '"_B" has base note B'; is $match<octave>, Nil, '"_B" has no octave'; is $match<accidental>, "_", '"_B" has accidental "_"'; } { my $match = ABC::Grammar.parse("C''", :rule<pitch>); isa-ok $match, Match, 'Got a match'; ok $match, '"note" is a pitch'; is $match<basenote>, "C", '"note" has base note C'; is $match<octave>, "''", '"note" has octave two-upticks'; is $match<accidental>, Nil, '"note" has no accidental'; } { my $match = ABC::Grammar.parse("=d,,,", :rule<pitch>); isa-ok $match, Match, 'Got a match'; ok $match, '"=d,,," is a pitch'; is $match<basenote>, "d", '"=d,,," has base note d'; is $match<octave>, ",,,", '"=d,,," has octave ",,,"'; is $match<accidental>, "=", '"=d,,," has accidental "="'; } { my $match = ABC::Grammar.parse("2", :rule<note_length>); 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<mnote>); isa-ok $match, Match, 'Got a match'; ok $match, '"^^e2" is a note'; is $match<pitch><basenote>, "e", '"^^e2" has base note e'; is $match<pitch><octave>, Nil, '"^^e2" has no octave'; is $match<pitch><accidental>, "^^", '"^^e2" has accidental "^^"'; is $match<note_length>, "2", '"^^e2" has note length 2'; } { my $match = ABC::Grammar.parse("__f'/", :rule<mnote>); isa-ok $match, Match, 'Got a match'; ok $match, '"__f/" is a note'; is $match<pitch><basenote>, "f", '"__f/" has base note f'; is $match<pitch><octave>, "'", '"__f/" has octave tick'; is $match<pitch><accidental>, "__", '"__f/" has accidental "__"'; is $match<note_length>, "/", '"__f/" has note length /'; } { my $match = ABC::Grammar.parse("G,2/3", :rule<mnote>); isa-ok $match, Match, 'Got a match'; ok $match, '"G,2/3" is a note'; is $match<pitch><basenote>, "G", '"G,2/3" has base note G'; is $match<pitch><octave>, ",", '"G,2/3" has octave ","'; is $match<pitch><accidental>, Nil, '"G,2/3" has no accidental'; is $match<note_length>, "2/3", '"G,2/3" has note length 2/3'; } { my $match = ABC::Grammar.parse("z2/3", :rule<rest>); isa-ok $match, Match, 'Got a match'; ok $match, '"z2/3" is a rest'; is $match<rest_type>, "z", '"z2/3" has base rest z'; is $match<note_length>, "2/3", '"z2/3" has note length 2/3'; } { my $match = ABC::Grammar.parse("y/3", :rule<rest>); isa-ok $match, Match, 'Got a match'; ok $match, '"y/3" is a rest'; is $match<rest_type>, "y", '"y/3" has base rest y'; is $match<note_length>, "/3", '"y/3" has note length 2/3'; } { my $match = ABC::Grammar.parse("x", :rule<rest>); isa-ok $match, Match, 'Got a match'; ok $match, '"x" is a rest'; is $match<rest_type>, "x", '"x" has base rest x'; is $match<note_length>, "", '"x" has no note length'; } { my $match = ABC::Grammar.parse("v", :rule<element>); isa-ok $match, Match, 'Got a match'; ok $match, '"v" is an element'; is $match<gracing>, "v", '"v" gracing is v'; } { my $match = ABC::Grammar.parse("T", :rule<element>); isa-ok $match, Match, 'Got a match'; ok $match, '"T" is an element'; is $match<gracing>, "T", '"T" gracing is T'; } { my $match = ABC::Grammar.parse("+trill+", :rule<element>); isa-ok $match, Match, 'Got a match'; ok $match, '"+trill+" is an element'; is $match<gracing>, "+trill+", '"+trill+" gracing is +trill+'; } { my $match = ABC::Grammar.parse("!trill!", :rule<element>); isa-ok $match, Match, 'Got a match'; ok $match, '"!trill!" is an element'; is $match<gracing>, "!trill!", '"!trill!" gracing is !trill!'; } { my $match = ABC::Grammar.parse("~", :rule<element>); isa-ok $match, Match, 'Got a match'; ok $match, '"~" is an element'; is $match<gracing>, "~", '"~" gracing is ~'; } { my $match = ABC::Grammar.parse("z/", :rule<element>); isa-ok $match, Match, 'Got a match'; ok $match, '"z/" is an element'; is $match<rest><rest_type>, "z", '"z/" has base rest z'; is $match<rest><note_length>, "/", '"z/" has length "/"'; } { my $match = ABC::Grammar.parse("(", :rule<element>); isa-ok $match, Match, 'Got a match'; ok $match, '"(" is an element'; is $match<slur_begin>, '(', '"(" is a slur begin'; } { my $match = ABC::Grammar.parse(")", :rule<element>); isa-ok $match, Match, 'Got a match'; ok $match, '")" is an element'; is $match<slur_end>, ')', '")" is a slur end'; } { my $match = ABC::Grammar.parse("_D,5/4", :rule<element>); isa-ok $match, Match, 'Got a match'; ok $match, '"_D,5/4" is an element'; is $match<stem><mnote>[0]<pitch><basenote>, "D", '"_D,5/4" has base note D'; is $match<stem><mnote>[0]<pitch><octave>, ",", '"_D,5/4" has octave ","'; is $match<stem><mnote>[0]<pitch><accidental>, "_", '"_D,5/4" is flat'; is $match<stem><mnote>[0]<note_length>, "5/4", '"_D,5/4" has note length 5/4'; } { my $match = ABC::Grammar.parse("A>^C'", :rule<broken_rhythm>); isa-ok $match, Match, 'Got a match'; ok $match, '"A>^C" is a broken rhythm'; is $match<stem>[0]<mnote>[0]<pitch><basenote>, "A", 'first note is A'; is $match<stem>[0]<mnote>[0]<pitch><octave>, Nil, 'first note has no octave'; is $match<stem>[0]<mnote>[0]<pitch><accidental>, Nil, 'first note has no accidental'; is $match<stem>[0]<mnote>[0]<note_length>, "", 'first note has no length'; is $match<broken_rhythm_bracket>, ">", 'angle is >'; is $match<stem>[1]<mnote>[0]<pitch><basenote>, "C", 'second note is C'; is $match<stem>[1]<mnote>[0]<pitch><octave>, "'", 'second note has octave tick'; is $match<stem>[1]<mnote>[0]<pitch><accidental>, "^", 'second note is sharp'; is $match<stem>[1]<mnote>[0]<note_length>, "", 'second note has no length'; } { my $match = ABC::Grammar.parse("d'+p+<<<+accent+_B", :rule<broken_rhythm>); isa-ok $match, Match, 'Got a match'; ok $match, '"d+p+<<<+accent+_B" is a broken rhythm'; given $match { is .<stem>[0]<mnote>[0]<pitch><basenote>, "d", 'first note is d'; is .<stem>[0]<mnote>[0]<pitch><octave>, "'", 'first note has an octave tick'; is .<stem>[0]<mnote>[0]<pitch><accidental>, Nil, 'first note has no accidental'; is .<stem>[0]<mnote>[0]<note_length>, "", 'first note has no length'; is .<g1>[0], "+p+", 'first gracing is +p+'; is .<broken_rhythm_bracket>, "<<<", 'angle is <<<'; is .<g2>[0], "+accent+", 'second gracing is +accent+'; is .<stem>[1]<mnote>[0]<pitch><basenote>, "B", 'second note is B'; is .<stem>[1]<mnote>[0]<pitch><octave>, Nil, 'second note has no octave'; is .<stem>[1]<mnote>[0]<pitch><accidental>, "_", 'second note is flat'; is .<stem>[1]<mnote>[0]<note_length>, "", 'second note has no length'; } } { my $match = ABC::Grammar.parse("(3abc", :rule<tuplet>); isa-ok $match, Match, 'Got a match'; ok $match, '"(3abc" is a tuplet'; is ~$match, "(3abc", '"(3abc" was the portion matched'; is [email protected]( $match<stem> ), 3, 'Three notes matched'; is $match<stem>[0], "a", 'first note is a'; is $match<stem>[1], "b", 'second note is b'; is $match<stem>[2], "c", 'third note is c'; } { my $match = ABC::Grammar.parse("(3 ab c", :rule<tuplet>); 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 [email protected]( $match<stem> ), 3, 'Three notes matched'; is $match<stem>[0], "a", 'first note is a'; is $match<stem>[1], "b", 'second note is b'; is $match<stem>[2], "c", 'third note is c'; } { my $match = ABC::Grammar.parse("(5abcde", :rule<tuplet>); isa-ok $match, Match, 'Got a match'; ok $match, '"(5abcde" is a tuplet'; is ~$match, "(5abcde", '"(5abcde" was the portion matched'; is [email protected]( $match<stem> ), 5, 'Three notes matched'; is $match<stem>[0], "a", 'first note is a'; is $match<stem>[1], "b", 'second note is b'; is $match<stem>[2], "c", 'third note is c'; is $match<stem>[3], "d", 'fourth note is d'; is $match<stem>[4], "e", 'fifth note is e'; } { 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 [email protected]( $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 [email protected]( $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'; } { my $match = ABC::Grammar.parse("[A3 D3 ]", :rule<stem>); 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 [email protected]( $match<mnote> ), 2, 'Two notes matched'; is $match<mnote>[0], "A3", 'first note is A3'; is $match<mnote>[1], "D3", 'second note is D3'; nok ?$match<tie>, 'not tied'; } # (3 is the only case that works currently. :( # { # my $match = ABC::Grammar.parse("(2abcd", :rule<tuple>); # isa-ok $match, Match, '"(2ab" is a tuple'; # is ~$match, "(2ab", '"(2ab" was the portion matched'; # is $match<stem>[0], "a", 'first note is a'; # is $match<stem>[1], "b", 'second note is b'; # } for ':|:', '|:', '|', ':|', '::', '|]' { my $match = ABC::Grammar.parse($_, :rule<barline>); 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<bar>); isa-ok $match, Match, 'Got a match'; ok $match, 'bar recognized'; is $match, "g>ecgece/f/g/e/|", "Entire bar was matched"; is $match<element>.flatmap(~*), "g>e c g e c e/ f/ g/ e/", "Each element was matched"; is $match<barline>, "|", "Barline was matched"; } { my $match = ABC::Grammar.parse("g>ecg ec e/f/g/e/ |", :rule<bar>); 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<element>.flatmap(~*), "g>e c g e c e/ f/ g/ e/ ", "Each element was matched"; is $match<barline>, "|", "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<line_of_music>); isa-ok $match, Match, 'Got a match'; ok $match, 'line of music recognized'; is $match, $line, "Entire line was matched"; is $match<bar>[0], "g>ecg ec e/f/g/e/ |", "First bar is correct"; is $match<bar>[1], " d/c/B/A/ Gd BG B/c/d/B/ |", "Second bar is correct"; # say $match<ABC::Grammar::line_of_music>.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<line_of_music>); isa-ok $match, Match, 'Got a match'; ok $match, 'line of music recognized'; is $match, $line, "Entire line was matched"; is $match<bar>[0], "g>ecg ec e/f/g/e/ |", "First bar is correct"; is $match<bar>[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<ABC::Grammar::line_of_music>.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<line_of_music>); isa-ok $match, Match, 'Got a match'; ok $match, 'line of music recognized'; is $match, $line, "Entire line was matched"; is $match<bar>[0], "A/B/c/A/ c>d e>deg |", "First bar is correct"; is $match<bar>[1], " dB/A/ gB +trill+A2 +trill+e2 ::", "Second bar is correct"; is $match<barline>, "|", "Initial barline matched"; # say $match<ABC::Grammar::line_of_music>.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<line_of_music>); isa-ok $match, Match, 'Got a match'; ok $match, 'line of music recognized'; is $match, $line, "Entire line was matched"; is $match<bar>[0], "g>ecg ec e/f/g/e/ |", "First bar is correct"; is $match<bar>[1], '[2-3 d/c/B/A/ {Gd} BG B/c/d/B/ |', "Second bar is correct"; # say $match<ABC::Grammar::line_of_music>.perl; } { my $match = ABC::Grammar.parse("[K:F]", :rule<inline_field>); isa-ok $match, Match, 'Got a match'; ok $match, 'inline field recognized'; is $match, "[K:F]", "Entire string was matched"; is $match<alpha>, "K", "Correct field name found"; is $match<value>, "F", "Correct field value found"; } { my $match = ABC::Grammar.parse("[M:3/4]", :rule<inline_field>); isa-ok $match, Match, 'Got a match'; ok $match, 'inline field recognized'; is $match, "[M:3/4]", "Entire string was matched"; is $match<alpha>, "M", "Correct field name found"; is $match<value>, "3/4", "Correct field value found"; } { my $match = ABC::Grammar.parse(" % this is a comment", :rule<comment_line>); 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<comment_line>); 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<line_of_music>); isa-ok $match, Match, 'Got a match'; ok $match, 'line of music recognized'; is $match, $line, "Entire line was matched"; is $match<bar>[0], "g>ecg ec e/f/g/e/ |", "First bar is correct"; is $match<bar>[1], " d/c/B/A/ [K:F] Gd BG B/c/d/B/ |", "Second bar is correct"; ok @( $match<bar>[1]<element> ).grep("[K:F]"), "Key change got recognized"; # say $match<ABC::Grammar::line_of_music>.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<line_of_music>); isa-ok $match, Match, 'Got a match'; ok $match, 'line of music recognized'; is $match, $line, "Entire line was matched"; is $match<bar>[0], "g>ecg ec e/f/g/e/ |", "First bar is correct"; is $match<bar>[1], " d/c/B/A/ [M:C] Gd BG B/c/d/B/ |", "Second bar is correct"; ok @( $match<bar>[1]<element> ).grep("[M:C]"), "Meter change got recognized"; # say $match<ABC::Grammar::line_of_music>.perl; } { my $line = "| [K:F] Gd BG [B/c/d/B/]|"; my $match = ABC::Grammar.parse($line, :rule<line_of_music>); isa-ok $match, Match, 'Got a match'; ok $match, 'line of music recognized'; is $match, $line, "Entire line was matched"; is $match<bar>[0]<element>[1], "[K:F]", "Key signature change is correctly captured"; # is $match<bar>[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<line_of_music>); isa-ok $match, Match, 'Got a match'; ok $match, 'line of music recognized'; is $match, $line, "Entire line was matched"; is $match<bar>[5]<element>[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<music>); isa-ok $match, Match, 'Got a match'; ok $match, 'music recognized'; is $match<line_of_music>.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<header>); isa-ok $match, Match, 'Got a match'; ok $match, 'header recognized'; is $match<header_field>.elems, 6, "Six fields matched"; is $match<header_field>.flatmap({ .<header_field_name> }), "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<tune>); isa-ok $match, Match, 'Got a match'; ok $match, 'tune recognized'; given $match<header> { is .<header_field>.elems, 6, "Six fields matched"; is .<header_field>.flatmap({ .<header_field_name> }), "X T S M L K", "Got the right field names"; } is $match<music><line_of_music>.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<tune_file>); isa-ok $match, Match, 'Got a match'; ok $match, 'tune_file recognized'; is $match<tune>.elems, 2, 'found two tunes'; is $match<tune>[0]<music><line_of_music>.elems, 3; is $match<tune>[1]<music><line_of_music>.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<tune_file>); isa-ok $match, Match, 'Got a match'; ok $match, 'tune_file recognized'; is $match<tune>.elems, 2, 'found two tunes'; is $match<tune>[0]<music><line_of_music>.elems, 3; is $match<tune>[1]<music><line_of_music>.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<tune_file>); isa-ok $match, Match, 'Got a match'; ok $match, 'tune_file recognized'; is $match<tune>.elems, 1, 'found one tune'; is $match<tune>[0]<music><line_of_music>.elems, 2, "with two lines of music"; } done-testing;