The solution becomes clear when one realizes that qr// regexes are nothing but strings (albiet special string), and that they are not interpolated until runtime. Consider:
my $inlinetag = do {
my $acc =
qr/(?> \{ (?: (?> \\. | [^\\{}]+ | (??{ $acc }) ) )*
+ \} )/x;
qr/ \{ (\w+): ( (?: (?> \\. | [^\\{}]+ | (??{ $acc }) ) )*
+) \} /x;
};
In this modified snippet, the $acc regex is constructed, and scoped lexically to the do block. Next, the unnamed regex is constructed. Note that both of these pass strict checking since $acc was created in the same block, and thus exists. Since the second regex was the last statement in the do block, it is returned, and is assigned to $inlinetag. I believe this is the behavior you expected.
So what is the problem? The problem is that when $inlinetag is expanded at runtime, $acc no longer exists since it went out of scope when the do block returned the unnamed regex and assigned it to $inlinetag. A potential solution is just to get rid of the do block:
my $acc =
qr/(?> \{ (?: (?> \\. | [^\\{}]+ | (??{ $acc }) ) )*
+ \} )/x;
my $inlinetag =
qr/ \{ (\w+): ( (?: (?> \\. | [^\\{}]+ | (??{ $acc }) ) )*
+) \} /x;
Or, if you're really worried about cluttering your namespace, you can do some closure magic:
my $inlinetag = sub {
my $acc =
qr/(?> \{ (?: (?> \\. | [^\\{}]+ | (??{ $acc }) ) )*
+ \} )/x;
qr/ \{ (\w+): ( (?: (?> \\. | [^\\{}]+ | (??{ $acc }) ) )*
+) \} /x;
};
However, you must now use it like this: qr/(??{$inlinetag->()}/ rather than like qr/$inlinetag/ with the first method.
|