Это моя попытка решить еженедельную задачу «реализовать расширение скобок». Я написал ниже грамматику, которая должна работать. Но не.
grammar BraceExpansion
{
regex TOP { <start-txt> <to-expand> <end-txt> }
regex start-txt { <save-char>* }
regex end-txt { <save-char>* }
token save-char { <-[ \" \& \( \) \` \' \; \< \> \| ]> }
token list-element { <-[ \" \! \$ \& \( \) \` \' \; \< \> \| ]> }
token alphanum { <[ a..z A..Z 0..9 ]> }
token alpha { <[ a..z A..Z ]> }
regex num { \-? <[ 0..9 ]>+ }
regex to-expand { <range> | <list> }
regex range { <alpha-range> | <num-range> }
regex num-range { \{ <num> \. \. <num> [ \. \. <num> ]? \} }
regex alpha-range { \{ <alpha> \. \. <alpha> [ \. \.<num> ]? \} }
regex list { \{ <list-element>+ % ',' \} }
}
say brace-expand( 'A{1..3}B{a..g..3}C{1,2}D' );
sub num-range( $match )
{
say "-NUM-";
my @num = |$match<range><num-range><num>.list>>.Int;
my @range = @num[0] ... @num[1];
my $steps = ( @num[2] // 1 ).abs;
@range.batch( $steps )>>.[0];
}
sub alpha-range( $match )
{
say "-ALPHA-";
my @num = |$match<range><alpha-range><alpha>.list>>.Str;
my @range = @num[0] ... @num[1];
my $steps = ( $match<range><alpha-range><num> // 1 ).abs;
@range.batch($steps)>>.[0];
}
sub list( $match )
{
say "-LIST-";
$match<list><list-element>.list>>.Str;
}
sub brace-expand( $str )
{
say "brace-expand( $str )";
my $match = BraceExpansion.parse( $str );
my @alternatives =
$match<range><num-range> ?? num-range( $match ) !!
$match<range><alpha-range> ?? alpha-range( $match ) !!
$match<list> ?? list( $match ) !!
();
say "A", @alternatives;
return $str
unless @alternatives;
@alternatives
.map( -> $element { $match<start-txt>.Str ~ $element ~ $match<end-txt>.Str } )
.map( -> $result { brace-expand( $result ) } )
;
}
Однако, если я изменю правило TOP на
regex TOP { <start-txt> <range> <end-txt> }
или
regex TOP { <start-txt> <list> <end-txt> }
range
и list
токены работают независимо, и я получаю ожидаемый результат. Но когда я использую правило to-expand
, вся грамматика не совпадает, и я не могу понять, почему. Это изменение не так? Но если так, то почему тогда <alpha-range> | <num-range>
работает?
.... (проходит время) ....
Тем временем я узнал, что
regex TOP { <start-txt> [ <range> | <list> ] <end-txt> }
делает то, что я хочу. Но мой вопрос остается в силе, почему он не работает, как указано выше?