Somewhere between "use re 'eval'" and "no re 'eval'"
Say, you have a function, which takes a string, a pattern, and then matches the pattern to the string, but with a twist; a (fixed) code fragment is inserted:
sub example {
my ($str, $pattern) = @_;
$str =~ /$pattern(?{ 1; })/;
}
The code block here is trivial, because it's not about the content of the block, just about its existence.
The above doesn't work, because by default you cannot interpolate a string in a
pattern containing code blocks. So, you have to use re 'eval';
:
sub example {
my ($str, $pattern) = @_;
use re 'eval';
$str =~ /$pattern(?{ 1; })/;
}
Now, that works, but that works a bit too well for my liking - it would
now run code blocks if they are passed in using $pattern
. This
is not what I want. The following seems to fix that:
sub example {
my ($str, $pattern) = @_;
no re 'eval';
$pattern = qr /$pattern/;
use re 'eval';
$str =~ /$pattern(?{ 1; })/;
}
This dies if $pattern
contains a (?{ code })
block. Except
that it doesn't die when $pattern
is already a compiled pattern -
that's deemed safe. So, we need an additional stringification:
sub example {
my ($str, $pattern) = @_;
no re 'eval';
$pattern = "$pattern";
$pattern = qr /$pattern/;
use re 'eval';
$str =~ /$pattern(?{ 1; })/;
}
This does what I want it to do: run the code block, but die if $pattern contains a code block, regardless whether it's passed as a string or a compiled regexp.
But I wonder, is there a less cluncky way?
Not without going the Perl 6 way, i.e. letting the regexp engine see
$pattern
as a token (and leaving to fetch its value) rather than just the interpolated contents of$pattern
– so that the regexp compiler would know which part of the pattern is literal (and code blocks therefore allowed) and which is interpolated (and code blocks therefore forbidden).With the Perl 5 approach it could at least be simplified if instead of a
re
pragma this was controlled by regexp flags. Then again we have too many of them anyway.But as it is I see no better way.
You can move things around a bit in your example: since compiled patterns as deemed safe, you could compile your code block and then later just interpolate it, obviating the need for an explicit “
use re 'eval'
”. But you don’t gain a thing.