Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.93k stars 552 forks source link

map { "$_", 1} @array is syntax error #2872

Closed p5pRT closed 20 years ago

p5pRT commented 23 years ago

Migrated from rt.perl.org#4723 (status was 'resolved')

Searchable as RT4723$

p5pRT commented 23 years ago

From Bruce.Albrecht@fingerhut.com

Created by bruce.albrecht@fingerhut.com

I was trying to do   %hash = map { "\L$_"\, 1 } @​array but it appears that any construct of the form​:   map { "string"\, 1 } causes a syntax error. I have found a work around for this​:   map { ("\L$_"\, 1) } @​array

This is also broken in 5.005.03.

Perl Info ``` Flags: category=core severity=low Site configuration information for perl v5.6.0: Configured by w246 at Wed Mar 29 12:36:29 CST 2000. Summary of my perl5 (revision 5.0 version 6 subversion 0) configuration: Platform: osname=solaris, osvers=2.6, archname=sun4-solaris uname='sunos gf003e0 5.6 generic_105181-17 sun4u sparc sunw,ultra-2 ' config_args='' hint=recommended, useposix=true, d_sigaction=define usethreads=undef use5005threads=undef useithreads=undef usemultiplicity=undef useperlio=undef d_sfio=undef uselargefiles=define use64bitint=undef use64bitall=undef uselongdouble=undef usesocks=undef Compiler: cc='cc', optimize='-O', gccversion= cppflags='-I/usr/local/gnu/include' ccflags ='-I/usr/local/gnu/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64' stdchar='unsigned char', d_stdstdio=define, usevfork=false intsize=4, longsize=4, ptrsize=4, doublesize=8 d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16 ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8 alignbytes=8, usemymalloc=y, prototype=define Linker and Libraries: ld='cc', ldflags ='-L/usr/local/lib -L/usr/local/gnu/lib -L/usr/ccs/lib ' libpth=/usr/local/lib /usr/local/gnu/lib /lib /usr/lib /usr/ccs/lib libs=-lsocket -lnsl -lgdbm -ldl -lm -lc -lcrypt -lsec libc=/lib/libc.so, so=so, useshrplib=false, libperl=libperl.a Dynamic Linking: dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags=' ' cccdlflags='-KPIC', lddlflags='-G -L/usr/local/lib -L/usr/local/gnu/lib -L/usr/ccs/lib' Locally applied patches: @INC for perl v5.6.0: /usr/local/gnu/perl-5.6.0/lib/5.6.0/sun4-solaris /usr/local/gnu/perl-5.6.0/lib/5.6.0 /usr/local/gnu/perl-5.6.0/lib/site_perl/5.6.0/sun4-solaris /usr/local/gnu/perl-5.6.0/lib/site_perl/5.6.0 /usr/local/gnu/perl-5.6.0/lib/site_perl . Environment for perl v5.6.0: HOME=/home/02/w246 LANG (unset) LANGUAGE (unset) LD_LIBRARY_PATH=/usr/local/Harvest/lib:/usr/local/Harvest/FCP/Galaxy/lib:/opt/oracle/prodvers/lib:/usr/dt/lib:/usr/lib:/opt/oracle/prodvers/lib:/usr/local/dt/lib:/usr/openwin/lib:/opt/SUNWspro3.0.1/lib:/usr/local/TeleUSE3.1.1/lib:/usr/local/gnu/lib LOGDIR (unset) PATH=/usr/local/Harvest/bin:/usr/local/Harvest/FCP/Galaxy/bin:/opt/oracle/prodvers/bin:/bin:/usr/bin:.:/home/02/w246/bin:/usr/local/bin:/usr/openwin/bin/xview:/usr/openwin/bin:/usr/ccs/bin:/opt/SUNWspro3.0.1/bin:/opt/SUNWguide/bin:/usr/local/softool/macros:/usr/local/stage/utilities/wb/prod/bin:/usr/local/stage/utilities/wb/prod/scripts:/usr/local/stage/apps/ccs/scripts:/opt/SUNWmfwm/bin:/usr/local/TeleUSE3.1.1/bin:/opt/oracle/prodvers/bin:/usr/local/xrunner/bin:/usr/local/gnu/bin:/usr/local/perl5/bin:/usr/local/Harvest/bin:/usr/ucb PERL_BADLANG (unset) SHELL=/bin/ksh ```
p5pRT commented 23 years ago

From @tamias

On Fri\, Nov 17\, 2000 at 11​:01​:07AM -0600\, Bruce Albrecht wrote​:

I was trying to do %hash = map { "\L$_"\, 1 } @​array but it appears that any construct of the form​: map { "string"\, 1 } causes a syntax error. I have found a work around for this​: map { ("\L$_"\, 1) } @​array

Thank you for your report. This is actually a known issue.

With the advent of anonymous hash references\, Perl has to determine whether map { ... is the start of map BLOCK LIST\, or map EXPR\, LIST with an anonymous hash as the expression.

Because Perl doesn't look ahead to the closing brace\, it has to guess. If the opening brace is followed by a string and a comma\, Perl guesses that it is an anonymous hash. Perl then expects to find a comma after the closing brace\, and reports a syntax error if there isn't one.

One workaround is to use parens\, as you found. Another is to put a plus before the string.

Because the workarounds are so simple\, this bug does not have a high priority for being fixed.

Ronald

p5pRT commented 23 years ago

From [Unknown Contact. See original ticket]

Lightning flashed\, thunder crashed and Ronald J Kimball \<rjk@​linguist.dartmouth .edu> whispered​: On Fri\, Nov 17\, 2000 at 11​:01​:07AM -0600\, Bruce Albrecht wrote​:
> I was trying to do
> %hash = map { "\L$_"\, 1 } @​array
> but it appears that any construct of the form​:
> map { "string"\, 1 }
> causes a syntax error. I have found a work around for this​:
> map { ("\L$_"\, 1) } @​array
Thank you for your report. This is actually a known issue.

Another fix for this specific instance is to use lc($_) instead of "\L$_".

-spp

p5pRT commented 23 years ago

From @nwc10

On Fri\, Nov 17\, 2000 at 01​:27​:52PM -0500\, Stephen P. Potter wrote​:

Lightning flashed\, thunder crashed and Ronald J Kimball \<rjk@​linguist.dartmouth .edu> whispered​: On Fri\, Nov 17\, 2000 at 11​:01​:07AM -0600\, Bruce Albrecht wrote​:
> I was trying to do
> %hash = map { "\L$_"\, 1 } @​array
> but it appears that any construct of the form​:
> map { "string"\, 1 }
> causes a syntax error. I have found a work around for this​:
> map { ("\L$_"\, 1) } @​array
Thank you for your report. This is actually a known issue.

Another fix for this specific instance is to use lc($_) instead of "\L$_".

but currently it's not documented as a trap. maybe I went a bit over the top​:

*** pod/perlfunc.pod.orig Tue Nov 14 18​:56​:07 2000 --- pod/perlfunc.pod Fri Nov 17 20​:55​:37 2000 *************** *** 2483\,2488 **** --- 2483\,2511 ----   most cases. See also L\ for an array composed of those items of   the original list for which the BLOCK or EXPR evaluates to true.  
+ C\<{> starts both hash references and blocks\, so C\<map { ...> could be either + the start of map BLOCK LIST or map EXPR\, LIST. Because perl doesn't look + ahead for the closing C\<}> it has to take a guess at which its dealing with + based what it finds just after the C\<{>. Usually it gets it right\, but if it + doesn't it won't realize something is wrong until it gets to the C\<}> and + encounters the missing (or unexpected) comma. The syntax error will be + reported close to the C\<}> but you'll need to change something near the C\<{> + such as using a unary C\<+> to give perl some help​: + + %hash = map { "\L$_"\, 1 } @​array # perl guesses EXPR. wrong + %hash = map { +"\L$_"\, 1 } @​array # perl guesses BLOCK. right + %hash = map { ("\L$_"\, 1) } @​array # this also works + %hash = map { lc($_)\, 1 } @​array # as does this. + %hash = map +( lc($_)\, 1 )\, @​array # this is EXPR and works! +
+ %hash = map ( lc($_)\, 1 )\, @​array # evaluates to (1\, @​array) + + or to force an anon hash constructor use C\<+{> + + @​hashes = map +{ lc($_)\, 1 }\, @​array # EXPR\, so needs \, at end + + and you get list of anonymous hashes each with only 1 entry. +   =item mkdir FILENAME\,MASK  
  =item mkdir FILENAME

map(lc($_)\,1)\,@​foo versus map+(lc($_)\,1)\,@​foo starts to look like something for an obfuscated perl contest.

Nicholas Clark

p5pRT commented 23 years ago

From @jhi

On Fri\, Nov 17\, 2000 at 10​:10​:28PM +0000\, Nicholas Clark wrote​:

On Fri\, Nov 17\, 2000 at 01​:27​:52PM -0500\, Stephen P. Potter wrote​:

Lightning flashed\, thunder crashed and Ronald J Kimball \<rjk@​linguist.dartmouth .edu> whispered​: On Fri\, Nov 17\, 2000 at 11​:01​:07AM -0600\, Bruce Albrecht wrote​:
> I was trying to do
> %hash = map { "\L$_"\, 1 } @​array
> but it appears that any construct of the form​:
> map { "string"\, 1 }
> causes a syntax error. I have found a work around for this​:
> map { ("\L$_"\, 1) } @​array
Thank you for your report. This is actually a known issue.

Another fix for this specific instance is to use lc($_) instead of "\L$_".

but currently it's not documented as a trap. maybe I went a bit over the top​:

Applied\, thanks.

p5pRT commented 23 years ago

From @ysth

In article \20001117221028\.A88930@&#8203;plum\.flirble\.org\, Nicholas Clark \nick@&#8203;ccl4\.org wrote​:

+ C\<{> starts both hash references and blocks\, so C\<map { ...> could be either + the start of map BLOCK LIST or map EXPR\, LIST. Because perl doesn't look + ahead for the closing C\<}> it has to take a guess at which its dealing with + based what it finds just after the C\<{>. Usually it gets it right\, but if it + doesn't it won't realize something is wrong until it gets to the C\<}> and + encounters the missing (or unexpected) comma. The syntax error will be + reported close to the C\<}> but you'll need to change something near the C\<{> + such as using a unary C\<+> to give perl some help​: + + %hash = map { "\L$_"\, 1 } @​array # perl guesses EXPR. wrong + %hash = map { +"\L$_"\, 1 } @​array # perl guesses BLOCK. right + %hash = map { ("\L$_"\, 1) } @​array # this also works + %hash = map { lc($_)\, 1 } @​array # as does this. + %hash = map +( lc($_)\, 1 )\, @​array # this is EXPR and works!

You left out my favorite!

Inline Patch ```diff --- pod/perlfunc.pod.orig Sat Nov 18 22:49:02 2000 +++ pod/perlfunc.pod Sun Nov 19 12:11:24 2000 @@ -2495,7 +2495,8 @@ %hash = map { "\L$_", 1 } @array # perl guesses EXPR. wrong %hash = map { +"\L$_", 1 } @array # perl guesses BLOCK. right %hash = map { ("\L$_", 1) } @array # this also works - %hash = map { lc($_), 1 } @array # as does this. + %hash = map { lc($_), 1 } @array # as does this + %hash = map {; "\L$_", 1 } @array # and this. %hash = map +( lc($_), 1 ), @array # this is EXPR and works! %hash = map ( lc($_), 1 ), @array # evaluates to (1, @array) End of Patch. ```
p5pRT commented 23 years ago

From @nwc10

On Sun\, Nov 19\, 2000 at 12​:13​:57PM -0800\, Yitzchak Scott-Thoennes wrote​:

You left out my favorite!

--- pod/perlfunc.pod.orig Sat Nov 18 22​:49​:02 2000 +++ pod/perlfunc.pod Sun Nov 19 12​:11​:24 2000 @​@​ -2495\,7 +2495\,8 @​@​ %hash = map { "\L$_"\, 1 } @​array # perl guesses EXPR. wrong %hash = map { +"\L$_"\, 1 } @​array # perl guesses BLOCK. right %hash = map { ("\L$_"\, 1) } @​array # this also works - %hash = map { lc($_)\, 1 } @​array # as does this. + %hash = map { lc($_)\, 1 } @​array # as does this + %hash = map {; "\L$_"\, 1 } @​array # and this.

that's quite nifty :-)

 %hash = map \+\( lc\($\_\)\, 1 \)\, @&#8203;array  \# this is EXPR and works\!

I also verified (after inspecting the code in toke.c) that having a literal newline inside the "" string also makes it look not like-an-anon-hash (the sniffer code looks to pair the qq() and find a "\," or => all as lookahead in the current line. Embedded literal \n means the close of the q() isn't in the current buffer\, so the {} is treated as block. Interesting only in that it's actually a case of whitespace having syntactic significance (sort of. arguably characters in strings are not "whitespace" in the traditional sense).

Nicholas Clark