readline (i.e. <>), glob, readdir, or each.
p4raw-id: //depot/ansiperl@900
case OP_NULL:
if (k2 && k2->op_type == OP_READLINE
&& (k2->op_flags & OPf_STACKED)
- && (k1->op_type == OP_RV2SV || k1->op_type == OP_PADSV))
+ && ((k1->op_flags & OPf_WANT) == OPf_WANT_SCALAR))
warnop = k2->op_type;
break;
|| (expr->op_type == OP_NULL && expr->op_targ == OP_GLOB)) {
expr = newUNOP(OP_DEFINED, 0,
newASSIGNOP(0, newDEFSVOP(), 0, expr) );
+ } else if (expr->op_flags & OPf_KIDS) {
+ OP *k1 = ((UNOP*)expr)->op_first;
+ OP *k2 = (k1) ? k1->op_sibling : NULL;
+ switch (expr->op_type) {
+ case OP_NULL:
+ if (k2 && k2->op_type == OP_READLINE
+ && (k2->op_flags & OPf_STACKED)
+ && ((k1->op_flags & OPf_WANT) == OPf_WANT_SCALAR))
+ expr = newUNOP(OP_DEFINED, 0, expr);
+ break;
+
+ case OP_SASSIGN:
+ if (k1->op_type == OP_READDIR
+ || k1->op_type == OP_GLOB
+ || k1->op_type == OP_EACH)
+ expr = newUNOP(OP_DEFINED, 0, expr);
+ break;
+ }
}
- }
+ }
listop = append_elem(OP_LINESEQ, block, newOP(OP_UNSTACK, 0));
o = new_logop(OP_AND, 0, &expr, &listop);
|| (expr->op_type == OP_NULL && expr->op_targ == OP_GLOB))) {
expr = newUNOP(OP_DEFINED, 0,
newASSIGNOP(0, newDEFSVOP(), 0, expr) );
+ } else if (expr && (expr->op_flags & OPf_KIDS)) {
+ OP *k1 = ((UNOP*)expr)->op_first;
+ OP *k2 = (k1) ? k1->op_sibling : NULL;
+ switch (expr->op_type) {
+ case OP_NULL:
+ if (k2 && k2->op_type == OP_READLINE
+ && (k2->op_flags & OPf_STACKED)
+ && ((k1->op_flags & OPf_WANT) == OPf_WANT_SCALAR))
+ expr = newUNOP(OP_DEFINED, 0, expr);
+ break;
+
+ case OP_SASSIGN:
+ if (k1->op_type == OP_READDIR
+ || k1->op_type == OP_GLOB
+ || k1->op_type == OP_EACH)
+ expr = newUNOP(OP_DEFINED, 0, expr);
+ break;
+ }
}
+
if (!block)
block = newOP(OP_NULL, 0);
situation where an automatic assignment happens. I<If and ONLY if> the
input symbol is the only thing inside the conditional of a C<while> or
C<for(;;)> loop, the value is automatically assigned to the variable
-C<$_>. The assigned value is then tested to see if it is defined.
-(This may seem like an odd thing to you, but you'll use the construct
-in almost every Perl script you write.) Anyway, the following lines
-are equivalent to each other:
+C<$_>. In these loop constructs, the assigned value (whether assignment
+is automatic or explcit) is then tested to see if it is defined.
+The defined test avoids problems where line has a string value
+that would be treated as false by perl e.g. "" or "0" with no trailing
+newline. (This may seem like an odd thing to you, but you'll use the
+construct in almost every Perl script you write.) Anyway, the following
+lines are equivalent to each other:
while (defined($_ = <STDIN>)) { print; }
+ while ($_ = <STDIN>) { print; }
while (<STDIN>) { print; }
for (;<STDIN>;) { print; }
print while defined($_ = <STDIN>);
+ print while ($_ = <STDIN>);
print while <STDIN>;
+and this also behaves similarly, but avoids the use of $_ :
+
+ while (my $line = <STDIN>) { print $line }
+
+If you really mean such values to terminate the loop they should be
+tested for explcitly:
+
+ while (($_ = <STDIN>) ne '0') { ... }
+ while (<STDIN>) { last unless $_; ... }
+
+In other boolean contexts C<E<lt>I<filehandle>E<gt>> without explcit C<defined>
+test or comparison will solicit a warning if C<-w> is in effect.
+
The filehandles STDIN, STDOUT, and STDERR are predefined. (The
filehandles C<stdin>, C<stdout>, and C<stderr> will also work except in
packages, where they would be interpreted as local identifiers rather
... # code for each line
}
-The E<lt>E<gt> symbol will return FALSE only once. If you call it again after
-this it will assume you are processing another @ARGV list, and if you
-haven't set @ARGV, will input from STDIN.
+The E<lt>E<gt> symbol will return C<undef> for end-of-file only once.
+If you call it again after this it will assume you are processing another
+@ARGV list, and if you haven't set @ARGV, will input from STDIN.
If the string inside the angle brackets is a reference to a scalar
variable (e.g., E<lt>$fooE<gt>), then that variable contains the name of the
list. All values must be read before it will start over. In a list
context this isn't important, because you automatically get them all
anyway. In a scalar context, however, the operator returns the next value
-each time it is called, or a FALSE value if you've just run out. Again,
-FALSE is returned only once. So if you're expecting a single value from
-a glob, it is much better to say
+each time it is called, or a C<undef> value if you've just run out. As
+for filehandles an automatic C<defined> is generated when the glob
+occurs in the test part of a C<while> or C<for> - because legal glob returns
+(e.g. a file called F<0>) would otherwise terminate the loop.
+Again, C<undef> is returned only once. So if you're expecting a single value
+from a glob, it is much better to say
($file) = <blurch*>;
--- /dev/null
+#!./perl -w
+
+#
+# test auto defined() test insertion
+#
+
+BEGIN {
+ chdir 't' if -d 't';
+ @INC = '../lib';
+ $SIG{__WARN__} = sub { $warns++; warn $_[0] };
+ print "1..14\n";
+}
+
+print "not " if $warns;
+print "ok 1\n";
+
+open(FILE,">./0");
+print FILE "1\n";
+print FILE "0";
+close(FILE);
+
+open(FILE,"<./0");
+my $seen = 0;
+my $dummy;
+while (my $name = <FILE>)
+ {
+ $seen++ if $name eq '0';
+ }
+print "not " unless $seen;
+print "ok 2\n";
+
+seek(FILE,0,0);
+$seen = 0;
+my $line = '';
+do
+ {
+ $seen++ if $line eq '0';
+ } while ($line = <FILE>);
+
+print "not " unless $seen;
+print "ok 3\n";
+
+
+seek(FILE,0,0);
+$seen = 0;
+while (($seen ? $dummy : $name) = <FILE>)
+ {
+ $seen++ if $name eq '0';
+ }
+print "not " unless $seen;
+print "ok 4\n";
+
+seek(FILE,0,0);
+$seen = 0;
+my %where;
+while ($where{$seen} = <FILE>)
+ {
+ $seen++ if $where{$seen} eq '0';
+ }
+print "not " unless $seen;
+print "ok 5\n";
+
+opendir(DIR,'.');
+$seen = 0;
+while (my $name = readdir(DIR))
+ {
+ $seen++ if $name eq '0';
+ }
+print "not " unless $seen;
+print "ok 6\n";
+
+rewinddir(DIR);
+$seen = 0;
+$dummy = '';
+while (($seen ? $dummy : $name) = readdir(DIR))
+ {
+ $seen++ if $name eq '0';
+ }
+print "not " unless $seen;
+print "ok 7\n";
+
+rewinddir(DIR);
+$seen = 0;
+while ($where{$seen} = readdir(DIR))
+ {
+ $seen++ if $where{$seen} eq '0';
+ }
+print "not " unless $seen;
+print "ok 8\n";
+
+$seen = 0;
+while (my $name = glob('*'))
+ {
+ $seen++ if $name eq '0';
+ }
+print "not " unless $seen;
+print "ok 9\n";
+
+$seen = 0;
+$dummy = '';
+while (($seen ? $dummy : $name) = glob('*'))
+ {
+ $seen++ if $name eq '0';
+ }
+print "not " unless $seen;
+print "ok 10\n";
+
+$seen = 0;
+while ($where{$seen} = glob('*'))
+ {
+ $seen++ if $where{$seen} eq '0';
+ }
+print "not " unless $seen;
+print "ok 11\n";
+
+unlink("./0");
+
+my %hash = (0 => 1, 1 => 2);
+
+$seen = 0;
+while (my $name = each %hash)
+ {
+ $seen++ if $name eq '0';
+ }
+print "not " unless $seen;
+print "ok 12\n";
+
+$seen = 0;
+$dummy = '';
+while (($seen ? $dummy : $name) = each %hash)
+ {
+ $seen++ if $name eq '0';
+ }
+print "not " unless $seen;
+print "ok 13\n";
+
+$seen = 0;
+while ($where{$seen} = each %hash)
+ {
+ $seen++ if $where{$seen} eq '0';
+ }
+print "not " unless $seen;
+print "ok 14\n";
+