package Perl6::Placeholders;

use Filter::Simple;

my %giftwrap = (
	'sort' => sub {"{$_[0]\->(\$a,\$b)}"},
	'grep' => sub {"{$_[0]\->(\$_)}"},
	'map'  => sub {"{$_[0]\->(\$_)}"},
	'sub'  => sub {$_[0]},
	''     => sub {$_[0]},
);

use re 'eval';
our $code        = qr{ (?: [^{}]+ | \{ (??{ $code }) \} )* }x;
our $placeholder = qr{ (?: $code (?: (??{ $carvar }) $code ) )+ }x;
our $carvar      = qr{ (?: \$\w+ (?:
			(?:->)?  (?:\[$placeholder\]|\{$placeholder\}) )+
		       | \$\^\w+
		       )
		     }x;

FILTER_ONLY 
	executable => sub {
			s<(sub|sort|map|grep)?\s*(?=.*\$\^\w)\{($placeholder)\}> {
				my ($context,$code) = ($1||"",$2);
				my $vars = join ",", sort $code =~ m/(\$\^\w+)/g;
				my $decl = qq{my($vars)=\@_;};
				$decl = "" if $code =~ /\Q$decl/;
				$code = qq{ sub ($vars) {$decl $code } }; 
				$code =~ s/\$\^(\w+)/\$$1/g;
				"$context ". $giftwrap{$context}($code);
			}ge;
		},

__END__

=head1 NAME

Perl6::Placeholders - Perl 6 implicitly declared parameters for Perl 5

=head1 VERSION

This document describes version 0.05 of Perl6::Placeholders,
released May 29, 2002.

=head1 SYNOPSIS

	use Perl6::Placeholders;

	my $add = { $^a + $^b };	# Create a sub that adds its two args

	print $add->(1,2), "\n";	# Call it

	# Use as map, grep, and sort blocks
	print join ",", sort { $^y <=> $^x } 1..10;
	print join "\n", map { $^value**2 } 1..10;
	print join "\n", map { $data{$_-1}.$^value**2 } 1..10;
	print join "\n", grep { $data{$^value} } 1..10;

	my $div = { $^x / $^y };	# Create a HOF that divides its two args

	print $div->(1,2), "\n";	# Do a division


=head1 DESCRIPTION

The Perl6::Placeholders module lets you try out the new Perl 6 implicit 
parameter specification syntax in Perl 5.

Perl 6 reserves all variables of the form C<$^name> or C<@^name> or
C<%^name> as "placeholders" that can be used to turn regular
blocks into subroutine references.

Any block containing one or more such placeholders
is treated as a reference to a subroutine in which the
placeholders are replaced by the appropriate
number and sequence of arguments.

That is, the expression:

	# Perl 6 code
        $check = { $^a == $^b**2 * $^c or die $^err_msg }; 

is equivalent to:

	# Perl 6 code
        $check = sub ($a, $b, $c, $err_msg) {
            $a == $b**2 * $c or die $err_msg
        };

This could then be invoked:

	# Perl 6 code
        $check.($i,$j,$k,$msg);
        
It is also be possible to interpolate an argument list into a static
expression like so:

	# Perl 6 code
        { $^a == $^b**2 * $^c or die $^err_msg }.($i,$j,$k,$msg);


The placeholders are sorted UTF8-abetically before they are used
to create the subroutine's parameter list. Hence the following:

	# Perl 6 code
        @reverse_sorted = sort {$^b <=> $^a} @list;

works as expected. That is, it's equivalent to:

        @reverse_sorted = sort sub($a,$b){$b <=> $a}, @list;


=head2 Declaring placeheld closures in Perl 5

The Perl6::Placeholders module allows you to use (almost) the same 
syntax in Perl 5.

That is, the expression:

	# Perl 5 code
	use Perl6::Placeholders;

        $check = { $^a == $^b**2 * $^c or die $^err_msg }; 

is equivalent to:

	# Perl 5 code

        $check = sub ($a, $b, $c, $err_msg) {
	    my ($a, $b, $c, $err_msg) = @_;
            $a == $b**2 * $c or die $err_msg;
        };

This could then be invoked:

	# Perl 5 code
        $check->($i,$j,$k,$msg);
        
It is also be possible to interpolate an argument list into a static
expression like so:

	# Perl 5 code
	use Perl6::Placeholders;

        { $^a == $^b**2 * $^c or die $^err_msg }->($i,$j,$k,$msg);

Note that the placeholders are restricted to scalars (though a future
release may support array and hash parameters too).

The placeholders are sorted ASCIIbetically before they are used
to create the subroutine's parameter list. Hence the following:

	# Perl 5 code
	use Perl6::Placeholders;

        @reverse_sorted = sort {$^b <=> $^a} @list;

works as expected (even in earlier perls that don't support sub refs as sort
specifiers!)


=head1 DEPENDENCIES

The module is implemented using Filter::Simple
and requires that module to be installed. 

=head1 AUTHOR

Damian Conway (damian@conway.org)

=head1 BUGS

This module is not designed for serious implementation work.

It uses some relatively sophisticated heuristics to translate Perl 6
syntax back to Perl 5. It I<will> make mistakes if your code gets even
moderately tricky.

Nevertheless, bug reports are most welcome.

=head1 COPYRIGHT

Copyright (c) 2002, Damian Conway. All Rights Reserved.
This module is free software. It may be used, redistributed
and/or modified under the terms of the Perl Artistic License
  (see http://www.perl.com/perl/misc/Artistic.html)
