After finally having realised that perl really does't do nested subs (lamented here) I decided to take the next obvious step and write a module that gives the illusion of having nested subs
#!/usr/bin/perl package MySub; use strict; use Regexp::Common; my $brackets_re = $RE{balanced}{-parens => '{}'}; my $paren_re = $RE{balanced}{-parens => '()'}; my $sub_name_re = qr/[_a-zA-Z](?:\w+)?/; my $sub_match_re = qr/my\s+sub\s+($sub_name_re)\s*($brackets_re)\s*;?/x; # my sub foobar { "code" } # my # 'my' # \s+ # 1> space # sub # 'sub' # \s+ # 1> space # ($sub_name_re) # '$subname' # \s* # 0> space # ($brackets_re) # balanced {} # \s* # 0> space # ;? # optional ';' use Filter::Simple; my @subs; # FILTER_ONLY code => sub { FILTER { my $code = $_; study $code; while(my($subname, $subcode) = $code =~ /$sub_match_re/s) { push @subs, { subname => $subname, code => $subcode }; # 'my sub name {}' => 'my $name = sub {};' $code =~ s/$sub_match_re/my \$$1 = sub $2;\n/s; # '&name();' => '$name->();' $code =~ s/ &? # optional & $subname # '$subname' \s* # 0> whitespace ( # group $1 $paren_re # balanced parens )? # optional group $1 \s* # 0> whitespace ; # ';' /"\$$subname->" . ($1 || '()') . ';'/sex; } $_ = $code; }; qw(package activated);Although the code is a little rough, it seems to DWIM so far. I haven't done any extensive testing (note to self - learn how to use test suites) but I havent found any problems as of yet. Once it's tidyed up a bit, I might even stick it on CPAN depending on the peoples' need for such an extension.
broquaint out
use strict;
use warnings;
use MySub;
sub foo {
print "in foo()\n";
my $lv = "a lex var in foo()";
my sub bar {
print "\tin bar()\n";
print "\tgot args - @_\n";
print "\t\$lv is $lv\n";
my $bar_args = \@_;
my sub quux {
print "\t\tin quux()\n";
print "\t\tbar() args = @$bar_args\n";
}
quux();
}
&bar(qw(a bunch of args));
}
foo();
exit(0);
__output__
in foo()
in bar()
got args - a bunch of args
$lv is a lex var in foo()
in quux()
bar() args = a bunch of args