Category: Source Filters
Author/Contact Info Brent Dax (brentdax1@earthlink.net)
Description: This module allows you to have named parameters (as in "parameters like every other fscking language on the planet", not "parameters using => notation") in subroutine prototypes, like this:

   sub foo($foo, CODE $bar, @baz, *@rest) {

If you've been following the Apocalypses and Exegesises, this will look oddly familiar, and there's a reason--it uses the same syntax as Perl 6.

Pod available by e-mail. This should be up in my CPAN account (BRENTDAX) fairly soon as Perl6-Parameters-0.01.zip. Requires Switch and Filter::Simple. 170 lines.

package Perl6::Parameters;

use 5.006;
use strict;
use warnings;
use Switch 'Perl6';        #given/when

our $VERSION = '0.01';

use Filter::Simple;

sub separate($);
sub makeproto(\@\@);
sub makepopstate(\@\@);

FILTER {
    while(/(sub\s+([\w:]+)\s*\(([^)]*\w.*?)\)\s*\{)/) {
        my($oldsubstate, $subname, $paramlist)=($1, $2, $3);
        my($substate);
        
        die "'is rw' is not implemented but is used in subroutine $sub
+name" if($oldsubstate =~ /is rw/);
        
        #build the new sub statement
        do {
            my($popstate, $proto);
            
            do {
                #separate the parameter list into 3 arrays
                my(@ret)=separate($paramlist);
                my(@seps)=@{$ret[0]}; my(@params)=@{$ret[1]}; my(@name
+s)=@{$ret[2]};

                #form the line-noise prototype
                ($proto, my(@symbols))=makeproto(@params, @seps);
                
                #form the population statements
                $popstate=makepopstate(@names, @symbols);
            };

            #now assemble the new sub statement
            $substate="sub $subname ($proto) {\n\t$popstate";
        };
        #$substate: DONE--contains the new sub statement

        #replace the old sub statement with the new one
        do {
            s/\Q$oldsubstate/$substate/;
        };
    }
    
    if(@_) {
        print STDERR $_ if($_[0] eq '-debug');
    }
};

sub separate($) {
    my($paramlist, @seps, @names, @params)=shift;
    my(@things);
    
    #split the param list on separators--but keep the separators aroun
+d
    @things=split /([,;])/, $paramlist;

    #separate the things into separators and parameters
    for(0..$#things) {
        if($_ % 2) {
            push @seps, $things[$_];
        }
        else {
            push @params, $things[$_];
        }
    }

    #form the names array
    push @names, (/([\$\@\%]\w+)$/)[0] for @params;
    
    return \@seps, \@params, \@names;
}

sub makeproto(\@\@) {
    my($params, $seps)=@_;
    my(@symbols, $proto);
    
    #first, we convert each parameter to the appropriate symbol
    for(@$params) {
        push @symbols, tosymbol($_);
    }
    
    #then we get rid of commas since they don't appear in line-noise p
+rototypes
    @$seps=map {$_ eq ',' ? "" : $_} @$seps;
    push @$seps, '';    #avoid warning
    
    #build the line-noise prototype
    $proto.="$symbols[$_]$seps->[$_]" for(0..$#symbols);
    
    return $proto, @symbols;
}

sub makepopstate(\@\@) {
    my(@names)=@{shift()};
    my(@symbols)=@{shift()};
    my($popstate);
        
    for(0..$#names) {
        given($symbols[$_]) {
            when '\@': {
                if($names[$_] =~ /\@/) {
                    #literal array--use it
                    $popstate .= "my($names[$_])=\@{shift()};\n";
                }
                else {
                    #array ref--just like a normal one
                    $popstate .= "my($names[$_])=shift;\n";
                }
            }
        
            when '\%': {
                if($names[$_] =~ m'%') {
                    #literal hash--use it
                    $popstate .= "my($names[$_])=\%{shift()};\n";
                }
                else {
                    #hash ref--just like a normal one
                    $popstate .= "my($names[$_])=shift;\n";
                }
            }
        
            when '@': {
                if($names[$_] ne '@_') {
                    $popstate .= "my($names[$_])=(\@_);\n";
                }
            }
        
            when '%': {
                if($names[$_] eq '%_') {
                    $popstate .= '(%_)=(@_);'
                }
                else {
                    $popstate .= "my($names[$_])=(\@_);\n"
                }
            }
        
            $popstate .= "my($names[$_])=shift;\n";
        }
    }

    return $popstate;
}



sub tosymbol {
    my $term=shift;
    $term =~ s/^\s+|\s+$//g;    #strip whitespace

    given($term) {
                when /^REF/   : { return '\.' }        #Proposed in p5
+p, but NYI
        when /^GLOB/  : { return '\*' }
        when /^CODE/  : { return '&'  }
        when /^HASH/  : { return '\%' }
        when /^ARRAY/ : { return '\@' }
                when /^REGEXP/: { return '/'  }        #Proposed in p5
+p, but NYI
        when /^SCALAR/: { return '\$' }
        when /^\*\@/  : { return '@'  }
        when /^\*\%/  : { return '%'  }
        when /^\@/    : { return '\@' }
        when /^\%/    : { return '\%' }
                        { return '$'  }
    }
}

1;
Replies are listed 'Best First'.
A reply falls below the community's threshold of quality. You may see it by logging in.