package Filter::Interpolate; use Filter::Simple; FILTER { my($trynext, $parencount, @code)=(0, 0, split //); for(@code) { $trynext=1, next if $_ eq '$'; if($trynext) { if($_ eq '(') { $parencount=1; $_='{\\scalar('; } $trynext=0; } elsif($parencount) { if($_ eq '(') { $parencount++; } elsif($_ eq ')') { $parencount--; $_=')}' unless $parencount; } } } $_=join '', @code; die "Filter::Interpolate: unbalanced parenthesis" if($parencount); ($trynext, $parencount, @code)=(0, 0, split //); for(@code) { $trynext=1, next if $_ eq '@'; if($trynext) { if($_ eq '(') { $parencount=1; $_='{['; } $trynext=0; } elsif($parencount) { if($_ eq '(') { $parencount++; } elsif($_ eq ')') { $parencount--; $_=']}' unless $parencount; } } } die "Filter::Interpolate: unbalanced parenthesis" if($parencount); $_=join '', @code; }; =head1 NAME Filter::Interpolate - Interpolated Function Calls =head1 SYNOPSIS use Filter::Interpolate; sub Foo { '1' } sub Bar { 1..5 } sub Baz { @_ } sub Context { wantarray ? 'list' : 'scalar' } print "Foo: $(Foo)\n"; #prints Foo: 1 print "Bar: @(Bar)\n"; #prints Bar: 1 2 3 4 5 print "Baz: $(Baz('a', 'b'))"; #prints Baz: b print "Baz: @(Baz('a', 'b'))"; #prints Baz: a b print "$(Context)"; #prints scalar print "@(Context)"; #prints list =head1 DESCRIPTION Filter::Interpolate allows you to interpolate function calls into strings. Because of Perl's contexts, Filter::Interpolate requires a sigil (a funny character--$ or @ in this case) to tell the function being called which context to use; thus, the syntax is C<$(>IC<)> for scalar context or C<@(>IC<)> for list context. (This syntax is expected to be used for the same thing in Perl 6, too.) Filter::Interpolate will work on both fuction and method calls. It will work on parenthesized calls c. It even works outside quotes, where it can be used to control context. (This may be the only way to get a list context in some cases, for example.) =head1 BUGS =over 4 =item * Filter::Interpolate doesn't really grok Perl that well, so it can't tell what you mean when you pass a parameter like C<')'>. (It won't have any trouble if you put the other type of parenthesis in front of it, however; the best way to code around this problem is probably something like C.) It can also get confused when a parameter is '(', making it eat your entire program looking for a closing parenthesis. I'm not sure how these problems could be fixed, but I'm looking into it. =item * As strange as it looks, the correct way to interpolate an expression like (Foo)[2] is @(Foo)[2]. This is a side effect of how the module works internally; I'll leave that as-is, since that's (probably) the way Perl 6 will be doing it anyway. =item * This code will look horrible if you try using B::Deparse on it. Y'see, when the module is used, your beautiful $(Foo) is butchered into ${\scalar(Foo)}. Your also-beautiful @(Foo) fares only a little better, becoming @{[Foo]}. (Yes, that's the at-brace-bracket hack.) Just don't try it--you won't be terribly happy with the output's appearance. =back =head1 AUTHOR Copyright (C) 2001 Brent Dax. 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). =cut