Showing posts with label bug. Show all posts
Showing posts with label bug. Show all posts

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.

Friday, November 26, 2010

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

Recently I faced an unexpected perl5's behaviour.
This simple and valid code

#!/usr/bin/perl
use POSIX;
use strict;

use Switch;

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

1;

failed to execute due to
syntax error at ./test.pl line 8, near ") {"
syntax error at ./test.pl line 15, near "}"
Bareword "case" not allowed while "strict subs" in use at ./test.pl line 12.
Bareword "NACK" not allowed while "strict subs" in use at ./test.pl line 12.
Execution of ./test.pl aborted due to compilation errors.



If we change foo's prototype requirement to expect more than one scalar
parameters, or drop any requirements - everything will cure and work just
as expected. IOW, case with one scalar parameter is kind of special (read broken).

This turned out to be known problem (#39861, according to Perl5's bugzilla )...
Since around 2004. Only one thing remains to write  - WTF?