Warum denkt Perl, dass dies map EXPR, LIST
statt map BLOCK LIST
sein sollte?
Der entsprechende Abschnitt des Codes ist in toke.c
, Perl Lexer (die unten ist von Perl 5.22.0):
/* This hack serves to disambiguate a pair of curlies
* as being a block or an anon hash. Normally, expectation
* determines that, but in cases where we're not in a
* position to expect anything in particular (like inside
* eval"") we have to resolve the ambiguity. This code
* covers the case where the first term in the curlies is a
* quoted string. Most other cases need to be explicitly
* disambiguated by prepending a "+" before the opening
* curly in order to force resolution as an anon hash.
*
* XXX should probably propagate the outer expectation
* into eval"" to rely less on this hack, but that could
* potentially break current behavior of eval"".
* GSAR 97-07-21
*/
t = s;
if (*s == '\'' || *s == '"' || *s == '`') {
/* common case: get past first string, handling escapes */
for (t++; t < PL_bufend && *t != *s;)
if (*t++ == '\\')
t++;
t++;
}
else if (*s == 'q') {
if (++t < PL_bufend
&& (!isWORDCHAR(*t)
|| ((*t == 'q' || *t == 'x') && ++t < PL_bufend
&& !isWORDCHAR(*t))))
{
/* skip q//-like construct */
const char *tmps;
char open, close, term;
I32 brackets = 1;
while (t < PL_bufend && isSPACE(*t))
t++;
/* check for q => */
if (t+1 < PL_bufend && t[0] == '=' && t[1] == '>') {
OPERATOR(HASHBRACK);
}
term = *t;
open = term;
if (term && (tmps = strchr("([{<)]}>)]}>",term)))
term = tmps[5];
close = term;
if (open == close)
for (t++; t < PL_bufend; t++) {
if (*t == '\\' && t+1 < PL_bufend && open != '\\')
t++;
else if (*t == open)
break;
}
else {
for (t++; t < PL_bufend; t++) {
if (*t == '\\' && t+1 < PL_bufend)
t++;
else if (*t == close && --brackets <= 0)
break;
else if (*t == open)
brackets++;
}
}
t++;
}
else
/* skip plain q word */
while (t < PL_bufend && isWORDCHAR_lazy_if(t,UTF))
t += UTF8SKIP(t);
}
else if (isWORDCHAR_lazy_if(t,UTF)) {
t += UTF8SKIP(t);
while (t < PL_bufend && isWORDCHAR_lazy_if(t,UTF))
t += UTF8SKIP(t);
}
while (t < PL_bufend && isSPACE(*t))
t++;
/* if comma follows first term, call it an anon hash */
/* XXX it could be a comma expression with loop modifiers */
if (t < PL_bufend && ((*t == ',' && (*s == 'q' || !isLOWER(*s)))
|| (*t == '=' && t[1] == '>')))
OPERATOR(HASHBRACK);
if (PL_expect == XREF)
{
block_expectation:
/* If there is an opening brace or 'sub:', treat it
as a term to make ${{...}}{k} and &{sub:attr...}
dwim. Otherwise, treat it as a statement, so
map {no strict; ...} works.
*/
s = skipspace(s);
if (*s == '{') {
PL_expect = XTERM;
break;
}
if (strnEQ(s, "sub", 3)) {
d = s + 3;
d = skipspace(d);
if (*d == ':') {
PL_expect = XTERM;
break;
}
}
PL_expect = XSTATE;
}
else {
PL_lex_brackstack[PL_lex_brackets-1] = XSTATE;
PL_expect = XSTATE;
}
Erklärung
Wenn der erste Term nach der Eröffnung curly ist eine Zeichenfolge (durch '
, "
oder `
abgegrenzt) oder ein Bareword, das mit einem Großbuchstaben beginnt, und der folgende Ausdruck lautet ,
oder =>
wird das Lockige als Anfang eines anonymen Hashes behandelt (das ist OPERATOR(HASHBRACK);
).
Die anderen Fälle sind ein bisschen schwieriger für mich zu verstehen. Ich lief das folgende Programm durch gdb:
{ (x => 1) }
und endete in der letzten else
Block up:
else {
PL_lex_brackstack[PL_lex_brackets-1] = XSTATE;
PL_expect = XSTATE;
}
Es genügt zu sagen, der Ausführungspfad deutlich unterscheidet; Am Ende wird es als Block geparst.
Ich glaube nicht, dass dies ein Fehler ist, nur ein Beispiel für Perl "Raten falsch" zwischen "map BLOCK LIST" und "map EXPR, LIST", die gegen Ende von "perldoc -f map" dokumentiert ist ] (http://perldoc.perl.org/functions/map.html). Hoffentlich kann jemand genau erklären, warum Perl in einer Antwort den Weg für Ihre Beispiele rät. – ThisSuitIsBlackNot
@ThisSuitIsBlackNot Ja, es sieht so aus https://eval.in/390502 aber normalerweise 'map EXPR, LIST' benötigt' + 'vor EXPR. Ansonsten ist es ein BLOCK. –
@ Сухой27 nein, map EXPR benötigt normalerweise kein +. Perl rät normalerweise gut. Hier sieht es so aus, als würden Sie einen anonymen Hash erstellen, keinen Block. – ysth