Saturday, November 27, 2010

"#39861: Switch module doesn't like subroutine prototypes" part 2

Spent some time playing with perl Switch bug.

Well, let's start from the begging.
The sort of main parsing routine in Switch.pm is
sub filter_blocks, which tries to parse $source and create $text.

failter_blocks calls Text::Balanced::_match_* to distinguish code blocks
from quoted, to validate variables, etc... and that's the point where the
whole thing hits the fan. Text::Balanced::_match_variable call is too
early here, since _match_variable validates $#, $$, $^ and fails to
validate $). In other words, suppose, we are parsing

sub foo($) {
        switch($_[0]) {
                case /ACK/i {
                        return "ACK";
                }                   
                case /NACK/i {
                        return "NACK";
                }                    
        }       
}



Text::Balanced::_match_variable will return the whole block, since
it doesn't know what to do with $). Yet it works for $$, $,, etc. quite
well. My first solution was change

m{\G\$\s*(?!::)(\d+|[][&`'+*./|,";%=~:?!\@<>()-]|\^[a-z]?)}gci)

to

m{\G\$\)\?\s*(?!::)(\d+|[][&`'+*./|,";%=~:?!\@<>()-]|\^[a-z]?)}gci)


so, we now parse $) correctly. However, I didn't like it much.

What we (IMHO) really should do - is to teach filter_blocks what
subroutine is. I did very simple and general (which may fail for 
some sophisticated cases) thing:
       
diff --git a/Switch.pm b/Switch.pm
index 2189ae0..781bae8 100755
--- a/Switch.pm
+++ b/Switch.pm
@@ -111,6 +111,11 @@ sub filter_blocks
             }
             next component;
         }
+        if ($source =~ m/\G(\s*sub.+)\{/) {
+            $text .= $1;
+            pos $source += length($1);
+            next component;
+        }
         if ($source =~ m/(\G\s*$pod_or_DATA)/gc) {
             $text .= $1;
             next component;


which shifts position in currently parsed $source to avoid wrong
Text::Balanced::_match_variable call on subroutine declaration.

Of course, this is not tested at all, except for my simple script.
Just playing.

No comments:

Post a Comment