Correctly handle ?-> in encapsed strings

Followup upstream change.
This commit is contained in:
Nikita Popov 2020-09-19 15:47:14 +02:00
parent c3e20d9970
commit 8505acd151
4 changed files with 52 additions and 14 deletions

View File

@ -22,15 +22,35 @@ final class NullsafeTokenEmulator extends TokenEmulator
// the tokens array on the way // the tokens array on the way
$line = 1; $line = 1;
for ($i = 0, $c = count($tokens); $i < $c; ++$i) { for ($i = 0, $c = count($tokens); $i < $c; ++$i) {
if (isset($tokens[$i + 1])) { if ($tokens[$i] === '?' && isset($tokens[$i + 1]) && $tokens[$i + 1][0] === \T_OBJECT_OPERATOR) {
if ($tokens[$i] === '?' && $tokens[$i + 1][0] === \T_OBJECT_OPERATOR) { array_splice($tokens, $i, 2, [
array_splice($tokens, $i, 2, [ [\T_NULLSAFE_OBJECT_OPERATOR, '?->', $line]
[\T_NULLSAFE_OBJECT_OPERATOR, '?->', $line] ]);
]); $c--;
$c--; continue;
continue;
}
} }
// Handle ?-> inside encapsed string.
if ($tokens[$i][0] === \T_ENCAPSED_AND_WHITESPACE && isset($tokens[$i - 1])
&& $tokens[$i - 1][0] === \T_VARIABLE
&& preg_match('/^\?->([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)/', $tokens[$i][1], $matches)
) {
$replacement = [
[\T_NULLSAFE_OBJECT_OPERATOR, '?->', $line],
[\T_STRING, $matches[1], $line],
];
if (\strlen($matches[0]) !== \strlen($tokens[$i][1])) {
$replacement[] = [
\T_ENCAPSED_AND_WHITESPACE,
\substr($tokens[$i][1], \strlen($matches[0])),
$line
];
}
array_splice($tokens, $i, 1, $replacement);
$c += \count($replacement) - 1;
continue;
}
if (\is_array($tokens[$i])) { if (\is_array($tokens[$i])) {
$line += substr_count($tokens[$i][1], "\n"); $line += substr_count($tokens[$i][1], "\n");
} }

View File

@ -320,6 +320,22 @@ class EmulativeTest extends LexerTest
['7.4', 'match', [[Tokens::T_STRING, 'match']]], ['7.4', 'match', [[Tokens::T_STRING, 'match']]],
['7.4', 'fn', [[Tokens::T_FN, 'fn']]], ['7.4', 'fn', [[Tokens::T_FN, 'fn']]],
['7.3', 'fn', [[Tokens::T_STRING, 'fn']]], ['7.3', 'fn', [[Tokens::T_STRING, 'fn']]],
// Tested here to skip testLeaveStuffAloneInStrings.
['8.0', '"$foo?->bar"', [
[ord('"'), '"'],
[Tokens::T_VARIABLE, '$foo'],
[Tokens::T_NULLSAFE_OBJECT_OPERATOR, '?->'],
[Tokens::T_STRING, 'bar'],
[ord('"'), '"'],
]],
['8.0', '"$foo?->bar baz"', [
[ord('"'), '"'],
[Tokens::T_VARIABLE, '$foo'],
[Tokens::T_NULLSAFE_OBJECT_OPERATOR, '?->'],
[Tokens::T_STRING, 'bar'],
[Tokens::T_ENCAPSED_AND_WHITESPACE, ' baz'],
[ord('"'), '"'],
]],
]; ];
} }
} }

View File

@ -71,11 +71,13 @@ array(
4: Stmt_Expression( 4: Stmt_Expression(
expr: Scalar_Encapsed( expr: Scalar_Encapsed(
parts: array( parts: array(
0: Expr_Variable( 0: Expr_NullsafePropertyFetch(
name: a var: Expr_Variable(
) name: a
1: Scalar_EncapsedStringPart( )
value: ?->b name: Identifier(
name: b
)
) )
) )
) )

View File

@ -19,4 +19,4 @@ $a?->b($c)?->d;
$a?->b($c)(); $a?->b($c)();
new $a?->b(); new $a?->b();
"{$a?->b}"; "{$a?->b}";
"{$a}?->b"; "{$a?->b}";