Skip to content

Commit

Permalink
PHP 8.0 | Tokenizer/PHP: efficiency tweaks
Browse files Browse the repository at this point in the history
This PR contains two separate, small efficiency tweaks for the `match` expression retokenization.

1. The tokenizer was walking backwards in the `match` backfill, while it could have just used `$finalTokens[$lastNotEmptyToken]` to get the last non-empty token.
2. There was some redundancy in the tokens which were being checked for the token "before".
    For tokens like, `T_CLASS` and `T_CONST`, the next token after the `match` keyword could never be an open parenthesis, so they would already be marked as "not match".

Includes additional tests.
Additionally, when I initially started the work on backfilling `match` expressions, the nullsafe object operator had not yet been backfilled, so there was not test covering that case. Added now just to be on the safe side.

Note: all extra tests would already pass prior to this change. These are just extra safeguards.
  • Loading branch information
jrfnl committed Mar 25, 2021
1 parent 2bd19c2 commit b4ad1ad
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 26 deletions.
39 changes: 14 additions & 25 deletions src/Tokenizers/PHP.php
Original file line number Diff line number Diff line change
Expand Up @@ -1288,33 +1288,22 @@ protected function tokenize($string)
break;
}

// Next was an open parenthesis, now check what is before the match keyword.
for ($y = ($stackPtr - 1); $y >= 0; $y--) {
if (is_array($tokens[$y]) === true
&& isset(Util\Tokens::$emptyTokens[$tokens[$y][0]]) === true
) {
continue;
}
$notMatchContext = [
T_PAAMAYIM_NEKUDOTAYIM => true,
T_OBJECT_OPERATOR => true,
T_NULLSAFE_OBJECT_OPERATOR => true,
T_NS_SEPARATOR => true,
T_NEW => true,
T_FUNCTION => true,
];

if (is_array($tokens[$y]) === true
&& ($tokens[$y][0] === T_PAAMAYIM_NEKUDOTAYIM
|| $tokens[$y][0] === T_OBJECT_OPERATOR
|| $tokens[$y][0] === T_NS_SEPARATOR
|| $tokens[$y][0] === T_NEW
|| $tokens[$y][0] === T_FUNCTION
|| $tokens[$y][0] === T_CLASS
|| $tokens[$y][0] === T_INTERFACE
|| $tokens[$y][0] === T_TRAIT
|| $tokens[$y][0] === T_NAMESPACE
|| $tokens[$y][0] === T_CONST)
) {
// This is not a match expression.
break 2;
}
if (isset($notMatchContext[$finalTokens[$lastNotEmptyToken]['code']]) === true) {
// Also not a match expression.
break;
}

$isMatch = true;
break 2;
}//end for
$isMatch = true;
break;
}//end for

if ($isMatch === true && $token[0] === T_STRING) {
Expand Down
14 changes: 13 additions & 1 deletion tests/Core/Tokenizer/BackfillMatchTokenTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ $a = MyClass::Match[$a];
$a = $obj->match($param);

/* testNoMatchMethodCallUpper */
$a = $obj->MATCH()->chain($param);
$a = $obj??->MATCH()->chain($param);

/* testNoMatchPropertyAccess */
$a = $obj->match;
Expand Down Expand Up @@ -282,6 +282,18 @@ function match() {}
// Intentional fatal error. Match is now a reserved keyword.
namespace Match {}

/* testNoMatchExtendedClassDeclaration */
// Intentional fatal error. Match is now a reserved keyword.
class Foo extends Match {}

/* testNoMatchImplementedClassDeclaration */
// Intentional fatal error. Match is now a reserved keyword.
class Bar implements Match {}

/* testNoMatchInUseStatement */
// Intentional fatal error in PHP < 8. Match is now a reserved keyword.
use Match\me;

function brokenMatchNoCurlies($x) {
/* testNoMatchMissingCurlies */
// Intentional fatal error. New control structure is not supported without curly braces.
Expand Down
12 changes: 12 additions & 0 deletions tests/Core/Tokenizer/BackfillMatchTokenTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,18 @@ public function dataNotAMatchStructure()
'/* testNoMatchNamespaceDeclaration */',
'Match',
],
'class_extends_declaration' => [
'/* testNoMatchExtendedClassDeclaration */',
'Match',
],
'class_implements_declaration' => [
'/* testNoMatchImplementedClassDeclaration */',
'Match',
],
'use_statement' => [
'/* testNoMatchInUseStatement */',
'Match',
],
'unsupported_inline_control_structure' => ['/* testNoMatchMissingCurlies */'],
'unsupported_alternative_syntax' => ['/* testNoMatchAlternativeSyntax */'],
'live_coding' => ['/* testLiveCoding */'],
Expand Down

0 comments on commit b4ad1ad

Please sign in to comment.