[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: 10-fyi-autom4te-trace-patterns.patch
From: |
Akim Demaille |
Subject: |
Re: 10-fyi-autom4te-trace-patterns.patch |
Date: |
10 Aug 2001 09:52:16 +0200 |
User-agent: |
Gnus/5.0808 (Gnus v5.8.8) XEmacs/21.4 (Academic Rigor) |
>>>>> "Russ" == Russ Allbery <address@hidden> writes:
Russ> You should be able to put the file you're loading with do into
Russ> another namespace with a package directive in the file... does
Russ> that not work for what you're trying to do?
Err, maybe :) Here is what I'm trying to do:
~/src/ace % cat /tmp/foo.pl nostromo 9:31
#! /usr/bin/perl
use Carp;
# source ($FILE)
# --------------
sub source
{
my ($file) = @_;
(my $return) = do "$file";
croak "$me: cannot parse $file: address@hidden" if $@;
croak "$me: cannot do $file: $!\n" if $!;
croak "$me: cannot run $file\n" unless $return;
}
sub try
{
my $bar = "You lose.";
source ('/tmp/bar1.pl');
print $bar, "\n";
source ('/tmp/bar2.pl');
print $bar, "\n";
}
system ('cat >/tmp/bar1.pl <<\EOF
$bar = "You win!";
EOF
');
system ('cat >/tmp/bar2.pl <<\EOF
package caller;
$bar = "You win!";
EOF
');
try;
~/src/ace % perl /tmp/foo.pl nostromo 9:31
You lose.
You lose.
~/src/ace % nostromo 9:31
(but again, it is my understanding this is prohibited for `my': if I
use `local $bar' both work. I want to know if there is a means to do
that with `my' vars).
Russ> The problem that you're having with chop (and well, first off,
Russ> you don't want to be using chop; you want to be using chomp
Russ> instead, which only removes newlines and is therefore safer than
Russ> chop which will remove the last character no matter what it is)
OK, thanks!
Russ> is that you're using it inside the code block of a map or grep,
Russ> so it *is* in a scalar context.
OK. What can I do to tell it its an array context?
Russ> What you actually want to do is chomp a list. And as it
Russ> happens, chomp can take a list as an argument. So instead just
Russ> write:
Russ> my @patterns = new IO::File ("$tmp/patterns")->getlines;
Russ> chomp @patterns;
Russ> and that will do exactly what you want.
Thanks! I had not realized.
Russ> Second, with these lines:
> my $forbidden = join ('|', grep { s/^forbid:// } @patterns) ||"^\$";
> my $allowed = join ('|', grep { s/^allow:// } @patterns) || "^\$";
Russ> remember that $_ inside the code block of a grep or map is an
Russ> *alias* for the corresponding element of the list. You're
Russ> assuming that grep makes a copy of @patterns and then applies
Russ> the code block to it, when what actually happens is that grep
Russ> iterates over @patterns and makes $_ an alias for each element
Russ> in turn. So the s/// pattern is affecting the original list.
Yes, I understood this. That's actually what the comment was saying:
# A potential bad bug is that the grep for $forbidden and $allowed
# *do modify @PATTERNS! So when $FORBIDDEN is computed, @PATTERNS
# still contains the forbidden patterns, but without the leading
# `forbid:'. So if some use forbids `allow:FOO', @ALLOW will receive
# `FOO', which is _bad_. But since `:' is not valid in macro names,
# this is science fiction.
Russ> What you want in this case so far as I can tell is to grap all
Russ> of the patterns in @patterns beginning with "forbid:" (or
Russ> "allow:") and store them in a variable, separated by |, with the
Russ> prefix removed. Try:
Russ> my $forbidden = join ('|', map { /^forbid:(.*)/ } @patterns) || "^\$";
Hm, I had not realized either I could use $1... Thanks!
Russ> This code is slightly more straightforward, IMO, if written as
Russ> three separate commands, but that approach will get it on one
Russ> line (which has other benefits for readability, so it's probably
Russ> a wash).
Yep, this is really what I meant to write.
Russ> What that's doing instead is using a pattern match to extract
Russ> the portion that you're interested in rather than a substitution
Russ> to remove the portion that you don't want, and then using the
Russ> behavior of m// in a list context to return the result of the
Russ> pattern match.
Aaaaaaah! Yet another thanks :)
Thanks a lot!
I have one last question. The documentation for map says:
map BLOCK LIST
map EXPR,LIST
[...] Evalu
ates BLOCK or EXPR in list context, so each ele
ment of LIST may produce zero, one, or more ele
ments in the returned value.
and I just don't know how to return 0 elements. I tried this, without
success:
~/src/ace % cat /tmp/map.pl nostromo 9:43
#! /usr/bin/perl -w
my @list = ('0: even', '1: odd', '2: even', '3: odd');
my @evens = map { $1 if m/(\d): even/ } @list;
my @odds = map { $1 if m/(\d): odd/ } @list;
print "Odds: ", join (',', @odds), "\n";
print "Evens: ", join (',', @evens), "\n";
~/src/ace % perl /tmp/map.pl nostromo 9:44
Odds: ,1,,3
Evens: 0,,2,
Clearly, I do return 1 element each time, empty though. So my
question is ``how to return 0 elements?´´.
Thanks, I really appreciate your help! Here is what I commit:
Index: ChangeLog
from Akim Demaille <address@hidden>
* bin/autom4te.in (&handle_output): Don't use `grep' with side
effects.
Suggested by Russ Allbery.
Index: bin/autom4te.in
===================================================================
RCS file: /cvs/autoconf/bin/autom4te.in,v
retrieving revision 1.24
diff -u -u -r1.24 autom4te.in
--- bin/autom4te.in 2001/08/09 10:27:40 1.24
+++ bin/autom4te.in 2001/08/10 07:47:31
@@ -552,26 +552,14 @@
verbose "creating $output";
# Load the forbidden/allowed patterns.
- #
- # I'm having fun with grep and map, but it's not extremely safe here...
- # First of all, I still don't understand why I can't use `map' for
- # instance to get @PATTERNS: `chop' thinks it's in a scalar context
- # and returns 1 instead of `$_' :(.
- #
- # A potential bad bug is that the grep for $forbidden and $allowed
- # *do modify @PATTERNS! So when $FORBIDDEN is computed, @PATTERNS
- # still contains the forbidden patterns, but without the leading
- # `forbid:'. So if some use forbids `allow:FOO', @ALLOW will receive
- # `FOO', which is _bad_. But since `:' is not valid in macro names,
- # this is science fiction.
- #
- # Still, if someone could teach me how to write this properly... --akim
handle_traces ($req, "$tmp/patterns",
('m4_pattern_forbid' => 'forbid:$1',
'm4_pattern_allow' => 'allow:$1'));
- my @patterns = grep { chop } new IO::File ("$tmp/patterns")->getlines;
- my $forbidden = join ('|', grep { s/^forbid:// } @patterns) || "^\$";
- my $allowed = join ('|', grep { s/^allow:// } @patterns) || "^\$";
+ my @patterns = new IO::File ("$tmp/patterns")->getlines;
+ chomp @patterns;
+ my $forbidden = join ('|', map { /^forbid:(.*)/ } @patterns) || "^\$";
+ my $allowed = join ('|', map { /^allow:(.*)/ } @patterns) || "^\$";
+
verbose "forbidden tokens: $forbidden";
verbose "allowed tokens: $allowed";