Switch-Back
view release on metacpan or search on metacpan
lib/Switch/Back.pm view on Meta::CPAN
(?>(?&PerlPodSequence))
(?: (?>(?&PerlLabel)) (?&PerlOWSOrEND) )?+
(?>(?&PerlPodSequence))
(?> (?&PerlKeyword)
| (?&PerlSubroutineDeclaration)
| (?&PerlMethodDeclaration)
| (?&PerlUseStatement)
| (?&PerlPackageDeclaration)
| (?&PerlClassDeclaration)
| (?&PerlFieldDeclaration)
| (?&PerlControlBlock)
| (?&PerlFormat)
|
# POSTFIX when HAS TO BE REWRITTEN BEFORE OTHER POSTFIX MODIFIERS ARE MATCHED...
(?<MATCH>
(?<EXPR> (?>(?&PerlExpression)) (?>(?&PerlOWS)) )
(?= when \b )
(?<MOD> (?&PerlStatementModifier) (?>(?&PerlOWSOrEND)) )
(?<END> (?> ; | (?= \} | \z )) )
)
(?{ my $len = length($+{MATCH});
unshift @target_pos, {
expr => $+{EXPR},
mod => substr($+{MOD},4),
end => $+{END},
from => pos() - $len,
len => $len,
}
})
|
(?>(?&PerlExpression)) (?>(?&PerlOWS))
(?&PerlStatementModifier)?+ (?>(?&PerlOWSOrEND))
(?> ; | (?= \} | \z ))
| (?&PerlBlock)
| ;
)
| # A yada-yada...
\.\.\. (?>(?&PerlOWSOrEND))
(?> ; | (?= \} | \z ))
| # Just a label...
(?>(?&PerlLabel)) (?>(?&PerlOWSOrEND))
(?> ; | (?= \} | \z ))
| # Just an empty statement...
(?>(?&PerlOWS)) ;
)
)
)
$PPR::X::GRAMMAR
}xms;
# Replace each postfix "when"...
for my $pos (@target_pos) {
# Unique ID for the "when" (needed by continue())...
state $ID; $ID++;
# Convert postfix "when" to a postfix "if" (preserving Afterwhen info for continue())...
substr($BLOCK, $pos->{from}, $pos->{len})
= "BEGIN { \$^H{'Switch::Back/Afterwhenprev'} = \$^H{'Switch::Back/Afterwhen'};"
. " \$^H{'Switch::Back/Afterwhen'} = 'Afterpostfixwhen$ID'; }"
. "$pos->{expr}, break if " . _apply_when_magic($pos->{mod})
. ";Afterpostfixwhen$ID:"
. "BEGIN { \$^H{'Switch::Back/Afterwhen'} = \$^H{'Switch::Back/Afterwhenprev'}; }"
. $pos->{end};
}
return $BLOCK;
}
# Change the target expression of a "when" to implement all the magic behaviours...
sub _apply_when_magic ($EXPR) {
# Reduce the expression to what the compiler would see...
$EXPR = _simplify_expr($EXPR);
# Split on low-precedence or...
my @low_disj = grep { defined }
$EXPR =~ m{ ( (?>(?&PerlLowPrecedenceNotExpression))
(?:
(?>(?&PerlOWS)) and
(?>(?&PerlOWS)) (?&PerlLowPrecedenceNotExpression)
)*+
)
(?>(?&PerlOWS)) (?: or | \z ) (?>(?&PerlOWS))
(?(DEFINE)
(?<PerlCommaList>
(?>(?&PerlAssignment))
(?:
(?: (?>(?&PerlOWS)) (?>(?&PerlComma)) )++
(?>(?&PerlOWS)) (?>(?&PerlAssignment))
)*+
(?: (?>(?&PerlOWS)) (?>(?&PerlComma)) )*+
) # End of rule (?<PerlCommaList>)
)
$PPR::GRAMMAR }gxms;
# If expression is a low-precedence or, apply any appropriate magic...
if (@low_disj > 1) {
# If the left-most operand isn't smartmatchable, the expression as a whole isn't,
# so just return it...
my $low_lhs = shift @low_disj;
my $magic_lhs = _apply_low_conj_magic($low_lhs);
if ($low_lhs eq $magic_lhs) {
return $EXPR;
}
# Otherwise, every operand has magic applied to it...
else {
return join ' or ', $magic_lhs, map { _apply_low_conj_magic($_) } @low_disj;
}
}
# Otherwise, see if it's a low-precedence conjunction...
return _apply_low_conj_magic($EXPR);
}
sub _apply_low_conj_magic ($EXPR) {
# Split on low-precedence and...
my @low_conj = grep { defined }
$EXPR =~ m{ ( (?>(?&PerlLowPrecedenceNotExpression)) )
(?>(?&PerlOWS)) (?: and | \z ) (?>(?&PerlOWS))
( run in 0.553 second using v1.01-cache-2.11-cpan-5b529ec07f3 )