mirror of
https://github.com/nikic/PHP-Parser.git
synced 2025-07-16 11:56:33 +02:00
Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
1c13d05035 | |||
c7dc3ce552 | |||
9f6ad686a7 | |||
1899471f80 | |||
8505acd151 | |||
c3e20d9970 | |||
4c22c62783 | |||
f66a32e2df | |||
75abbbd2d4 | |||
39b046007d | |||
e3872b8906 | |||
4a40a84cf6 |
@ -35,7 +35,7 @@ matrix:
|
||||
- name: PHP 8.0 Code on PHP 7.0 Integration Tests
|
||||
php: 7.0
|
||||
script:
|
||||
- test_old/run-php-src.sh 8.0.0beta1
|
||||
- test_old/run-php-src.sh 8.0.0beta4
|
||||
allow_failures:
|
||||
- name: PHP 8.0 Code on PHP 7.0 Integration Tests
|
||||
fast_finish: true
|
||||
|
21
CHANGELOG.md
21
CHANGELOG.md
@ -1,8 +1,25 @@
|
||||
Version 4.9.2-dev
|
||||
-----------------
|
||||
Version 4.10.1-dev
|
||||
------------------
|
||||
|
||||
Nothing yet.
|
||||
|
||||
Version 4.10.0 (2020-09-19)
|
||||
---------------------------
|
||||
|
||||
### Added
|
||||
|
||||
* [PHP 8.0] Added support for attributes. These are represented using a new `AttributeGroup` node
|
||||
containing `Attribute` nodes. A new `attrGroups` subnode is available on all node types that
|
||||
support attributes, i.e. `Stmt\Class_`, `Stmt\Trait_`, `Stmt\Interface_`, `Stmt\Function_`,
|
||||
`Stmt\ClassMethod`, `Stmt\ClassConst`, `Stmt\Property`, `Expr\Closure`, `Expr\ArrowFunction` and
|
||||
`Param`.
|
||||
* [PHP 8.0] Added support for nullsafe properties inside interpolated strings, in line with an
|
||||
upstream change.
|
||||
|
||||
### Fixed
|
||||
|
||||
* Improved compatibility with other libraries that use forward compatibility defines for PHP tokens.
|
||||
|
||||
Version 4.9.1 (2020-08-30)
|
||||
--------------------------
|
||||
|
||||
|
@ -82,6 +82,31 @@ no_comma:
|
||||
optional_comma:
|
||||
/* empty */
|
||||
| ','
|
||||
;
|
||||
|
||||
attribute_decl:
|
||||
class_name { $$ = Node\Attribute[$1, []]; }
|
||||
| class_name argument_list { $$ = Node\Attribute[$1, $2]; }
|
||||
;
|
||||
|
||||
attribute_group:
|
||||
attribute_decl { init($1); }
|
||||
| attribute_group ',' attribute_decl { push($1, $3); }
|
||||
;
|
||||
|
||||
attribute:
|
||||
T_ATTRIBUTE attribute_group optional_comma ']' { $$ = Node\AttributeGroup[$2]; }
|
||||
;
|
||||
|
||||
attributes:
|
||||
attribute { init($1); }
|
||||
| attributes attribute { push($1, $2); }
|
||||
;
|
||||
|
||||
optional_attributes:
|
||||
/* empty */ { $$ = []; }
|
||||
| attributes { $$ = $1; }
|
||||
;
|
||||
|
||||
top_statement:
|
||||
statement { $$ = $1; }
|
||||
@ -317,18 +342,23 @@ block_or_error:
|
||||
|
||||
function_declaration_statement:
|
||||
T_FUNCTION optional_ref identifier '(' parameter_list ')' optional_return_type block_or_error
|
||||
{ $$ = Stmt\Function_[$3, ['byRef' => $2, 'params' => $5, 'returnType' => $7, 'stmts' => $8]]; }
|
||||
{ $$ = Stmt\Function_[$3, ['byRef' => $2, 'params' => $5, 'returnType' => $7, 'stmts' => $8, 'attrGroups' => []]]; }
|
||||
| attributes T_FUNCTION optional_ref identifier '(' parameter_list ')' optional_return_type block_or_error
|
||||
{ $$ = Stmt\Function_[$4, ['byRef' => $3, 'params' => $6, 'returnType' => $8, 'stmts' => $9, 'attrGroups' => $1]]; }
|
||||
;
|
||||
|
||||
class_declaration_statement:
|
||||
class_entry_type identifier extends_from implements_list '{' class_statement_list '}'
|
||||
{ $$ = Stmt\Class_[$2, ['type' => $1, 'extends' => $3, 'implements' => $4, 'stmts' => $6]];
|
||||
{ $$ = Stmt\Class_[$2, ['type' => $1, 'extends' => $3, 'implements' => $4, 'stmts' => $6, 'attrGroups' => []]];
|
||||
$this->checkClass($$, #2); }
|
||||
| T_INTERFACE identifier interface_extends_list '{' class_statement_list '}'
|
||||
{ $$ = Stmt\Interface_[$2, ['extends' => $3, 'stmts' => $5]];
|
||||
$this->checkInterface($$, #2); }
|
||||
| T_TRAIT identifier '{' class_statement_list '}'
|
||||
{ $$ = Stmt\Trait_[$2, ['stmts' => $4]]; }
|
||||
| attributes class_entry_type identifier extends_from implements_list '{' class_statement_list '}'
|
||||
{ $$ = Stmt\Class_[$3, ['type' => $2, 'extends' => $4, 'implements' => $5, 'stmts' => $7, 'attrGroups' => $1]];
|
||||
$this->checkClass($$, #3); }
|
||||
| optional_attributes T_INTERFACE identifier interface_extends_list '{' class_statement_list '}'
|
||||
{ $$ = Stmt\Interface_[$3, ['extends' => $4, 'stmts' => $6, 'attrGroups' => $1]];
|
||||
$this->checkInterface($$, #3); }
|
||||
| optional_attributes T_TRAIT identifier '{' class_statement_list '}'
|
||||
{ $$ = Stmt\Trait_[$3, ['stmts' => $5, 'attrGroups' => $1]]; }
|
||||
;
|
||||
|
||||
class_entry_type:
|
||||
@ -489,14 +519,14 @@ optional_visibility_modifier:
|
||||
;
|
||||
|
||||
parameter:
|
||||
optional_visibility_modifier optional_type_without_static optional_ref optional_ellipsis plain_variable
|
||||
{ $$ = new Node\Param($5, null, $2, $3, $4, attributes(), $1);
|
||||
optional_attributes optional_visibility_modifier optional_type_without_static optional_ref optional_ellipsis plain_variable
|
||||
{ $$ = new Node\Param($6, null, $3, $4, $5, attributes(), $2, $1);
|
||||
$this->checkParam($$); }
|
||||
| optional_visibility_modifier optional_type_without_static optional_ref optional_ellipsis plain_variable '=' expr
|
||||
{ $$ = new Node\Param($5, $7, $2, $3, $4, attributes(), $1);
|
||||
| optional_attributes optional_visibility_modifier optional_type_without_static optional_ref optional_ellipsis plain_variable '=' expr
|
||||
{ $$ = new Node\Param($6, $8, $3, $4, $5, attributes(), $2, $1);
|
||||
$this->checkParam($$); }
|
||||
| optional_visibility_modifier optional_type_without_static optional_ref optional_ellipsis error
|
||||
{ $$ = new Node\Param(Expr\Error[], null, $2, $3, $4, attributes(), $1); }
|
||||
| optional_attributes optional_visibility_modifier optional_type_without_static optional_ref optional_ellipsis error
|
||||
{ $$ = new Node\Param(Expr\Error[], null, $3, $4, $5, attributes(), $2, $1); }
|
||||
;
|
||||
|
||||
type_expr:
|
||||
@ -600,14 +630,15 @@ class_statement_list:
|
||||
;
|
||||
|
||||
class_statement:
|
||||
variable_modifiers optional_type_without_static property_declaration_list ';'
|
||||
{ $attrs = attributes();
|
||||
$$ = new Stmt\Property($1, $3, $attrs, $2); $this->checkProperty($$, #1); }
|
||||
| method_modifiers T_CONST class_const_list ';'
|
||||
{ $$ = Stmt\ClassConst[$3, $1]; $this->checkClassConst($$, #1); }
|
||||
| method_modifiers T_FUNCTION optional_ref identifier_ex '(' parameter_list ')' optional_return_type method_body
|
||||
{ $$ = Stmt\ClassMethod[$4, ['type' => $1, 'byRef' => $3, 'params' => $6, 'returnType' => $8, 'stmts' => $9]];
|
||||
$this->checkClassMethod($$, #1); }
|
||||
optional_attributes variable_modifiers optional_type_without_static property_declaration_list ';'
|
||||
{ $$ = new Stmt\Property($2, $4, attributes(), $3, $1);
|
||||
$this->checkProperty($$, #2); }
|
||||
| optional_attributes method_modifiers T_CONST class_const_list ';'
|
||||
{ $$ = new Stmt\ClassConst($4, $2, attributes(), $1);
|
||||
$this->checkClassConst($$, #2); }
|
||||
| optional_attributes method_modifiers T_FUNCTION optional_ref identifier_ex '(' parameter_list ')' optional_return_type method_body
|
||||
{ $$ = Stmt\ClassMethod[$5, ['type' => $2, 'byRef' => $4, 'params' => $7, 'returnType' => $9, 'stmts' => $10, 'attrGroups' => $1]];
|
||||
$this->checkClassMethod($$, #2); }
|
||||
| T_USE class_name_list trait_adaptations { $$ = Stmt\TraitUse[$2, $3]; }
|
||||
| error { $$ = null; /* will be skipped */ }
|
||||
;
|
||||
@ -802,21 +833,27 @@ expr:
|
||||
| T_THROW expr { $$ = Expr\Throw_[$2]; }
|
||||
|
||||
| T_FN optional_ref '(' parameter_list ')' optional_return_type T_DOUBLE_ARROW expr
|
||||
{ $$ = Expr\ArrowFunction[['static' => false, 'byRef' => $2, 'params' => $4, 'returnType' => $6, 'expr' => $8]]; }
|
||||
{ $$ = Expr\ArrowFunction[['static' => false, 'byRef' => $2, 'params' => $4, 'returnType' => $6, 'expr' => $8, 'attrGroups' => []]]; }
|
||||
| T_STATIC T_FN optional_ref '(' parameter_list ')' optional_return_type T_DOUBLE_ARROW expr
|
||||
{ $$ = Expr\ArrowFunction[['static' => true, 'byRef' => $3, 'params' => $5, 'returnType' => $7, 'expr' => $9]]; }
|
||||
{ $$ = Expr\ArrowFunction[['static' => true, 'byRef' => $3, 'params' => $5, 'returnType' => $7, 'expr' => $9, 'attrGroups' => []]]; }
|
||||
| T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type block_or_error
|
||||
{ $$ = Expr\Closure[['static' => false, 'byRef' => $2, 'params' => $4, 'uses' => $6, 'returnType' => $7, 'stmts' => $8, 'attrGroups' => []]]; }
|
||||
| T_STATIC T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type block_or_error
|
||||
{ $$ = Expr\Closure[['static' => true, 'byRef' => $3, 'params' => $5, 'uses' => $7, 'returnType' => $8, 'stmts' => $9, 'attrGroups' => []]]; }
|
||||
|
||||
| T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type
|
||||
block_or_error
|
||||
{ $$ = Expr\Closure[['static' => false, 'byRef' => $2, 'params' => $4, 'uses' => $6, 'returnType' => $7, 'stmts' => $8]]; }
|
||||
| T_STATIC T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type
|
||||
block_or_error
|
||||
{ $$ = Expr\Closure[['static' => true, 'byRef' => $3, 'params' => $5, 'uses' => $7, 'returnType' => $8, 'stmts' => $9]]; }
|
||||
| attributes T_FN optional_ref '(' parameter_list ')' optional_return_type T_DOUBLE_ARROW expr
|
||||
{ $$ = Expr\ArrowFunction[['static' => false, 'byRef' => $3, 'params' => $5, 'returnType' => $7, 'expr' => $9, 'attrGroups' => $1]]; }
|
||||
| attributes T_STATIC T_FN optional_ref '(' parameter_list ')' optional_return_type T_DOUBLE_ARROW expr
|
||||
{ $$ = Expr\ArrowFunction[['static' => true, 'byRef' => $4, 'params' => $6, 'returnType' => $8, 'expr' => $10, 'attrGroups' => $1]]; }
|
||||
| attributes T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type block_or_error
|
||||
{ $$ = Expr\Closure[['static' => false, 'byRef' => $3, 'params' => $5, 'uses' => $7, 'returnType' => $8, 'stmts' => $9, 'attrGroups' => $1]]; }
|
||||
| attributes T_STATIC T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type block_or_error
|
||||
{ $$ = Expr\Closure[['static' => true, 'byRef' => $4, 'params' => $6, 'uses' => $8, 'returnType' => $9, 'stmts' => $10, 'attrGroups' => $1]]; }
|
||||
;
|
||||
|
||||
anonymous_class:
|
||||
T_CLASS ctor_arguments extends_from implements_list '{' class_statement_list '}'
|
||||
{ $$ = array(Stmt\Class_[null, ['type' => 0, 'extends' => $3, 'implements' => $4, 'stmts' => $6]], $2);
|
||||
optional_attributes T_CLASS ctor_arguments extends_from implements_list '{' class_statement_list '}'
|
||||
{ $$ = array(Stmt\Class_[null, ['type' => 0, 'extends' => $4, 'implements' => $5, 'stmts' => $7, 'attrGroups' => $1]], $3);
|
||||
$this->checkClass($$[0], -1); }
|
||||
;
|
||||
|
||||
|
@ -117,28 +117,28 @@ function resolveMacros($code) {
|
||||
$matches['args']
|
||||
);
|
||||
|
||||
if ('attributes' == $name) {
|
||||
if ('attributes' === $name) {
|
||||
assertArgs(0, $args, $name);
|
||||
return '$this->startAttributeStack[#1] + $this->endAttributes';
|
||||
}
|
||||
|
||||
if ('stackAttributes' == $name) {
|
||||
if ('stackAttributes' === $name) {
|
||||
assertArgs(1, $args, $name);
|
||||
return '$this->startAttributeStack[' . $args[0] . ']'
|
||||
. ' + $this->endAttributeStack[' . $args[0] . ']';
|
||||
}
|
||||
|
||||
if ('init' == $name) {
|
||||
if ('init' === $name) {
|
||||
return '$$ = array(' . implode(', ', $args) . ')';
|
||||
}
|
||||
|
||||
if ('push' == $name) {
|
||||
if ('push' === $name) {
|
||||
assertArgs(2, $args, $name);
|
||||
|
||||
return $args[0] . '[] = ' . $args[1] . '; $$ = ' . $args[0];
|
||||
}
|
||||
|
||||
if ('pushNormalizing' == $name) {
|
||||
if ('pushNormalizing' === $name) {
|
||||
assertArgs(2, $args, $name);
|
||||
|
||||
return 'if (is_array(' . $args[1] . ')) { $$ = array_merge(' . $args[0] . ', ' . $args[1] . '); }'
|
||||
@ -151,20 +151,20 @@ function resolveMacros($code) {
|
||||
return 'is_array(' . $args[0] . ') ? ' . $args[0] . ' : array(' . $args[0] . ')';
|
||||
}
|
||||
|
||||
if ('parseVar' == $name) {
|
||||
if ('parseVar' === $name) {
|
||||
assertArgs(1, $args, $name);
|
||||
|
||||
return 'substr(' . $args[0] . ', 1)';
|
||||
}
|
||||
|
||||
if ('parseEncapsed' == $name) {
|
||||
if ('parseEncapsed' === $name) {
|
||||
assertArgs(3, $args, $name);
|
||||
|
||||
return 'foreach (' . $args[0] . ' as $s) { if ($s instanceof Node\Scalar\EncapsedStringPart) {'
|
||||
. ' $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, ' . $args[1] . ', ' . $args[2] . '); } }';
|
||||
}
|
||||
|
||||
if ('makeNop' == $name) {
|
||||
if ('makeNop' === $name) {
|
||||
assertArgs(3, $args, $name);
|
||||
|
||||
return '$startAttributes = ' . $args[1] . ';'
|
||||
@ -182,7 +182,7 @@ function resolveMacros($code) {
|
||||
. ' else { ' . $args[0] . ' = null; }';
|
||||
}
|
||||
|
||||
if ('strKind' == $name) {
|
||||
if ('strKind' === $name) {
|
||||
assertArgs(1, $args, $name);
|
||||
|
||||
return '(' . $args[0] . '[0] === "\'" || (' . $args[0] . '[1] === "\'" && '
|
||||
@ -190,7 +190,7 @@ function resolveMacros($code) {
|
||||
. '? Scalar\String_::KIND_SINGLE_QUOTED : Scalar\String_::KIND_DOUBLE_QUOTED)';
|
||||
}
|
||||
|
||||
if ('prependLeadingComments' == $name) {
|
||||
if ('prependLeadingComments' === $name) {
|
||||
assertArgs(1, $args, $name);
|
||||
|
||||
return '$attrs = $this->startAttributeStack[#1]; $stmts = ' . $args[0] . '; '
|
||||
|
@ -110,3 +110,4 @@
|
||||
%token T_NAME_FULLY_QUALIFIED
|
||||
%token T_NAME_QUALIFIED
|
||||
%token T_NAME_RELATIVE
|
||||
%token T_ATTRIBUTE
|
@ -17,6 +17,8 @@ use PhpParser\Node\Expr;
|
||||
*/
|
||||
class PrintableNewAnonClassNode extends Expr
|
||||
{
|
||||
/** @var Node\AttributeGroup[] PHP attribute groups */
|
||||
public $attrGroups;
|
||||
/** @var Node\Arg[] Arguments */
|
||||
public $args;
|
||||
/** @var null|Node\Name Name of extended class */
|
||||
@ -27,9 +29,11 @@ class PrintableNewAnonClassNode extends Expr
|
||||
public $stmts;
|
||||
|
||||
public function __construct(
|
||||
array $args, Node\Name $extends = null, array $implements, array $stmts, array $attributes
|
||||
array $attrGroups, array $args, Node\Name $extends = null, array $implements,
|
||||
array $stmts, array $attributes
|
||||
) {
|
||||
parent::__construct($attributes);
|
||||
$this->attrGroups = $attrGroups;
|
||||
$this->args = $args;
|
||||
$this->extends = $extends;
|
||||
$this->implements = $implements;
|
||||
@ -42,7 +46,7 @@ class PrintableNewAnonClassNode extends Expr
|
||||
// We don't assert that $class->name is null here, to allow consumers to assign unique names
|
||||
// to anonymous classes for their own purposes. We simplify ignore the name here.
|
||||
return new self(
|
||||
$newNode->args, $class->extends, $class->implements,
|
||||
$class->attrGroups, $newNode->args, $class->extends, $class->implements,
|
||||
$class->stmts, $newNode->getAttributes()
|
||||
);
|
||||
}
|
||||
@ -52,6 +56,6 @@ class PrintableNewAnonClassNode extends Expr
|
||||
}
|
||||
|
||||
public function getSubNodeNames() : array {
|
||||
return ['args', 'extends', 'implements', 'stmts'];
|
||||
return ['attrGroups', 'args', 'extends', 'implements', 'stmts'];
|
||||
}
|
||||
}
|
||||
|
@ -405,35 +405,60 @@ class Lexer
|
||||
}
|
||||
|
||||
private function defineCompatibilityTokens() {
|
||||
// PHP 7.4
|
||||
if (!defined('T_BAD_CHARACTER')) {
|
||||
\define('T_BAD_CHARACTER', -1);
|
||||
}
|
||||
if (!defined('T_FN')) {
|
||||
\define('T_FN', -2);
|
||||
}
|
||||
if (!defined('T_COALESCE_EQUAL')) {
|
||||
\define('T_COALESCE_EQUAL', -3);
|
||||
static $compatTokensDefined = false;
|
||||
if ($compatTokensDefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
$compatTokens = [
|
||||
// PHP 7.4
|
||||
'T_BAD_CHARACTER',
|
||||
'T_FN',
|
||||
'T_COALESCE_EQUAL',
|
||||
// PHP 8.0
|
||||
if (!defined('T_NAME_QUALIFIED')) {
|
||||
\define('T_NAME_QUALIFIED', -4);
|
||||
'T_NAME_QUALIFIED',
|
||||
'T_NAME_FULLY_QUALIFIED',
|
||||
'T_NAME_RELATIVE',
|
||||
'T_MATCH',
|
||||
'T_NULLSAFE_OBJECT_OPERATOR',
|
||||
'T_ATTRIBUTE',
|
||||
];
|
||||
|
||||
// PHP-Parser might be used together with another library that also emulates some or all
|
||||
// of these tokens. Perform a sanity-check that all already defined tokens have been
|
||||
// assigned a unique ID.
|
||||
$usedTokenIds = [];
|
||||
foreach ($compatTokens as $token) {
|
||||
if (\defined($token)) {
|
||||
$tokenId = \constant($token);
|
||||
$clashingToken = $usedTokenIds[$tokenId] ?? null;
|
||||
if ($clashingToken !== null) {
|
||||
throw new \Error(sprintf(
|
||||
'Token %s has same ID as token %s, ' .
|
||||
'you may be using a library with broken token emulation',
|
||||
$token, $clashingToken
|
||||
));
|
||||
}
|
||||
if (!defined('T_NAME_FULLY_QUALIFIED')) {
|
||||
\define('T_NAME_FULLY_QUALIFIED', -5);
|
||||
$usedTokenIds[$token] = $tokenId;
|
||||
}
|
||||
if (!defined('T_NAME_RELATIVE')) {
|
||||
\define('T_NAME_RELATIVE', -6);
|
||||
}
|
||||
if (!defined('T_MATCH')) {
|
||||
\define('T_MATCH', -7);
|
||||
|
||||
// Now define any tokens that have not yet been emulated. Try to assign IDs from -1
|
||||
// downwards, but skip any IDs that may already be in use.
|
||||
$newTokenId = -1;
|
||||
foreach ($compatTokens as $token) {
|
||||
if (!\defined($token)) {
|
||||
while (isset($usedTokenIds[$newTokenId])) {
|
||||
$newTokenId--;
|
||||
}
|
||||
if (!defined('T_NULLSAFE_OBJECT_OPERATOR')) {
|
||||
\define('T_NULLSAFE_OBJECT_OPERATOR', -8);
|
||||
\define($token, $newTokenId);
|
||||
$newTokenId--;
|
||||
}
|
||||
}
|
||||
|
||||
$compatTokensDefined = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the token map.
|
||||
*
|
||||
@ -486,6 +511,7 @@ class Lexer
|
||||
$tokenMap[\T_NAME_RELATIVE] = Tokens::T_NAME_RELATIVE;
|
||||
$tokenMap[\T_MATCH] = Tokens::T_MATCH;
|
||||
$tokenMap[\T_NULLSAFE_OBJECT_OPERATOR] = Tokens::T_NULLSAFE_OBJECT_OPERATOR;
|
||||
$tokenMap[\T_ATTRIBUTE] = Tokens::T_ATTRIBUTE;
|
||||
|
||||
return $tokenMap;
|
||||
}
|
||||
|
@ -5,12 +5,15 @@ namespace PhpParser\Lexer;
|
||||
use PhpParser\Error;
|
||||
use PhpParser\ErrorHandler;
|
||||
use PhpParser\Lexer;
|
||||
use PhpParser\Lexer\TokenEmulator\AttributeEmulator;
|
||||
use PhpParser\Lexer\TokenEmulator\CoaleseEqualTokenEmulator;
|
||||
use PhpParser\Lexer\TokenEmulator\FlexibleDocStringEmulator;
|
||||
use PhpParser\Lexer\TokenEmulator\FnTokenEmulator;
|
||||
use PhpParser\Lexer\TokenEmulator\MatchTokenEmulator;
|
||||
use PhpParser\Lexer\TokenEmulator\NullsafeTokenEmulator;
|
||||
use PhpParser\Lexer\TokenEmulator\NumericLiteralSeparatorEmulator;
|
||||
use PhpParser\Lexer\TokenEmulator\TokenEmulatorInterface;
|
||||
use PhpParser\Lexer\TokenEmulator\ReverseEmulator;
|
||||
use PhpParser\Lexer\TokenEmulator\TokenEmulator;
|
||||
use PhpParser\Parser\Tokens;
|
||||
|
||||
class Emulative extends Lexer
|
||||
@ -19,17 +22,11 @@ class Emulative extends Lexer
|
||||
const PHP_7_4 = '7.4dev';
|
||||
const PHP_8_0 = '8.0dev';
|
||||
|
||||
const FLEXIBLE_DOC_STRING_REGEX = <<<'REGEX'
|
||||
/<<<[ \t]*(['"]?)([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)\1\r?\n
|
||||
(?:.*\r?\n)*?
|
||||
(?<indentation>\h*)\2(?![a-zA-Z0-9_\x80-\xff])(?<separator>(?:;?[\r\n])?)/x
|
||||
REGEX;
|
||||
|
||||
/** @var mixed[] Patches used to reverse changes introduced in the code */
|
||||
private $patches = [];
|
||||
|
||||
/** @var TokenEmulatorInterface[] */
|
||||
private $tokenEmulators = [];
|
||||
/** @var TokenEmulator[] */
|
||||
private $emulators = [];
|
||||
|
||||
/** @var string */
|
||||
private $targetPhpVersion;
|
||||
@ -46,27 +43,47 @@ REGEX;
|
||||
|
||||
parent::__construct($options);
|
||||
|
||||
$this->tokenEmulators[] = new FnTokenEmulator();
|
||||
$this->tokenEmulators[] = new MatchTokenEmulator();
|
||||
$this->tokenEmulators[] = new CoaleseEqualTokenEmulator();
|
||||
$this->tokenEmulators[] = new NumericLiteralSeparatorEmulator();
|
||||
$this->tokenEmulators[] = new NullsafeTokenEmulator();
|
||||
$emulators = [
|
||||
new FlexibleDocStringEmulator(),
|
||||
new FnTokenEmulator(),
|
||||
new MatchTokenEmulator(),
|
||||
new CoaleseEqualTokenEmulator(),
|
||||
new NumericLiteralSeparatorEmulator(),
|
||||
new NullsafeTokenEmulator(),
|
||||
new AttributeEmulator(),
|
||||
];
|
||||
|
||||
// Collect emulators that are relevant for the PHP version we're running
|
||||
// and the PHP version we're targeting for emulation.
|
||||
foreach ($emulators as $emulator) {
|
||||
$emulatorPhpVersion = $emulator->getPhpVersion();
|
||||
if ($this->isForwardEmulationNeeded($emulatorPhpVersion)) {
|
||||
$this->emulators[] = $emulator;
|
||||
} else if ($this->isReverseEmulationNeeded($emulatorPhpVersion)) {
|
||||
$this->emulators[] = new ReverseEmulator($emulator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function startLexing(string $code, ErrorHandler $errorHandler = null) {
|
||||
$this->patches = [];
|
||||
$emulators = array_filter($this->emulators, function($emulator) use($code) {
|
||||
return $emulator->isEmulationNeeded($code);
|
||||
});
|
||||
|
||||
if ($this->isEmulationNeeded($code) === false) {
|
||||
if (empty($emulators)) {
|
||||
// Nothing to emulate, yay
|
||||
parent::startLexing($code, $errorHandler);
|
||||
return;
|
||||
}
|
||||
|
||||
$collector = new ErrorHandler\Collecting();
|
||||
$this->patches = [];
|
||||
foreach ($emulators as $emulator) {
|
||||
$code = $emulator->preprocessCode($code, $this->patches);
|
||||
}
|
||||
|
||||
// 1. emulation of heredoc and nowdoc new syntax
|
||||
$preparedCode = $this->processHeredocNowdoc($code);
|
||||
parent::startLexing($preparedCode, $collector);
|
||||
$collector = new ErrorHandler\Collecting();
|
||||
parent::startLexing($code, $collector);
|
||||
$this->sortPatches();
|
||||
$this->fixupTokens();
|
||||
|
||||
$errors = $collector->getErrors();
|
||||
@ -77,84 +94,28 @@ REGEX;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->tokenEmulators as $tokenEmulator) {
|
||||
$emulatorPhpVersion = $tokenEmulator->getPhpVersion();
|
||||
if (version_compare(\PHP_VERSION, $emulatorPhpVersion, '<')
|
||||
&& version_compare($this->targetPhpVersion, $emulatorPhpVersion, '>=')
|
||||
&& $tokenEmulator->isEmulationNeeded($code)) {
|
||||
$this->tokens = $tokenEmulator->emulate($code, $this->tokens);
|
||||
} else if (version_compare(\PHP_VERSION, $emulatorPhpVersion, '>=')
|
||||
&& version_compare($this->targetPhpVersion, $emulatorPhpVersion, '<')
|
||||
&& $tokenEmulator->isEmulationNeeded($code)) {
|
||||
$this->tokens = $tokenEmulator->reverseEmulate($code, $this->tokens);
|
||||
}
|
||||
foreach ($emulators as $emulator) {
|
||||
$this->tokens = $emulator->emulate($code, $this->tokens);
|
||||
}
|
||||
}
|
||||
|
||||
private function isHeredocNowdocEmulationNeeded(string $code): bool
|
||||
private function isForwardEmulationNeeded(string $emulatorPhpVersion): bool {
|
||||
return version_compare(\PHP_VERSION, $emulatorPhpVersion, '<')
|
||||
&& version_compare($this->targetPhpVersion, $emulatorPhpVersion, '>=');
|
||||
}
|
||||
|
||||
private function isReverseEmulationNeeded(string $emulatorPhpVersion): bool {
|
||||
return version_compare(\PHP_VERSION, $emulatorPhpVersion, '>=')
|
||||
&& version_compare($this->targetPhpVersion, $emulatorPhpVersion, '<');
|
||||
}
|
||||
|
||||
private function sortPatches()
|
||||
{
|
||||
// skip version where this works without emulation
|
||||
if (version_compare(\PHP_VERSION, self::PHP_7_3, '>=')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return strpos($code, '<<<') !== false;
|
||||
}
|
||||
|
||||
private function processHeredocNowdoc(string $code): string
|
||||
{
|
||||
if ($this->isHeredocNowdocEmulationNeeded($code) === false) {
|
||||
return $code;
|
||||
}
|
||||
|
||||
if (!preg_match_all(self::FLEXIBLE_DOC_STRING_REGEX, $code, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE)) {
|
||||
// No heredoc/nowdoc found
|
||||
return $code;
|
||||
}
|
||||
|
||||
// Keep track of how much we need to adjust string offsets due to the modifications we
|
||||
// already made
|
||||
$posDelta = 0;
|
||||
foreach ($matches as $match) {
|
||||
$indentation = $match['indentation'][0];
|
||||
$indentationStart = $match['indentation'][1];
|
||||
|
||||
$separator = $match['separator'][0];
|
||||
$separatorStart = $match['separator'][1];
|
||||
|
||||
if ($indentation === '' && $separator !== '') {
|
||||
// Ordinary heredoc/nowdoc
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($indentation !== '') {
|
||||
// Remove indentation
|
||||
$indentationLen = strlen($indentation);
|
||||
$code = substr_replace($code, '', $indentationStart + $posDelta, $indentationLen);
|
||||
$this->patches[] = [$indentationStart + $posDelta, 'add', $indentation];
|
||||
$posDelta -= $indentationLen;
|
||||
}
|
||||
|
||||
if ($separator === '') {
|
||||
// Insert newline as separator
|
||||
$code = substr_replace($code, "\n", $separatorStart + $posDelta, 0);
|
||||
$this->patches[] = [$separatorStart + $posDelta, 'remove', "\n"];
|
||||
$posDelta += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
private function isEmulationNeeded(string $code): bool
|
||||
{
|
||||
foreach ($this->tokenEmulators as $emulativeToken) {
|
||||
if ($emulativeToken->isEmulationNeeded($code)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->isHeredocNowdocEmulationNeeded($code);
|
||||
// Patches may be contributed by different emulators.
|
||||
// Make sure they are sorted by increasing patch position.
|
||||
usort($this->patches, function($p1, $p2) {
|
||||
return $p1[0] <=> $p2[0];
|
||||
});
|
||||
}
|
||||
|
||||
private function fixupTokens()
|
||||
@ -173,7 +134,20 @@ REGEX;
|
||||
for ($i = 0, $c = \count($this->tokens); $i < $c; $i++) {
|
||||
$token = $this->tokens[$i];
|
||||
if (\is_string($token)) {
|
||||
// We assume that patches don't apply to string tokens
|
||||
if ($patchPos === $pos) {
|
||||
// Only support replacement for string tokens.
|
||||
assert($patchType === 'replace');
|
||||
$this->tokens[$i] = $patchText;
|
||||
|
||||
// Fetch the next patch
|
||||
$patchIdx++;
|
||||
if ($patchIdx >= \count($this->patches)) {
|
||||
// No more patches, we're done
|
||||
return;
|
||||
}
|
||||
list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx];
|
||||
}
|
||||
|
||||
$pos += \strlen($token);
|
||||
continue;
|
||||
}
|
||||
@ -201,6 +175,11 @@ REGEX;
|
||||
$token[1], $patchText, $patchPos - $pos + $posDelta, 0
|
||||
);
|
||||
$posDelta += $patchTextLen;
|
||||
} else if ($patchType === 'replace') {
|
||||
// Replace inside the token string
|
||||
$this->tokens[$i][1] = substr_replace(
|
||||
$token[1], $patchText, $patchPos - $pos + $posDelta, $patchTextLen
|
||||
);
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
@ -247,7 +226,7 @@ REGEX;
|
||||
if ($patchType === 'add') {
|
||||
$posDelta += strlen($patchText);
|
||||
$lineDelta += substr_count($patchText, "\n");
|
||||
} else {
|
||||
} else if ($patchType === 'remove') {
|
||||
$posDelta -= strlen($patchText);
|
||||
$lineDelta -= substr_count($patchText, "\n");
|
||||
}
|
||||
|
56
lib/PhpParser/Lexer/TokenEmulator/AttributeEmulator.php
Normal file
56
lib/PhpParser/Lexer/TokenEmulator/AttributeEmulator.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Lexer\TokenEmulator;
|
||||
|
||||
use PhpParser\Lexer\Emulative;
|
||||
|
||||
final class AttributeEmulator extends TokenEmulator
|
||||
{
|
||||
public function getPhpVersion(): string
|
||||
{
|
||||
return Emulative::PHP_8_0;
|
||||
}
|
||||
|
||||
public function isEmulationNeeded(string $code) : bool
|
||||
{
|
||||
return strpos($code, '#[') !== false;
|
||||
}
|
||||
|
||||
public function emulate(string $code, array $tokens): array
|
||||
{
|
||||
// We need to manually iterate and manage a count because we'll change
|
||||
// the tokens array on the way.
|
||||
$line = 1;
|
||||
for ($i = 0, $c = count($tokens); $i < $c; ++$i) {
|
||||
if ($tokens[$i] === '#' && isset($tokens[$i + 1]) && $tokens[$i + 1] === '[') {
|
||||
array_splice($tokens, $i, 2, [
|
||||
[\T_ATTRIBUTE, '#[', $line]
|
||||
]);
|
||||
$c--;
|
||||
continue;
|
||||
}
|
||||
if (\is_array($tokens[$i])) {
|
||||
$line += substr_count($tokens[$i][1], "\n");
|
||||
}
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
public function reverseEmulate(string $code, array $tokens): array
|
||||
{
|
||||
// TODO
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
public function preprocessCode(string $code, array &$patches): string {
|
||||
$pos = 0;
|
||||
while (false !== $pos = strpos($code, '#[', $pos)) {
|
||||
// Replace #[ with %[
|
||||
$code[$pos] = '%';
|
||||
$patches[] = [$pos, 'replace', '#'];
|
||||
$pos += 2;
|
||||
}
|
||||
return $code;
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ namespace PhpParser\Lexer\TokenEmulator;
|
||||
|
||||
use PhpParser\Lexer\Emulative;
|
||||
|
||||
final class CoaleseEqualTokenEmulator implements TokenEmulatorInterface
|
||||
final class CoaleseEqualTokenEmulator extends TokenEmulator
|
||||
{
|
||||
public function getPhpVersion(): string
|
||||
{
|
||||
|
@ -0,0 +1,76 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Lexer\TokenEmulator;
|
||||
|
||||
use PhpParser\Lexer\Emulative;
|
||||
|
||||
final class FlexibleDocStringEmulator extends TokenEmulator
|
||||
{
|
||||
const FLEXIBLE_DOC_STRING_REGEX = <<<'REGEX'
|
||||
/<<<[ \t]*(['"]?)([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)\1\r?\n
|
||||
(?:.*\r?\n)*?
|
||||
(?<indentation>\h*)\2(?![a-zA-Z0-9_\x80-\xff])(?<separator>(?:;?[\r\n])?)/x
|
||||
REGEX;
|
||||
|
||||
public function getPhpVersion(): string
|
||||
{
|
||||
return Emulative::PHP_7_3;
|
||||
}
|
||||
|
||||
public function isEmulationNeeded(string $code) : bool
|
||||
{
|
||||
return strpos($code, '<<<') !== false;
|
||||
}
|
||||
|
||||
public function emulate(string $code, array $tokens): array
|
||||
{
|
||||
// Handled by preprocessing + fixup.
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
public function reverseEmulate(string $code, array $tokens): array
|
||||
{
|
||||
// Not supported.
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
public function preprocessCode(string $code, array &$patches): string {
|
||||
if (!preg_match_all(self::FLEXIBLE_DOC_STRING_REGEX, $code, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE)) {
|
||||
// No heredoc/nowdoc found
|
||||
return $code;
|
||||
}
|
||||
|
||||
// Keep track of how much we need to adjust string offsets due to the modifications we
|
||||
// already made
|
||||
$posDelta = 0;
|
||||
foreach ($matches as $match) {
|
||||
$indentation = $match['indentation'][0];
|
||||
$indentationStart = $match['indentation'][1];
|
||||
|
||||
$separator = $match['separator'][0];
|
||||
$separatorStart = $match['separator'][1];
|
||||
|
||||
if ($indentation === '' && $separator !== '') {
|
||||
// Ordinary heredoc/nowdoc
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($indentation !== '') {
|
||||
// Remove indentation
|
||||
$indentationLen = strlen($indentation);
|
||||
$code = substr_replace($code, '', $indentationStart + $posDelta, $indentationLen);
|
||||
$patches[] = [$indentationStart + $posDelta, 'add', $indentation];
|
||||
$posDelta -= $indentationLen;
|
||||
}
|
||||
|
||||
if ($separator === '') {
|
||||
// Insert newline as separator
|
||||
$code = substr_replace($code, "\n", $separatorStart + $posDelta, 0);
|
||||
$patches[] = [$separatorStart + $posDelta, 'remove', "\n"];
|
||||
$posDelta += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace PhpParser\Lexer\TokenEmulator;
|
||||
|
||||
abstract class KeywordEmulator implements TokenEmulatorInterface
|
||||
abstract class KeywordEmulator extends TokenEmulator
|
||||
{
|
||||
abstract function getKeywordString(): string;
|
||||
abstract function getKeywordToken(): int;
|
||||
|
@ -4,7 +4,7 @@ namespace PhpParser\Lexer\TokenEmulator;
|
||||
|
||||
use PhpParser\Lexer\Emulative;
|
||||
|
||||
final class NullsafeTokenEmulator implements TokenEmulatorInterface
|
||||
final class NullsafeTokenEmulator extends TokenEmulator
|
||||
{
|
||||
public function getPhpVersion(): string
|
||||
{
|
||||
@ -22,15 +22,35 @@ final class NullsafeTokenEmulator implements TokenEmulatorInterface
|
||||
// the tokens array on the way
|
||||
$line = 1;
|
||||
for ($i = 0, $c = count($tokens); $i < $c; ++$i) {
|
||||
if (isset($tokens[$i + 1])) {
|
||||
if ($tokens[$i] === '?' && $tokens[$i + 1][0] === \T_OBJECT_OPERATOR) {
|
||||
if ($tokens[$i] === '?' && isset($tokens[$i + 1]) && $tokens[$i + 1][0] === \T_OBJECT_OPERATOR) {
|
||||
array_splice($tokens, $i, 2, [
|
||||
[\T_NULLSAFE_OBJECT_OPERATOR, '?->', $line]
|
||||
]);
|
||||
$c--;
|
||||
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])) {
|
||||
$line += substr_count($tokens[$i][1], "\n");
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ namespace PhpParser\Lexer\TokenEmulator;
|
||||
|
||||
use PhpParser\Lexer\Emulative;
|
||||
|
||||
final class NumericLiteralSeparatorEmulator implements TokenEmulatorInterface
|
||||
final class NumericLiteralSeparatorEmulator extends TokenEmulator
|
||||
{
|
||||
const BIN = '(?:0b[01]+(?:_[01]+)*)';
|
||||
const HEX = '(?:0x[0-9a-f]+(?:_[0-9a-f]+)*)';
|
||||
|
36
lib/PhpParser/Lexer/TokenEmulator/ReverseEmulator.php
Normal file
36
lib/PhpParser/Lexer/TokenEmulator/ReverseEmulator.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Lexer\TokenEmulator;
|
||||
|
||||
/**
|
||||
* Reverses emulation direction of the inner emulator.
|
||||
*/
|
||||
final class ReverseEmulator extends TokenEmulator
|
||||
{
|
||||
/** @var TokenEmulator Inner emulator */
|
||||
private $emulator;
|
||||
|
||||
public function __construct(TokenEmulator $emulator) {
|
||||
$this->emulator = $emulator;
|
||||
}
|
||||
|
||||
public function getPhpVersion(): string {
|
||||
return $this->emulator->getPhpVersion();
|
||||
}
|
||||
|
||||
public function isEmulationNeeded(string $code): bool {
|
||||
return $this->emulator->isEmulationNeeded($code);
|
||||
}
|
||||
|
||||
public function emulate(string $code, array $tokens): array {
|
||||
return $this->emulator->reverseEmulate($code, $tokens);
|
||||
}
|
||||
|
||||
public function reverseEmulate(string $code, array $tokens): array {
|
||||
return $this->emulator->emulate($code, $tokens);
|
||||
}
|
||||
|
||||
public function preprocessCode(string $code, array &$patches): string {
|
||||
return $code;
|
||||
}
|
||||
}
|
25
lib/PhpParser/Lexer/TokenEmulator/TokenEmulator.php
Normal file
25
lib/PhpParser/Lexer/TokenEmulator/TokenEmulator.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Lexer\TokenEmulator;
|
||||
|
||||
/** @internal */
|
||||
abstract class TokenEmulator
|
||||
{
|
||||
abstract public function getPhpVersion(): string;
|
||||
|
||||
abstract public function isEmulationNeeded(string $code): bool;
|
||||
|
||||
/**
|
||||
* @return array Modified Tokens
|
||||
*/
|
||||
abstract public function emulate(string $code, array $tokens): array;
|
||||
|
||||
/**
|
||||
* @return array Modified Tokens
|
||||
*/
|
||||
abstract public function reverseEmulate(string $code, array $tokens): array;
|
||||
|
||||
public function preprocessCode(string $code, array &$patches): string {
|
||||
return $code;
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Lexer\TokenEmulator;
|
||||
|
||||
/** @internal */
|
||||
interface TokenEmulatorInterface
|
||||
{
|
||||
public function getPhpVersion(): string;
|
||||
|
||||
public function isEmulationNeeded(string $code): bool;
|
||||
|
||||
/**
|
||||
* @return array Modified Tokens
|
||||
*/
|
||||
public function emulate(string $code, array $tokens): array;
|
||||
|
||||
/**
|
||||
* @return array Modified Tokens
|
||||
*/
|
||||
public function reverseEmulate(string $code, array $tokens): array;
|
||||
}
|
34
lib/PhpParser/Node/Attribute.php
Normal file
34
lib/PhpParser/Node/Attribute.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Node;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\NodeAbstract;
|
||||
|
||||
class Attribute extends NodeAbstract
|
||||
{
|
||||
/** @var Name Attribute name */
|
||||
public $name;
|
||||
|
||||
/** @var Arg[] Attribute arguments */
|
||||
public $args;
|
||||
|
||||
/**
|
||||
* @param Node\Name $name Attribute name
|
||||
* @param Arg[] $args Attribute arguments
|
||||
* @param array $attributes Additional node attributes
|
||||
*/
|
||||
public function __construct(Name $name, array $args = [], array $attributes = []) {
|
||||
$this->attributes = $attributes;
|
||||
$this->name = $name;
|
||||
$this->args = $args;
|
||||
}
|
||||
|
||||
public function getSubNodeNames() : array {
|
||||
return ['name', 'args'];
|
||||
}
|
||||
|
||||
public function getType() : string {
|
||||
return 'Attribute';
|
||||
}
|
||||
}
|
29
lib/PhpParser/Node/AttributeGroup.php
Normal file
29
lib/PhpParser/Node/AttributeGroup.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Node;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\NodeAbstract;
|
||||
|
||||
class AttributeGroup extends NodeAbstract
|
||||
{
|
||||
/** @var Attribute[] Attributes */
|
||||
public $attrs;
|
||||
|
||||
/**
|
||||
* @param Attribute[] $attrs PHP attributes
|
||||
* @param array $attributes Additional node attributes
|
||||
*/
|
||||
public function __construct(array $attrs, array $attributes = []) {
|
||||
$this->attributes = $attributes;
|
||||
$this->attrs = $attrs;
|
||||
}
|
||||
|
||||
public function getSubNodeNames() : array {
|
||||
return ['attrs'];
|
||||
}
|
||||
|
||||
public function getType() : string {
|
||||
return 'AttributeGroup';
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ namespace PhpParser\Node;
|
||||
use PhpParser\NodeAbstract;
|
||||
|
||||
/**
|
||||
* @property Name $namespacedName Namespaced name (for class constants, if using NameResolver)
|
||||
* @property Name $namespacedName Namespaced name (for global constants, if using NameResolver)
|
||||
*/
|
||||
class Const_ extends NodeAbstract
|
||||
{
|
||||
|
@ -22,6 +22,8 @@ class ArrowFunction extends Expr implements FunctionLike
|
||||
|
||||
/** @var Expr */
|
||||
public $expr;
|
||||
/** @var Node\AttributeGroup[] */
|
||||
public $attrGroups;
|
||||
|
||||
/**
|
||||
* @param array $subNodes Array of the following optional subnodes:
|
||||
@ -30,6 +32,7 @@ class ArrowFunction extends Expr implements FunctionLike
|
||||
* 'params' => array() : Parameters
|
||||
* 'returnType' => null : Return type
|
||||
* 'expr' => Expr : Expression body
|
||||
* 'attrGroups' => array() : PHP attribute groups
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(array $subNodes = [], array $attributes = []) {
|
||||
@ -40,10 +43,11 @@ class ArrowFunction extends Expr implements FunctionLike
|
||||
$returnType = $subNodes['returnType'] ?? null;
|
||||
$this->returnType = \is_string($returnType) ? new Node\Identifier($returnType) : $returnType;
|
||||
$this->expr = $subNodes['expr'] ?? null;
|
||||
$this->attrGroups = $subNodes['attrGroups'] ?? [];
|
||||
}
|
||||
|
||||
public function getSubNodeNames() : array {
|
||||
return ['static', 'byRef', 'params', 'returnType', 'expr'];
|
||||
return ['attrGroups', 'static', 'byRef', 'params', 'returnType', 'expr'];
|
||||
}
|
||||
|
||||
public function returnsByRef() : bool {
|
||||
@ -58,6 +62,10 @@ class ArrowFunction extends Expr implements FunctionLike
|
||||
return $this->returnType;
|
||||
}
|
||||
|
||||
public function getAttrGroups() : array {
|
||||
return $this->attrGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Node\Stmt\Return_[]
|
||||
*/
|
||||
|
@ -20,6 +20,8 @@ class Closure extends Expr implements FunctionLike
|
||||
public $returnType;
|
||||
/** @var Node\Stmt[] Statements */
|
||||
public $stmts;
|
||||
/** @var Node\AttributeGroup[] PHP attribute groups */
|
||||
public $attrGroups;
|
||||
|
||||
/**
|
||||
* Constructs a lambda function node.
|
||||
@ -31,6 +33,7 @@ class Closure extends Expr implements FunctionLike
|
||||
* 'uses' => array(): use()s
|
||||
* 'returnType' => null : Return type
|
||||
* 'stmts' => array(): Statements
|
||||
* 'attrGroups' => array(): PHP attributes groups
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(array $subNodes = [], array $attributes = []) {
|
||||
@ -42,10 +45,11 @@ class Closure extends Expr implements FunctionLike
|
||||
$returnType = $subNodes['returnType'] ?? null;
|
||||
$this->returnType = \is_string($returnType) ? new Node\Identifier($returnType) : $returnType;
|
||||
$this->stmts = $subNodes['stmts'] ?? [];
|
||||
$this->attrGroups = $subNodes['attrGroups'] ?? [];
|
||||
}
|
||||
|
||||
public function getSubNodeNames() : array {
|
||||
return ['static', 'byRef', 'params', 'uses', 'returnType', 'stmts'];
|
||||
return ['attrGroups', 'static', 'byRef', 'params', 'uses', 'returnType', 'stmts'];
|
||||
}
|
||||
|
||||
public function returnsByRef() : bool {
|
||||
@ -65,6 +69,10 @@ class Closure extends Expr implements FunctionLike
|
||||
return $this->stmts;
|
||||
}
|
||||
|
||||
public function getAttrGroups() : array {
|
||||
return $this->attrGroups;
|
||||
}
|
||||
|
||||
public function getType() : string {
|
||||
return 'Expr_Closure';
|
||||
}
|
||||
|
@ -16,21 +16,28 @@ interface FunctionLike extends Node
|
||||
/**
|
||||
* List of parameters
|
||||
*
|
||||
* @return Node\Param[]
|
||||
* @return Param[]
|
||||
*/
|
||||
public function getParams() : array;
|
||||
|
||||
/**
|
||||
* Get the declared return type or null
|
||||
*
|
||||
* @return null|Identifier|Node\Name|Node\NullableType|Node\UnionType
|
||||
* @return null|Identifier|Name|NullableType|UnionType
|
||||
*/
|
||||
public function getReturnType();
|
||||
|
||||
/**
|
||||
* The function body
|
||||
*
|
||||
* @return Node\Stmt[]|null
|
||||
* @return Stmt[]|null
|
||||
*/
|
||||
public function getStmts();
|
||||
|
||||
/**
|
||||
* Get PHP attribute groups.
|
||||
*
|
||||
* @return AttributeGroup[]
|
||||
*/
|
||||
public function getAttrGroups() : array;
|
||||
}
|
||||
|
@ -18,6 +18,8 @@ class Param extends NodeAbstract
|
||||
public $default;
|
||||
/** @var int */
|
||||
public $flags;
|
||||
/** @var AttributeGroup[] PHP attribute groups */
|
||||
public $attrGroups;
|
||||
|
||||
/**
|
||||
* Constructs a parameter node.
|
||||
@ -27,14 +29,16 @@ class Param extends NodeAbstract
|
||||
* @param null|string|Identifier|Name|NullableType|UnionType $type Type declaration
|
||||
* @param bool $byRef Whether is passed by reference
|
||||
* @param bool $variadic Whether this is a variadic argument
|
||||
* @param array $flags Optional visibility flags
|
||||
* @param array $attributes Additional attributes
|
||||
* @param int $flags Optional visibility flags
|
||||
* @param AttributeGroup[] $attrGroups PHP attribute groups
|
||||
*/
|
||||
public function __construct(
|
||||
$var, Expr $default = null, $type = null,
|
||||
bool $byRef = false, bool $variadic = false,
|
||||
array $attributes = [],
|
||||
int $flags = 0
|
||||
int $flags = 0,
|
||||
array $attrGroups = []
|
||||
) {
|
||||
$this->attributes = $attributes;
|
||||
$this->type = \is_string($type) ? new Identifier($type) : $type;
|
||||
@ -43,10 +47,11 @@ class Param extends NodeAbstract
|
||||
$this->var = $var;
|
||||
$this->default = $default;
|
||||
$this->flags = $flags;
|
||||
$this->attrGroups = $attrGroups;
|
||||
}
|
||||
|
||||
public function getSubNodeNames() : array {
|
||||
return ['flags', 'type', 'byRef', 'variadic', 'var', 'default'];
|
||||
return ['attrGroups', 'flags', 'type', 'byRef', 'variadic', 'var', 'default'];
|
||||
}
|
||||
|
||||
public function getType() : string {
|
||||
|
@ -10,6 +10,8 @@ class ClassConst extends Node\Stmt
|
||||
public $flags;
|
||||
/** @var Node\Const_[] Constant declarations */
|
||||
public $consts;
|
||||
/** @var Node\AttributeGroup[] */
|
||||
public $attrGroups;
|
||||
|
||||
/**
|
||||
* Constructs a class const list node.
|
||||
@ -17,15 +19,22 @@ class ClassConst extends Node\Stmt
|
||||
* @param Node\Const_[] $consts Constant declarations
|
||||
* @param int $flags Modifiers
|
||||
* @param array $attributes Additional attributes
|
||||
* @param Node\AttributeGroup[] $attrGroups PHP attribute groups
|
||||
*/
|
||||
public function __construct(array $consts, int $flags = 0, array $attributes = []) {
|
||||
public function __construct(
|
||||
array $consts,
|
||||
int $flags = 0,
|
||||
array $attributes = [],
|
||||
array $attrGroups = []
|
||||
) {
|
||||
$this->attributes = $attributes;
|
||||
$this->flags = $flags;
|
||||
$this->consts = $consts;
|
||||
$this->attrGroups = $attrGroups;
|
||||
}
|
||||
|
||||
public function getSubNodeNames() : array {
|
||||
return ['flags', 'consts'];
|
||||
return ['attrGroups', 'flags', 'consts'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -13,6 +13,8 @@ abstract class ClassLike extends Node\Stmt
|
||||
public $name;
|
||||
/** @var Node\Stmt[] Statements */
|
||||
public $stmts;
|
||||
/** @var Node\AttributeGroup[] PHP attribute groups */
|
||||
public $attrGroups;
|
||||
|
||||
/**
|
||||
* @return TraitUse[]
|
||||
|
@ -19,6 +19,8 @@ class ClassMethod extends Node\Stmt implements FunctionLike
|
||||
public $returnType;
|
||||
/** @var Node\Stmt[]|null Statements */
|
||||
public $stmts;
|
||||
/** @var Node\AttributeGroup[] PHP attribute groups */
|
||||
public $attrGroups;
|
||||
|
||||
private static $magicNames = [
|
||||
'__construct' => true,
|
||||
@ -48,6 +50,7 @@ class ClassMethod extends Node\Stmt implements FunctionLike
|
||||
* 'params' => array() : Parameters
|
||||
* 'returnType' => null : Return type
|
||||
* 'stmts' => array() : Statements
|
||||
* 'attrGroups' => array() : PHP attribute groups
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($name, array $subNodes = [], array $attributes = []) {
|
||||
@ -59,10 +62,11 @@ class ClassMethod extends Node\Stmt implements FunctionLike
|
||||
$returnType = $subNodes['returnType'] ?? null;
|
||||
$this->returnType = \is_string($returnType) ? new Node\Identifier($returnType) : $returnType;
|
||||
$this->stmts = array_key_exists('stmts', $subNodes) ? $subNodes['stmts'] : [];
|
||||
$this->attrGroups = $subNodes['attrGroups'] ?? [];
|
||||
}
|
||||
|
||||
public function getSubNodeNames() : array {
|
||||
return ['flags', 'byRef', 'name', 'params', 'returnType', 'stmts'];
|
||||
return ['attrGroups', 'flags', 'byRef', 'name', 'params', 'returnType', 'stmts'];
|
||||
}
|
||||
|
||||
public function returnsByRef() : bool {
|
||||
@ -81,6 +85,10 @@ class ClassMethod extends Node\Stmt implements FunctionLike
|
||||
return $this->stmts;
|
||||
}
|
||||
|
||||
public function getAttrGroups() : array {
|
||||
return $this->attrGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the method is explicitly or implicitly public.
|
||||
*
|
||||
|
@ -32,6 +32,7 @@ class Class_ extends ClassLike
|
||||
* 'extends' => null : Name of extended class
|
||||
* 'implements' => array(): Names of implemented interfaces
|
||||
* 'stmts' => array(): Statements
|
||||
* '$attrGroups' => array(): PHP attribute groups
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($name, array $subNodes = [], array $attributes = []) {
|
||||
@ -41,10 +42,11 @@ class Class_ extends ClassLike
|
||||
$this->extends = $subNodes['extends'] ?? null;
|
||||
$this->implements = $subNodes['implements'] ?? [];
|
||||
$this->stmts = $subNodes['stmts'] ?? [];
|
||||
$this->attrGroups = $subNodes['attrGroups'] ?? [];
|
||||
}
|
||||
|
||||
public function getSubNodeNames() : array {
|
||||
return ['flags', 'name', 'extends', 'implements', 'stmts'];
|
||||
return ['attrGroups', 'flags', 'name', 'extends', 'implements', 'stmts'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -20,6 +20,8 @@ class Function_ extends Node\Stmt implements FunctionLike
|
||||
public $returnType;
|
||||
/** @var Node\Stmt[] Statements */
|
||||
public $stmts;
|
||||
/** @var Node\AttributeGroup[] PHP attribute groups */
|
||||
public $attrGroups;
|
||||
|
||||
/**
|
||||
* Constructs a function node.
|
||||
@ -30,6 +32,7 @@ class Function_ extends Node\Stmt implements FunctionLike
|
||||
* 'params' => array(): Parameters
|
||||
* 'returnType' => null : Return type
|
||||
* 'stmts' => array(): Statements
|
||||
* 'attrGroups' => array(): PHP attribute groups
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($name, array $subNodes = [], array $attributes = []) {
|
||||
@ -40,10 +43,11 @@ class Function_ extends Node\Stmt implements FunctionLike
|
||||
$returnType = $subNodes['returnType'] ?? null;
|
||||
$this->returnType = \is_string($returnType) ? new Node\Identifier($returnType) : $returnType;
|
||||
$this->stmts = $subNodes['stmts'] ?? [];
|
||||
$this->attrGroups = $subNodes['attrGroups'] ?? [];
|
||||
}
|
||||
|
||||
public function getSubNodeNames() : array {
|
||||
return ['byRef', 'name', 'params', 'returnType', 'stmts'];
|
||||
return ['attrGroups', 'byRef', 'name', 'params', 'returnType', 'stmts'];
|
||||
}
|
||||
|
||||
public function returnsByRef() : bool {
|
||||
@ -58,6 +62,10 @@ class Function_ extends Node\Stmt implements FunctionLike
|
||||
return $this->returnType;
|
||||
}
|
||||
|
||||
public function getAttrGroups() : array {
|
||||
return $this->attrGroups;
|
||||
}
|
||||
|
||||
/** @return Node\Stmt[] */
|
||||
public function getStmts() : array {
|
||||
return $this->stmts;
|
||||
|
@ -16,6 +16,7 @@ class Interface_ extends ClassLike
|
||||
* @param array $subNodes Array of the following optional subnodes:
|
||||
* 'extends' => array(): Name of extended interfaces
|
||||
* 'stmts' => array(): Statements
|
||||
* 'attrGroups' => array(): PHP attribute groups
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($name, array $subNodes = [], array $attributes = []) {
|
||||
@ -23,10 +24,11 @@ class Interface_ extends ClassLike
|
||||
$this->name = \is_string($name) ? new Node\Identifier($name) : $name;
|
||||
$this->extends = $subNodes['extends'] ?? [];
|
||||
$this->stmts = $subNodes['stmts'] ?? [];
|
||||
$this->attrGroups = $subNodes['attrGroups'] ?? [];
|
||||
}
|
||||
|
||||
public function getSubNodeNames() : array {
|
||||
return ['name', 'extends', 'stmts'];
|
||||
return ['attrGroups', 'name', 'extends', 'stmts'];
|
||||
}
|
||||
|
||||
public function getType() : string {
|
||||
|
@ -16,6 +16,8 @@ class Property extends Node\Stmt
|
||||
public $props;
|
||||
/** @var null|Identifier|Name|NullableType|UnionType Type declaration */
|
||||
public $type;
|
||||
/** @var Node\AttributeGroup[] PHP attribute groups */
|
||||
public $attrGroups;
|
||||
|
||||
/**
|
||||
* Constructs a class property list node.
|
||||
@ -24,16 +26,18 @@ class Property extends Node\Stmt
|
||||
* @param PropertyProperty[] $props Properties
|
||||
* @param array $attributes Additional attributes
|
||||
* @param null|string|Identifier|Name|NullableType|UnionType $type Type declaration
|
||||
* @param Node\AttributeGroup[] $attrGroups PHP attribute groups
|
||||
*/
|
||||
public function __construct(int $flags, array $props, array $attributes = [], $type = null) {
|
||||
public function __construct(int $flags, array $props, array $attributes = [], $type = null, array $attrGroups = []) {
|
||||
$this->attributes = $attributes;
|
||||
$this->flags = $flags;
|
||||
$this->props = $props;
|
||||
$this->type = \is_string($type) ? new Identifier($type) : $type;
|
||||
$this->attrGroups = $attrGroups;
|
||||
}
|
||||
|
||||
public function getSubNodeNames() : array {
|
||||
return ['flags', 'type', 'props'];
|
||||
return ['attrGroups', 'flags', 'type', 'props'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -12,16 +12,18 @@ class Trait_ extends ClassLike
|
||||
* @param string|Node\Identifier $name Name
|
||||
* @param array $subNodes Array of the following optional subnodes:
|
||||
* 'stmts' => array(): Statements
|
||||
* 'attrGroups' => array(): PHP attribute groups
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($name, array $subNodes = [], array $attributes = []) {
|
||||
$this->attributes = $attributes;
|
||||
$this->name = \is_string($name) ? new Node\Identifier($name) : $name;
|
||||
$this->stmts = $subNodes['stmts'] ?? [];
|
||||
$this->attrGroups = $subNodes['attrGroups'] ?? [];
|
||||
}
|
||||
|
||||
public function getSubNodeNames() : array {
|
||||
return ['name', 'stmts'];
|
||||
return ['attrGroups', 'name', 'stmts'];
|
||||
}
|
||||
|
||||
public function getType() : string {
|
||||
|
@ -75,6 +75,7 @@ class NameResolver extends NodeVisitorAbstract
|
||||
$interface = $this->resolveClassName($interface);
|
||||
}
|
||||
|
||||
$this->resolveAttrGroups($node);
|
||||
if (null !== $node->name) {
|
||||
$this->addNamespacedName($node);
|
||||
}
|
||||
@ -83,25 +84,32 @@ class NameResolver extends NodeVisitorAbstract
|
||||
$interface = $this->resolveClassName($interface);
|
||||
}
|
||||
|
||||
$this->resolveAttrGroups($node);
|
||||
$this->addNamespacedName($node);
|
||||
} elseif ($node instanceof Stmt\Trait_) {
|
||||
$this->resolveAttrGroups($node);
|
||||
$this->addNamespacedName($node);
|
||||
} elseif ($node instanceof Stmt\Function_) {
|
||||
$this->addNamespacedName($node);
|
||||
$this->resolveSignature($node);
|
||||
$this->resolveAttrGroups($node);
|
||||
$this->addNamespacedName($node);
|
||||
} elseif ($node instanceof Stmt\ClassMethod
|
||||
|| $node instanceof Expr\Closure
|
||||
|| $node instanceof Expr\ArrowFunction
|
||||
) {
|
||||
$this->resolveSignature($node);
|
||||
$this->resolveAttrGroups($node);
|
||||
} elseif ($node instanceof Stmt\Property) {
|
||||
if (null !== $node->type) {
|
||||
$node->type = $this->resolveType($node->type);
|
||||
}
|
||||
$this->resolveAttrGroups($node);
|
||||
} elseif ($node instanceof Stmt\Const_) {
|
||||
foreach ($node->consts as $const) {
|
||||
$this->addNamespacedName($const);
|
||||
}
|
||||
} else if ($node instanceof Stmt\ClassConst) {
|
||||
$this->resolveAttrGroups($node);
|
||||
} elseif ($node instanceof Expr\StaticCall
|
||||
|| $node instanceof Expr\StaticPropertyFetch
|
||||
|| $node instanceof Expr\ClassConstFetch
|
||||
@ -157,6 +165,7 @@ class NameResolver extends NodeVisitorAbstract
|
||||
private function resolveSignature($node) {
|
||||
foreach ($node->params as $param) {
|
||||
$param->type = $this->resolveType($param->type);
|
||||
$this->resolveAttrGroups($param);
|
||||
}
|
||||
$node->returnType = $this->resolveType($node->returnType);
|
||||
}
|
||||
@ -225,4 +234,13 @@ class NameResolver extends NodeVisitorAbstract
|
||||
$node->namespacedName = Name::concat(
|
||||
$this->nameContext->getNamespace(), (string) $node->name);
|
||||
}
|
||||
|
||||
protected function resolveAttrGroups(Node $node)
|
||||
{
|
||||
foreach ($node->attrGroups as $attrGroup) {
|
||||
foreach ($attrGroup->attrs as $attr) {
|
||||
$attr->name = $this->resolveClassName($attr->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,11 +17,11 @@ use PhpParser\Node\Stmt;
|
||||
*/
|
||||
class Php5 extends \PhpParser\ParserAbstract
|
||||
{
|
||||
protected $tokenToSymbolMapSize = 391;
|
||||
protected $tokenToSymbolMapSize = 392;
|
||||
protected $actionTableSize = 1069;
|
||||
protected $gotoTableSize = 580;
|
||||
|
||||
protected $invalidSymbol = 164;
|
||||
protected $invalidSymbol = 165;
|
||||
protected $errorSymbol = 1;
|
||||
protected $defaultAction = -32766;
|
||||
protected $unexpectedTokenRule = 32767;
|
||||
@ -193,36 +193,37 @@ class Php5 extends \PhpParser\ParserAbstract
|
||||
"'`'",
|
||||
"']'",
|
||||
"'\"'",
|
||||
"T_NULLSAFE_OBJECT_OPERATOR"
|
||||
"T_NULLSAFE_OBJECT_OPERATOR",
|
||||
"T_ATTRIBUTE"
|
||||
);
|
||||
|
||||
protected $tokenToSymbol = array(
|
||||
0, 164, 164, 164, 164, 164, 164, 164, 164, 164,
|
||||
164, 164, 164, 164, 164, 164, 164, 164, 164, 164,
|
||||
164, 164, 164, 164, 164, 164, 164, 164, 164, 164,
|
||||
164, 164, 164, 55, 162, 164, 159, 54, 37, 164,
|
||||
157, 158, 52, 49, 8, 50, 51, 53, 164, 164,
|
||||
164, 164, 164, 164, 164, 164, 164, 164, 31, 154,
|
||||
43, 16, 45, 30, 67, 164, 164, 164, 164, 164,
|
||||
164, 164, 164, 164, 164, 164, 164, 164, 164, 164,
|
||||
164, 164, 164, 164, 164, 164, 164, 164, 164, 164,
|
||||
164, 69, 164, 161, 36, 164, 160, 164, 164, 164,
|
||||
164, 164, 164, 164, 164, 164, 164, 164, 164, 164,
|
||||
164, 164, 164, 164, 164, 164, 164, 164, 164, 164,
|
||||
164, 164, 164, 155, 35, 156, 57, 164, 164, 164,
|
||||
164, 164, 164, 164, 164, 164, 164, 164, 164, 164,
|
||||
164, 164, 164, 164, 164, 164, 164, 164, 164, 164,
|
||||
164, 164, 164, 164, 164, 164, 164, 164, 164, 164,
|
||||
164, 164, 164, 164, 164, 164, 164, 164, 164, 164,
|
||||
164, 164, 164, 164, 164, 164, 164, 164, 164, 164,
|
||||
164, 164, 164, 164, 164, 164, 164, 164, 164, 164,
|
||||
164, 164, 164, 164, 164, 164, 164, 164, 164, 164,
|
||||
164, 164, 164, 164, 164, 164, 164, 164, 164, 164,
|
||||
164, 164, 164, 164, 164, 164, 164, 164, 164, 164,
|
||||
164, 164, 164, 164, 164, 164, 164, 164, 164, 164,
|
||||
164, 164, 164, 164, 164, 164, 164, 164, 164, 164,
|
||||
164, 164, 164, 164, 164, 164, 164, 164, 164, 164,
|
||||
164, 164, 164, 164, 164, 164, 1, 2, 3, 4,
|
||||
0, 165, 165, 165, 165, 165, 165, 165, 165, 165,
|
||||
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
|
||||
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
|
||||
165, 165, 165, 55, 162, 165, 159, 54, 37, 165,
|
||||
157, 158, 52, 49, 8, 50, 51, 53, 165, 165,
|
||||
165, 165, 165, 165, 165, 165, 165, 165, 31, 154,
|
||||
43, 16, 45, 30, 67, 165, 165, 165, 165, 165,
|
||||
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
|
||||
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
|
||||
165, 69, 165, 161, 36, 165, 160, 165, 165, 165,
|
||||
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
|
||||
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
|
||||
165, 165, 165, 155, 35, 156, 57, 165, 165, 165,
|
||||
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
|
||||
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
|
||||
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
|
||||
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
|
||||
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
|
||||
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
|
||||
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
|
||||
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
|
||||
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
|
||||
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
|
||||
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
|
||||
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
|
||||
165, 165, 165, 165, 165, 165, 1, 2, 3, 4,
|
||||
5, 6, 7, 9, 10, 11, 12, 13, 14, 15,
|
||||
17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
|
||||
27, 28, 29, 32, 33, 34, 38, 39, 40, 41,
|
||||
@ -236,7 +237,7 @@ class Php5 extends \PhpParser\ParserAbstract
|
||||
124, 125, 126, 127, 128, 129, 130, 131, 163, 132,
|
||||
133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
|
||||
143, 144, 145, 146, 147, 148, 149, 150, 151, 152,
|
||||
153
|
||||
153, 164
|
||||
);
|
||||
|
||||
protected $action = array(
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -140,4 +140,5 @@ final class Tokens
|
||||
const T_NAME_FULLY_QUALIFIED = 388;
|
||||
const T_NAME_QUALIFIED = 389;
|
||||
const T_NAME_RELATIVE = 390;
|
||||
const T_ATTRIBUTE = 391;
|
||||
}
|
||||
|
@ -18,7 +18,8 @@ class Standard extends PrettyPrinterAbstract
|
||||
// Special nodes
|
||||
|
||||
protected function pParam(Node\Param $node) {
|
||||
return ($this->pModifiers($node->flags))
|
||||
return $this->pAttrGroups($node->attrGroups, true)
|
||||
. $this->pModifiers($node->flags)
|
||||
. ($node->type ? $this->p($node->type) . ' ' : '')
|
||||
. ($node->byRef ? '&' : '')
|
||||
. ($node->variadic ? '...' : '')
|
||||
@ -52,6 +53,15 @@ class Standard extends PrettyPrinterAbstract
|
||||
return '$' . $node->name;
|
||||
}
|
||||
|
||||
protected function pAttribute(Node\Attribute $node) {
|
||||
return $this->p($node->name)
|
||||
. ($node->args ? '(' . $this->pCommaSeparated($node->args) . ')' : '');
|
||||
}
|
||||
|
||||
protected function pAttributeGroup(Node\AttributeGroup $node) {
|
||||
return '#[' . $this->pCommaSeparated($node->attrs) . ']';
|
||||
}
|
||||
|
||||
// Names
|
||||
|
||||
protected function pName(Name $node) {
|
||||
@ -600,7 +610,8 @@ class Standard extends PrettyPrinterAbstract
|
||||
}
|
||||
|
||||
protected function pExpr_Closure(Expr\Closure $node) {
|
||||
return ($node->static ? 'static ' : '')
|
||||
return $this->pAttrGroups($node->attrGroups, true)
|
||||
. ($node->static ? 'static ' : '')
|
||||
. 'function ' . ($node->byRef ? '&' : '')
|
||||
. '(' . $this->pCommaSeparated($node->params) . ')'
|
||||
. (!empty($node->uses) ? ' use(' . $this->pCommaSeparated($node->uses) . ')' : '')
|
||||
@ -621,7 +632,8 @@ class Standard extends PrettyPrinterAbstract
|
||||
}
|
||||
|
||||
protected function pExpr_ArrowFunction(Expr\ArrowFunction $node) {
|
||||
return ($node->static ? 'static ' : '')
|
||||
return $this->pAttrGroups($node->attrGroups, true)
|
||||
. ($node->static ? 'static ' : '')
|
||||
. 'fn' . ($node->byRef ? '&' : '')
|
||||
. '(' . $this->pCommaSeparated($node->params) . ')'
|
||||
. (null !== $node->returnType ? ': ' . $this->p($node->returnType) : '')
|
||||
@ -709,7 +721,8 @@ class Standard extends PrettyPrinterAbstract
|
||||
}
|
||||
|
||||
protected function pStmt_Interface(Stmt\Interface_ $node) {
|
||||
return 'interface ' . $node->name
|
||||
return $this->pAttrGroups($node->attrGroups)
|
||||
. 'interface ' . $node->name
|
||||
. (!empty($node->extends) ? ' extends ' . $this->pCommaSeparated($node->extends) : '')
|
||||
. $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}';
|
||||
}
|
||||
@ -719,7 +732,8 @@ class Standard extends PrettyPrinterAbstract
|
||||
}
|
||||
|
||||
protected function pStmt_Trait(Stmt\Trait_ $node) {
|
||||
return 'trait ' . $node->name
|
||||
return $this->pAttrGroups($node->attrGroups)
|
||||
. 'trait ' . $node->name
|
||||
. $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}';
|
||||
}
|
||||
|
||||
@ -744,7 +758,8 @@ class Standard extends PrettyPrinterAbstract
|
||||
}
|
||||
|
||||
protected function pStmt_Property(Stmt\Property $node) {
|
||||
return (0 === $node->flags ? 'var ' : $this->pModifiers($node->flags))
|
||||
return $this->pAttrGroups($node->attrGroups)
|
||||
. (0 === $node->flags ? 'var ' : $this->pModifiers($node->flags))
|
||||
. ($node->type ? $this->p($node->type) . ' ' : '')
|
||||
. $this->pCommaSeparated($node->props) . ';';
|
||||
}
|
||||
@ -755,7 +770,8 @@ class Standard extends PrettyPrinterAbstract
|
||||
}
|
||||
|
||||
protected function pStmt_ClassMethod(Stmt\ClassMethod $node) {
|
||||
return $this->pModifiers($node->flags)
|
||||
return $this->pAttrGroups($node->attrGroups)
|
||||
. $this->pModifiers($node->flags)
|
||||
. 'function ' . ($node->byRef ? '&' : '') . $node->name
|
||||
. '(' . $this->pMaybeMultiline($node->params) . ')'
|
||||
. (null !== $node->returnType ? ' : ' . $this->p($node->returnType) : '')
|
||||
@ -765,12 +781,14 @@ class Standard extends PrettyPrinterAbstract
|
||||
}
|
||||
|
||||
protected function pStmt_ClassConst(Stmt\ClassConst $node) {
|
||||
return $this->pModifiers($node->flags)
|
||||
return $this->pAttrGroups($node->attrGroups)
|
||||
. $this->pModifiers($node->flags)
|
||||
. 'const ' . $this->pCommaSeparated($node->consts) . ';';
|
||||
}
|
||||
|
||||
protected function pStmt_Function(Stmt\Function_ $node) {
|
||||
return 'function ' . ($node->byRef ? '&' : '') . $node->name
|
||||
return $this->pAttrGroups($node->attrGroups)
|
||||
. 'function ' . ($node->byRef ? '&' : '') . $node->name
|
||||
. '(' . $this->pCommaSeparated($node->params) . ')'
|
||||
. (null !== $node->returnType ? ' : ' . $this->p($node->returnType) : '')
|
||||
. $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}';
|
||||
@ -925,7 +943,8 @@ class Standard extends PrettyPrinterAbstract
|
||||
// Helpers
|
||||
|
||||
protected function pClassCommon(Stmt\Class_ $node, $afterClassToken) {
|
||||
return $this->pModifiers($node->flags)
|
||||
return $this->pAttrGroups($node->attrGroups, $node->name === null)
|
||||
. $this->pModifiers($node->flags)
|
||||
. 'class' . $afterClassToken
|
||||
. (null !== $node->extends ? ' extends ' . $this->p($node->extends) : '')
|
||||
. (!empty($node->implements) ? ' implements ' . $this->pCommaSeparated($node->implements) : '')
|
||||
@ -1030,11 +1049,21 @@ class Standard extends PrettyPrinterAbstract
|
||||
return false;
|
||||
}
|
||||
|
||||
private function pMaybeMultiline(array $nodes, $trailingComma = false) {
|
||||
private function pMaybeMultiline(array $nodes, bool $trailingComma = false) {
|
||||
if (!$this->hasNodeWithComments($nodes)) {
|
||||
return $this->pCommaSeparated($nodes);
|
||||
} else {
|
||||
return $this->pCommaSeparatedMultiline($nodes, $trailingComma) . $this->nl;
|
||||
}
|
||||
}
|
||||
|
||||
private function pAttrGroups(array $nodes, bool $inline = false): string {
|
||||
$result = '';
|
||||
$sep = $inline ? ' ' : $this->nl;
|
||||
foreach ($nodes as $node) {
|
||||
$result .= $this->p($node) . $sep;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
@ -1375,6 +1375,7 @@ abstract class PrettyPrinterAbstract
|
||||
'Stmt_Unset->vars' => ', ',
|
||||
'Stmt_Use->uses' => ', ',
|
||||
'MatchArm->conds' => ', ',
|
||||
'AttributeGroup->attrs' => ', ',
|
||||
|
||||
// statement lists
|
||||
'Expr_Closure->stmts' => "\n",
|
||||
@ -1395,6 +1396,17 @@ abstract class PrettyPrinterAbstract
|
||||
'Stmt_Function->stmts' => "\n",
|
||||
'Stmt_If->stmts' => "\n",
|
||||
'Stmt_Namespace->stmts' => "\n",
|
||||
'Stmt_Class->attrGroups' => "\n",
|
||||
'Stmt_Interface->attrGroups' => "\n",
|
||||
'Stmt_Trait->attrGroups' => "\n",
|
||||
'Stmt_Function->attrGroups' => "\n",
|
||||
'Stmt_ClassMethod->attrGroups' => "\n",
|
||||
'Stmt_ClassConst->attrGroups' => "\n",
|
||||
'Stmt_Property->attrGroups' => "\n",
|
||||
'Expr_PrintableNewAnonClass->attrGroups' => ' ',
|
||||
'Expr_Closure->attrGroups' => ' ',
|
||||
'Expr_ArrowFunction->attrGroups' => ' ',
|
||||
'Param->attrGroups' => ' ',
|
||||
'Stmt_Switch->cases' => "\n",
|
||||
'Stmt_TraitUse->adaptations' => "\n",
|
||||
'Stmt_TryCatch->stmts' => "\n",
|
||||
|
@ -121,9 +121,11 @@ class ConstExprEvaluatorTest extends \PHPUnit\Framework\TestCase
|
||||
'Modulo by zero'
|
||||
],
|
||||
[
|
||||
new Expr\BinaryOp\Div(new Scalar\LNumber(42), new Scalar\LNumber(0)),
|
||||
new Expr\BinaryOp\Plus(new Scalar\LNumber(42), new Scalar\String_("1foo")),
|
||||
\ErrorException::class,
|
||||
'Division by zero'
|
||||
\PHP_VERSION_ID >= 80000
|
||||
? 'A non-numeric value encountered'
|
||||
: 'A non well formed numeric value encountered'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
@ -275,6 +275,33 @@ class EmulativeTest extends LexerTest
|
||||
['?->', [
|
||||
[Tokens::T_NULLSAFE_OBJECT_OPERATOR, '?->'],
|
||||
]],
|
||||
['#[Attr]', [
|
||||
[Tokens::T_ATTRIBUTE, '#['],
|
||||
[Tokens::T_STRING, 'Attr'],
|
||||
[ord(']'), ']'],
|
||||
]],
|
||||
["#[\nAttr\n]", [
|
||||
[Tokens::T_ATTRIBUTE, '#['],
|
||||
[Tokens::T_STRING, 'Attr'],
|
||||
[ord(']'), ']'],
|
||||
]],
|
||||
// Test interaction of two patch-based emulators
|
||||
["<<<LABEL\n LABEL, #[Attr]", [
|
||||
[Tokens::T_START_HEREDOC, "<<<LABEL\n"],
|
||||
[Tokens::T_END_HEREDOC, " LABEL"],
|
||||
[ord(','), ','],
|
||||
[Tokens::T_ATTRIBUTE, '#['],
|
||||
[Tokens::T_STRING, 'Attr'],
|
||||
[ord(']'), ']'],
|
||||
]],
|
||||
["#[Attr] <<<LABEL\n LABEL,", [
|
||||
[Tokens::T_ATTRIBUTE, '#['],
|
||||
[Tokens::T_STRING, 'Attr'],
|
||||
[ord(']'), ']'],
|
||||
[Tokens::T_START_HEREDOC, "<<<LABEL\n"],
|
||||
[Tokens::T_END_HEREDOC, " LABEL"],
|
||||
[ord(','), ','],
|
||||
]],
|
||||
];
|
||||
}
|
||||
|
||||
@ -293,6 +320,22 @@ class EmulativeTest extends LexerTest
|
||||
['7.4', 'match', [[Tokens::T_STRING, 'match']]],
|
||||
['7.4', 'fn', [[Tokens::T_FN, '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('"'), '"'],
|
||||
]],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -248,6 +248,7 @@ PHP;
|
||||
}
|
||||
},
|
||||
"flags": 0,
|
||||
"attrGroups": [],
|
||||
"attributes": {
|
||||
"startLine": 4,
|
||||
"endLine": 4
|
||||
@ -275,6 +276,7 @@ PHP;
|
||||
}
|
||||
},
|
||||
"flags": 0,
|
||||
"attrGroups": [],
|
||||
"attributes": {
|
||||
"startLine": 4,
|
||||
"endLine": 4
|
||||
@ -302,6 +304,7 @@ PHP;
|
||||
}
|
||||
}
|
||||
],
|
||||
"attrGroups": [],
|
||||
"attributes": {
|
||||
"startLine": 4,
|
||||
"comments": [
|
||||
|
@ -165,13 +165,8 @@ namespace Baz {
|
||||
}
|
||||
EOC;
|
||||
|
||||
$parser = new PhpParser\Parser\Php7(new PhpParser\Lexer\Emulative);
|
||||
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
|
||||
$traverser = new PhpParser\NodeTraverser;
|
||||
$traverser->addVisitor(new NameResolver);
|
||||
|
||||
$stmts = $parser->parse($code);
|
||||
$stmts = $traverser->traverse($stmts);
|
||||
$stmts = $this->parseAndResolve($code);
|
||||
|
||||
$this->assertSame(
|
||||
$this->canonicalize($expectedCode),
|
||||
@ -187,33 +182,43 @@ EOC;
|
||||
<?php
|
||||
namespace NS;
|
||||
|
||||
#[X]
|
||||
class A extends B implements C, D {
|
||||
use E, F, G {
|
||||
f as private g;
|
||||
E::h as i;
|
||||
E::j insteadof F, G;
|
||||
}
|
||||
|
||||
#[X]
|
||||
public float $php = 7.4;
|
||||
public ?Foo $person;
|
||||
protected static ?bool $probability;
|
||||
public A|B|int $prop;
|
||||
|
||||
#[X]
|
||||
const C = 1;
|
||||
}
|
||||
|
||||
#[X]
|
||||
interface A extends C, D {
|
||||
public function a(A $a) : A;
|
||||
public function b(A|B|int $a): A|B|int;
|
||||
}
|
||||
|
||||
class ClassWithTypeProperties {
|
||||
public float $php = 7.4;
|
||||
public ?Foo $person;
|
||||
protected static ?bool $probability;
|
||||
public A|B|int $prop;
|
||||
}
|
||||
#[X]
|
||||
trait A {}
|
||||
|
||||
function f(A $a) : A {}
|
||||
#[X]
|
||||
function f(#[X] A $a) : A {}
|
||||
function f2(array $a) : array {}
|
||||
function(A $a) : A {};
|
||||
|
||||
function fn3(?A $a) : ?A {}
|
||||
function fn4(?array $a) : ?array {}
|
||||
|
||||
#[X]
|
||||
function(A $a) : A {};
|
||||
|
||||
#[X]
|
||||
fn(array $a): array => $a;
|
||||
fn(A $a): A => $a;
|
||||
fn(?A $a): ?A => $a;
|
||||
@ -236,6 +241,7 @@ EOC;
|
||||
$expectedCode = <<<'EOC'
|
||||
namespace NS;
|
||||
|
||||
#[\NS\X]
|
||||
class A extends \NS\B implements \NS\C, \NS\D
|
||||
{
|
||||
use \NS\E, \NS\F, \NS\G {
|
||||
@ -243,34 +249,40 @@ class A extends \NS\B implements \NS\C, \NS\D
|
||||
\NS\E::h as i;
|
||||
\NS\E::j insteadof \NS\F, \NS\G;
|
||||
}
|
||||
#[\NS\X]
|
||||
public float $php = 7.4;
|
||||
public ?\NS\Foo $person;
|
||||
protected static ?bool $probability;
|
||||
public \NS\A|\NS\B|int $prop;
|
||||
#[\NS\X]
|
||||
const C = 1;
|
||||
}
|
||||
#[\NS\X]
|
||||
interface A extends \NS\C, \NS\D
|
||||
{
|
||||
public function a(\NS\A $a) : \NS\A;
|
||||
public function b(\NS\A|\NS\B|int $a) : \NS\A|\NS\B|int;
|
||||
}
|
||||
class ClassWithTypeProperties
|
||||
#[\NS\X]
|
||||
trait A
|
||||
{
|
||||
public float $php = 7.4;
|
||||
public ?\NS\Foo $person;
|
||||
protected static ?bool $probability;
|
||||
public \NS\A|\NS\B|int $prop;
|
||||
}
|
||||
function f(\NS\A $a) : \NS\A
|
||||
#[\NS\X]
|
||||
function f(#[\NS\X] \NS\A $a) : \NS\A
|
||||
{
|
||||
}
|
||||
function f2(array $a) : array
|
||||
{
|
||||
}
|
||||
function (\NS\A $a) : \NS\A {
|
||||
};
|
||||
function fn3(?\NS\A $a) : ?\NS\A
|
||||
{
|
||||
}
|
||||
function fn4(?array $a) : ?array
|
||||
{
|
||||
}
|
||||
fn(array $a): array => $a;
|
||||
#[\NS\X] function (\NS\A $a) : \NS\A {
|
||||
};
|
||||
#[\NS\X] fn(array $a): array => $a;
|
||||
fn(\NS\A $a): \NS\A => $a;
|
||||
fn(?\NS\A $a): ?\NS\A => $a;
|
||||
\NS\A::b();
|
||||
@ -287,13 +299,8 @@ try {
|
||||
}
|
||||
EOC;
|
||||
|
||||
$parser = new PhpParser\Parser\Php7(new PhpParser\Lexer\Emulative);
|
||||
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
|
||||
$traverser = new PhpParser\NodeTraverser;
|
||||
$traverser->addVisitor(new NameResolver);
|
||||
|
||||
$stmts = $parser->parse($code);
|
||||
$stmts = $traverser->traverse($stmts);
|
||||
$stmts = $this->parseAndResolve($code);
|
||||
|
||||
$this->assertSame(
|
||||
$this->canonicalize($expectedCode),
|
||||
@ -512,4 +519,14 @@ EOC;
|
||||
$this->assertEquals(
|
||||
new Name\FullyQualified('Foo\bar'), $n2->getAttribute('namespacedName'));
|
||||
}
|
||||
|
||||
private function parseAndResolve(string $code): array
|
||||
{
|
||||
$parser = new PhpParser\Parser\Php7(new PhpParser\Lexer\Emulative);
|
||||
$traverser = new PhpParser\NodeTraverser;
|
||||
$traverser->addVisitor(new NameResolver);
|
||||
|
||||
$stmts = $parser->parse($code);
|
||||
return $traverser->traverse($stmts);
|
||||
}
|
||||
}
|
||||
|
179
test/code/formatPreservation/attributes.test
Normal file
179
test/code/formatPreservation/attributes.test
Normal file
@ -0,0 +1,179 @@
|
||||
Attributes
|
||||
-----
|
||||
<?php
|
||||
#[A]
|
||||
class X {
|
||||
#[A]
|
||||
public function m(#[A] & $p) {}
|
||||
|
||||
#[A]
|
||||
public
|
||||
$prop;
|
||||
|
||||
#[A]
|
||||
const
|
||||
X = 42;
|
||||
}
|
||||
|
||||
#[A]
|
||||
trait X {}
|
||||
|
||||
#[A]
|
||||
interface X {}
|
||||
|
||||
#[A]
|
||||
function f() {}
|
||||
|
||||
new #[A] class {};
|
||||
#[A] function() {};
|
||||
#[A] fn()
|
||||
=> 42;
|
||||
-----
|
||||
$attrGroup = new Node\AttributeGroup([
|
||||
new Node\Attribute(new Node\Name('B'), []),
|
||||
]);
|
||||
$stmts[0]->attrGroups[] = $attrGroup;
|
||||
$stmts[0]->stmts[0]->attrGroups[] = $attrGroup;
|
||||
$stmts[0]->stmts[0]->params[0]->attrGroups[] = $attrGroup;
|
||||
$stmts[0]->stmts[1]->attrGroups[] = $attrGroup;
|
||||
$stmts[0]->stmts[2]->attrGroups[] = $attrGroup;
|
||||
$stmts[1]->attrGroups[] = $attrGroup;
|
||||
$stmts[2]->attrGroups[] = $attrGroup;
|
||||
$stmts[3]->attrGroups[] = $attrGroup;
|
||||
$stmts[4]->expr->class->attrGroups[] = $attrGroup;
|
||||
$stmts[5]->expr->attrGroups[] = $attrGroup;
|
||||
$stmts[6]->expr->attrGroups[] = $attrGroup;
|
||||
-----
|
||||
<?php
|
||||
#[A]
|
||||
#[B]
|
||||
class X {
|
||||
#[A]
|
||||
#[B]
|
||||
public function m(#[A] #[B] & $p) {}
|
||||
|
||||
#[A]
|
||||
#[B]
|
||||
public
|
||||
$prop;
|
||||
|
||||
#[A]
|
||||
#[B]
|
||||
const
|
||||
X = 42;
|
||||
}
|
||||
|
||||
#[A]
|
||||
#[B]
|
||||
trait X {}
|
||||
|
||||
#[A]
|
||||
#[B]
|
||||
interface X {}
|
||||
|
||||
#[A]
|
||||
#[B]
|
||||
function f() {}
|
||||
|
||||
new #[A] #[B] class {};
|
||||
#[A] #[B] function() {};
|
||||
#[A] #[B] fn()
|
||||
=> 42;
|
||||
-----
|
||||
<?php
|
||||
class X {
|
||||
public function m() {}
|
||||
|
||||
public
|
||||
$prop;
|
||||
|
||||
const
|
||||
X = 42;
|
||||
}
|
||||
|
||||
trait X {}
|
||||
|
||||
interface X {}
|
||||
|
||||
function f() {}
|
||||
|
||||
new class {};
|
||||
function() {};
|
||||
fn()
|
||||
=> 42;
|
||||
-----
|
||||
// TODO: Currently we lose formatting for this case.
|
||||
$attrGroup = new Node\AttributeGroup([
|
||||
new Node\Attribute(new Node\Name('A'), []),
|
||||
]);
|
||||
$stmts[0]->attrGroups[] = $attrGroup;
|
||||
$stmts[0]->stmts[0]->attrGroups[] = $attrGroup;
|
||||
$stmts[0]->stmts[1]->attrGroups[] = $attrGroup;
|
||||
$stmts[0]->stmts[2]->attrGroups[] = $attrGroup;
|
||||
$stmts[1]->attrGroups[] = $attrGroup;
|
||||
$stmts[2]->attrGroups[] = $attrGroup;
|
||||
$stmts[3]->attrGroups[] = $attrGroup;
|
||||
$stmts[4]->expr->class->attrGroups[] = $attrGroup;
|
||||
$stmts[5]->expr->attrGroups[] = $attrGroup;
|
||||
$stmts[6]->expr->attrGroups[] = $attrGroup;
|
||||
-----
|
||||
<?php
|
||||
#[A]
|
||||
class X
|
||||
{
|
||||
#[A]
|
||||
public function m()
|
||||
{
|
||||
}
|
||||
#[A]
|
||||
public $prop;
|
||||
#[A]
|
||||
const X = 42;
|
||||
}
|
||||
|
||||
#[A]
|
||||
trait X
|
||||
{
|
||||
}
|
||||
|
||||
#[A]
|
||||
interface X
|
||||
{
|
||||
}
|
||||
|
||||
#[A]
|
||||
function f()
|
||||
{
|
||||
}
|
||||
|
||||
new #[A] class
|
||||
{
|
||||
};
|
||||
#[A] function () {
|
||||
};
|
||||
#[A] fn() => 42;
|
||||
-----
|
||||
<?php
|
||||
|
||||
#[ A, B]
|
||||
class X {};
|
||||
#[
|
||||
A,
|
||||
B,
|
||||
]
|
||||
class X {};
|
||||
-----
|
||||
$attr = new Node\Attribute(new Node\Name('C'), []);
|
||||
$stmts[0]->attrGroups[0]->attrs[] = $attr;
|
||||
$stmts[1]->attrGroups[0]->attrs[] = $attr;
|
||||
-----
|
||||
<?php
|
||||
|
||||
#[ A, B, C]
|
||||
class X {};
|
||||
#[
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
]
|
||||
class X {};
|
@ -8,6 +8,8 @@ class MyClass {
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: MyClass
|
||||
@ -17,6 +19,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PROTECTED (2)
|
||||
type: null
|
||||
props: array(
|
||||
|
@ -161,6 +161,8 @@ function test() {
|
||||
Syntax error, unexpected '}' from 4:1 to 4:1
|
||||
array(
|
||||
0: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: test
|
||||
@ -306,6 +308,8 @@ function foo() {
|
||||
Syntax error, unexpected '}', expecting T_STRING or T_VARIABLE or '{' or '$' from 4:1 to 4:1
|
||||
array(
|
||||
0: Stmt_Function[2:1 - 4:1](
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier[2:10 - 2:12](
|
||||
name: foo
|
||||
@ -683,6 +687,8 @@ array(
|
||||
)
|
||||
)
|
||||
4: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: X
|
||||
@ -736,6 +742,8 @@ array(
|
||||
)
|
||||
)
|
||||
2: Stmt_ClassConst(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
consts: array(
|
||||
0: Const(
|
||||
@ -749,6 +757,8 @@ array(
|
||||
)
|
||||
)
|
||||
3: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
type: null
|
||||
props: array(
|
||||
@ -763,6 +773,8 @@ array(
|
||||
)
|
||||
)
|
||||
5: Stmt_Interface(
|
||||
attrGroups: array(
|
||||
)
|
||||
name: Identifier(
|
||||
name: I
|
||||
)
|
||||
@ -895,6 +907,8 @@ class Foo {
|
||||
Syntax error, unexpected T_STRING from 4:5 to 4:9
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: Foo
|
||||
@ -904,6 +918,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
type: null
|
||||
props: array(
|
||||
@ -998,12 +1014,16 @@ Syntax error, unexpected ')', expecting T_VARIABLE from 22:21 to 22:21
|
||||
Syntax error, unexpected ')', expecting T_VARIABLE from 25:13 to 25:13
|
||||
array(
|
||||
0: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: foo
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: Name(
|
||||
parts: array(
|
||||
@ -1027,12 +1047,16 @@ array(
|
||||
)
|
||||
)
|
||||
1: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: foo
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: Name(
|
||||
parts: array(
|
||||
@ -1047,6 +1071,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: Name(
|
||||
parts: array(
|
||||
@ -1070,12 +1096,16 @@ array(
|
||||
)
|
||||
)
|
||||
2: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: foo
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -1095,12 +1125,16 @@ array(
|
||||
)
|
||||
)
|
||||
3: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: foo
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: true
|
||||
@ -1120,12 +1154,16 @@ array(
|
||||
)
|
||||
)
|
||||
4: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: foo
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: Name(
|
||||
parts: array(
|
||||
@ -1144,6 +1182,8 @@ array(
|
||||
)
|
||||
)
|
||||
5: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: Bar
|
||||
@ -1153,6 +1193,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -1160,6 +1202,8 @@ array(
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: Name(
|
||||
parts: array(
|
||||
@ -1181,10 +1225,14 @@ array(
|
||||
)
|
||||
6: Stmt_Expression(
|
||||
expr: Expr_Closure(
|
||||
attrGroups: array(
|
||||
)
|
||||
static: false
|
||||
byRef: false
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: Name(
|
||||
parts: array(
|
||||
@ -1219,9 +1267,9 @@ $array = [
|
||||
];
|
||||
-----
|
||||
!!php7
|
||||
Syntax error, unexpected T_VARIABLE, expecting ',' or ')' or ']' from 3:18 to 3:34
|
||||
Syntax error, unexpected T_VARIABLE, expecting ',' or ')' or ']' from 6:12 to 6:28
|
||||
Syntax error, unexpected T_VARIABLE, expecting ',' or ')' or ']' from 9:21 to 9:37
|
||||
Syntax error, unexpected T_VARIABLE, expecting ',' or ']' or ')' from 3:18 to 3:34
|
||||
Syntax error, unexpected T_VARIABLE, expecting ',' or ']' or ')' from 6:12 to 6:28
|
||||
Syntax error, unexpected T_VARIABLE, expecting ',' or ']' or ')' from 9:21 to 9:37
|
||||
array(
|
||||
0: Stmt_Expression(
|
||||
expr: Expr_Assign(
|
||||
@ -1330,6 +1378,8 @@ function foo() :
|
||||
Syntax error, unexpected '{' from 3:1 to 3:1
|
||||
array(
|
||||
0: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: foo
|
||||
@ -1351,4 +1401,4 @@ array(
|
||||
$a = ["a "thing"];
|
||||
-----
|
||||
!!php7
|
||||
Syntax error, unexpected T_STRING, expecting ',' or ')' or ']' from 2:11 to 2:15
|
||||
Syntax error, unexpected T_STRING, expecting ',' or ']' or ')' from 2:11 to 2:15
|
@ -59,6 +59,8 @@ array(
|
||||
)
|
||||
)
|
||||
1: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: getArr
|
||||
@ -92,6 +94,8 @@ array(
|
||||
)
|
||||
)
|
||||
2: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: arrGen
|
||||
|
@ -12,10 +12,14 @@ fn(): int => $x;
|
||||
array(
|
||||
0: Stmt_Expression(
|
||||
expr: Expr_ArrowFunction(
|
||||
attrGroups: array(
|
||||
)
|
||||
static: false
|
||||
byRef: false
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: Identifier(
|
||||
name: bool
|
||||
@ -36,10 +40,14 @@ array(
|
||||
)
|
||||
1: Stmt_Expression(
|
||||
expr: Expr_ArrowFunction(
|
||||
attrGroups: array(
|
||||
)
|
||||
static: false
|
||||
byRef: false
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -60,10 +68,14 @@ array(
|
||||
)
|
||||
2: Stmt_Expression(
|
||||
expr: Expr_ArrowFunction(
|
||||
attrGroups: array(
|
||||
)
|
||||
static: true
|
||||
byRef: false
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: true
|
||||
@ -82,10 +94,14 @@ array(
|
||||
)
|
||||
3: Stmt_Expression(
|
||||
expr: Expr_ArrowFunction(
|
||||
attrGroups: array(
|
||||
)
|
||||
static: false
|
||||
byRef: true
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -104,10 +120,14 @@ array(
|
||||
)
|
||||
4: Stmt_Expression(
|
||||
expr: Expr_ArrowFunction(
|
||||
attrGroups: array(
|
||||
)
|
||||
static: false
|
||||
byRef: false
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -118,6 +138,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -136,6 +158,8 @@ array(
|
||||
)
|
||||
5: Stmt_Expression(
|
||||
expr: Expr_ArrowFunction(
|
||||
attrGroups: array(
|
||||
)
|
||||
static: false
|
||||
byRef: false
|
||||
params: array(
|
||||
|
@ -12,10 +12,14 @@ function() use($a) : \Foo\Bar {};
|
||||
array(
|
||||
0: Stmt_Expression(
|
||||
expr: Expr_Closure(
|
||||
attrGroups: array(
|
||||
)
|
||||
static: false
|
||||
byRef: false
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -40,10 +44,14 @@ array(
|
||||
)
|
||||
1: Stmt_Expression(
|
||||
expr: Expr_Closure(
|
||||
attrGroups: array(
|
||||
)
|
||||
static: false
|
||||
byRef: false
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -69,6 +77,8 @@ array(
|
||||
)
|
||||
2: Stmt_Expression(
|
||||
expr: Expr_Closure(
|
||||
attrGroups: array(
|
||||
)
|
||||
static: false
|
||||
byRef: false
|
||||
params: array(
|
||||
@ -94,10 +104,14 @@ array(
|
||||
)
|
||||
3: Stmt_Expression(
|
||||
expr: Expr_Closure(
|
||||
attrGroups: array(
|
||||
)
|
||||
static: false
|
||||
byRef: true
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -117,6 +131,8 @@ array(
|
||||
)
|
||||
4: Stmt_Expression(
|
||||
expr: Expr_Closure(
|
||||
attrGroups: array(
|
||||
)
|
||||
static: true
|
||||
byRef: false
|
||||
params: array(
|
||||
@ -130,10 +146,14 @@ array(
|
||||
)
|
||||
5: Stmt_Expression(
|
||||
expr: Expr_Closure(
|
||||
attrGroups: array(
|
||||
)
|
||||
static: false
|
||||
byRef: false
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -155,6 +175,8 @@ array(
|
||||
)
|
||||
6: Stmt_Expression(
|
||||
expr: Expr_Closure(
|
||||
attrGroups: array(
|
||||
)
|
||||
static: false
|
||||
byRef: false
|
||||
params: array(
|
||||
|
@ -7,6 +7,8 @@ function() use($a,) {};
|
||||
array(
|
||||
0: Stmt_Expression(
|
||||
expr: Expr_Closure(
|
||||
attrGroups: array(
|
||||
)
|
||||
static: false
|
||||
byRef: false
|
||||
params: array(
|
||||
|
@ -71,11 +71,13 @@ array(
|
||||
4: Stmt_Expression(
|
||||
expr: Scalar_Encapsed(
|
||||
parts: array(
|
||||
0: Expr_Variable(
|
||||
0: Expr_NullsafePropertyFetch(
|
||||
var: Expr_Variable(
|
||||
name: a
|
||||
)
|
||||
1: Scalar_EncapsedStringPart(
|
||||
value: ?->b
|
||||
name: Identifier(
|
||||
name: b
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -204,10 +204,14 @@ array(
|
||||
name: Expr_FuncCall(
|
||||
name: Expr_FuncCall(
|
||||
name: Expr_Closure(
|
||||
attrGroups: array(
|
||||
)
|
||||
static: false
|
||||
byRef: false
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -274,10 +278,14 @@ array(
|
||||
name: f
|
||||
)
|
||||
expr: Expr_Closure(
|
||||
attrGroups: array(
|
||||
)
|
||||
static: false
|
||||
byRef: false
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
|
@ -54,6 +54,8 @@ class Foo {
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: Test
|
||||
@ -63,6 +65,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -75,6 +79,8 @@ array(
|
||||
)
|
||||
)
|
||||
1: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -87,6 +93,8 @@ array(
|
||||
)
|
||||
)
|
||||
2: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_STATIC (8)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -99,6 +107,8 @@ array(
|
||||
)
|
||||
)
|
||||
3: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_STATIC (8)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -111,6 +121,8 @@ array(
|
||||
)
|
||||
)
|
||||
4: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
type: null
|
||||
props: array(
|
||||
@ -123,6 +135,8 @@ array(
|
||||
)
|
||||
)
|
||||
5: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
type: null
|
||||
props: array(
|
||||
@ -135,6 +149,8 @@ array(
|
||||
)
|
||||
)
|
||||
6: Stmt_ClassConst(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
consts: array(
|
||||
0: Const(
|
||||
@ -156,6 +172,8 @@ array(
|
||||
)
|
||||
)
|
||||
7: Stmt_ClassConst(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
consts: array(
|
||||
0: Const(
|
||||
@ -344,6 +362,8 @@ array(
|
||||
)
|
||||
)
|
||||
10: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: Foo
|
||||
|
388
test/code/parser/stmt/attributes.test
Normal file
388
test/code/parser/stmt/attributes.test
Normal file
@ -0,0 +1,388 @@
|
||||
Attributes
|
||||
-----
|
||||
<?php
|
||||
|
||||
#[
|
||||
A1,
|
||||
A2(),
|
||||
A3(0),
|
||||
A4(x: 1),
|
||||
]
|
||||
function a() {
|
||||
}
|
||||
|
||||
#[A5]
|
||||
class C {
|
||||
#[A6]
|
||||
public function m(
|
||||
#[A7] $param,
|
||||
) {}
|
||||
#[A14]
|
||||
public $prop;
|
||||
}
|
||||
|
||||
#[A8]
|
||||
interface I {}
|
||||
#[A9]
|
||||
trait T {}
|
||||
|
||||
$x = #[A10] function() {};
|
||||
$y = #[A11] fn() => 0;
|
||||
$a = #[A12] static function() {};
|
||||
$b = #[A13] static fn() => 0;
|
||||
-----
|
||||
!!php7
|
||||
array(
|
||||
0: Stmt_Function(
|
||||
attrGroups: array(
|
||||
0: AttributeGroup(
|
||||
attrs: array(
|
||||
0: Attribute(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: A1
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
1: Attribute(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: A2
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
2: Attribute(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: A3
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
0: Arg(
|
||||
name: null
|
||||
value: Scalar_LNumber(
|
||||
value: 0
|
||||
)
|
||||
byRef: false
|
||||
unpack: false
|
||||
)
|
||||
)
|
||||
)
|
||||
3: Attribute(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: A4
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
0: Arg(
|
||||
name: Identifier(
|
||||
name: x
|
||||
)
|
||||
value: Scalar_LNumber(
|
||||
value: 1
|
||||
)
|
||||
byRef: false
|
||||
unpack: false
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: a
|
||||
)
|
||||
params: array(
|
||||
)
|
||||
returnType: null
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
1: Stmt_Class(
|
||||
attrGroups: array(
|
||||
0: AttributeGroup(
|
||||
attrs: array(
|
||||
0: Attribute(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: A5
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: C
|
||||
)
|
||||
extends: null
|
||||
implements: array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
0: AttributeGroup(
|
||||
attrs: array(
|
||||
0: Attribute(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: A6
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: m
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
0: AttributeGroup(
|
||||
attrs: array(
|
||||
0: Attribute(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: A7
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
var: Expr_Variable(
|
||||
name: param
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
1: Stmt_Property(
|
||||
attrGroups: array(
|
||||
0: AttributeGroup(
|
||||
attrs: array(
|
||||
0: Attribute(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: A14
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
type: null
|
||||
props: array(
|
||||
0: Stmt_PropertyProperty(
|
||||
name: VarLikeIdentifier(
|
||||
name: prop
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
2: Stmt_Interface(
|
||||
attrGroups: array(
|
||||
0: AttributeGroup(
|
||||
attrs: array(
|
||||
0: Attribute(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: A8
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
name: Identifier(
|
||||
name: I
|
||||
)
|
||||
extends: array(
|
||||
)
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
3: Stmt_Trait(
|
||||
attrGroups: array(
|
||||
0: AttributeGroup(
|
||||
attrs: array(
|
||||
0: Attribute(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: A9
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
name: Identifier(
|
||||
name: T
|
||||
)
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
4: Stmt_Expression(
|
||||
expr: Expr_Assign(
|
||||
var: Expr_Variable(
|
||||
name: x
|
||||
)
|
||||
expr: Expr_Closure(
|
||||
attrGroups: array(
|
||||
0: AttributeGroup(
|
||||
attrs: array(
|
||||
0: Attribute(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: A10
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
static: false
|
||||
byRef: false
|
||||
params: array(
|
||||
)
|
||||
uses: array(
|
||||
)
|
||||
returnType: null
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
5: Stmt_Expression(
|
||||
expr: Expr_Assign(
|
||||
var: Expr_Variable(
|
||||
name: y
|
||||
)
|
||||
expr: Expr_ArrowFunction(
|
||||
attrGroups: array(
|
||||
0: AttributeGroup(
|
||||
attrs: array(
|
||||
0: Attribute(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: A11
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
static: false
|
||||
byRef: false
|
||||
params: array(
|
||||
)
|
||||
returnType: null
|
||||
expr: Scalar_LNumber(
|
||||
value: 0
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
6: Stmt_Expression(
|
||||
expr: Expr_Assign(
|
||||
var: Expr_Variable(
|
||||
name: a
|
||||
)
|
||||
expr: Expr_Closure(
|
||||
attrGroups: array(
|
||||
0: AttributeGroup(
|
||||
attrs: array(
|
||||
0: Attribute(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: A12
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
static: true
|
||||
byRef: false
|
||||
params: array(
|
||||
)
|
||||
uses: array(
|
||||
)
|
||||
returnType: null
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
7: Stmt_Expression(
|
||||
expr: Expr_Assign(
|
||||
var: Expr_Variable(
|
||||
name: b
|
||||
)
|
||||
expr: Expr_ArrowFunction(
|
||||
attrGroups: array(
|
||||
0: AttributeGroup(
|
||||
attrs: array(
|
||||
0: Attribute(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: A13
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
static: true
|
||||
byRef: false
|
||||
params: array(
|
||||
)
|
||||
returnType: null
|
||||
expr: Scalar_LNumber(
|
||||
value: 0
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
@ -9,6 +9,8 @@ abstract class A {
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_ABSTRACT (16)
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -18,6 +20,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -30,6 +34,8 @@ array(
|
||||
)
|
||||
)
|
||||
1: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC | MODIFIER_ABSTRACT (17)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
|
@ -25,6 +25,8 @@ array(
|
||||
0: Stmt_Expression(
|
||||
expr: Expr_New(
|
||||
class: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: null
|
||||
extends: null
|
||||
@ -32,6 +34,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -52,6 +56,8 @@ array(
|
||||
1: Stmt_Expression(
|
||||
expr: Expr_New(
|
||||
class: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: null
|
||||
extends: Name(
|
||||
@ -81,6 +87,8 @@ array(
|
||||
2: Stmt_Expression(
|
||||
expr: Expr_New(
|
||||
class: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: null
|
||||
extends: null
|
||||
@ -88,6 +96,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
type: null
|
||||
props: array(
|
||||
@ -108,6 +118,8 @@ array(
|
||||
3: Stmt_Expression(
|
||||
expr: Expr_New(
|
||||
class: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: null
|
||||
extends: Name(
|
||||
@ -152,6 +164,8 @@ array(
|
||||
)
|
||||
)
|
||||
4: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -161,6 +175,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -173,6 +189,8 @@ array(
|
||||
0: Stmt_Return(
|
||||
expr: Expr_New(
|
||||
class: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: null
|
||||
extends: Name(
|
||||
@ -184,6 +202,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassConst(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
consts: array(
|
||||
0: Const(
|
||||
|
66
test/code/parser/stmt/class/class_position.test
Normal file
66
test/code/parser/stmt/class/class_position.test
Normal file
@ -0,0 +1,66 @@
|
||||
Class position
|
||||
-----
|
||||
<?php
|
||||
|
||||
class A {
|
||||
}
|
||||
|
||||
try {
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
|
||||
class B {
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
!!positions
|
||||
array(
|
||||
0: Stmt_Class[3:1 - 4:1](
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier[3:7 - 3:7](
|
||||
name: A
|
||||
)
|
||||
extends: null
|
||||
implements: array(
|
||||
)
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
1: Stmt_TryCatch[6:1 - 8:1](
|
||||
stmts: array(
|
||||
)
|
||||
catches: array(
|
||||
0: Stmt_Catch[7:3 - 8:1](
|
||||
types: array(
|
||||
0: Name[7:10 - 7:18](
|
||||
parts: array(
|
||||
0: Exception
|
||||
)
|
||||
)
|
||||
)
|
||||
var: Expr_Variable[7:20 - 7:21](
|
||||
name: e
|
||||
)
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
finally: null
|
||||
)
|
||||
2: Stmt_Class[10:1 - 11:1](
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier[10:7 - 10:7](
|
||||
name: B
|
||||
)
|
||||
extends: null
|
||||
implements: array(
|
||||
)
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
)
|
@ -17,6 +17,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
|
@ -9,6 +9,8 @@ class A {
|
||||
Cannot use 'static' as constant modifier from 3:5 to 3:10
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -18,6 +20,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassConst(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_STATIC (8)
|
||||
consts: array(
|
||||
0: Const(
|
||||
@ -43,6 +47,8 @@ class A {
|
||||
Cannot use 'abstract' as constant modifier from 3:5 to 3:12
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -52,6 +58,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassConst(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_ABSTRACT (16)
|
||||
consts: array(
|
||||
0: Const(
|
||||
@ -77,6 +85,8 @@ class A {
|
||||
Cannot use 'final' as constant modifier from 3:5 to 3:9
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -86,6 +96,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassConst(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_FINAL (32)
|
||||
consts: array(
|
||||
0: Const(
|
||||
@ -111,6 +123,8 @@ class A {
|
||||
Multiple access type modifiers are not allowed from 3:12 to 3:17
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -120,6 +134,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassConst(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
consts: array(
|
||||
0: Const(
|
||||
|
@ -12,6 +12,8 @@ class Foo {
|
||||
!!php7
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: Foo
|
||||
@ -21,6 +23,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassConst(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
consts: array(
|
||||
0: Const(
|
||||
@ -34,6 +38,8 @@ array(
|
||||
)
|
||||
)
|
||||
1: Stmt_ClassConst(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
consts: array(
|
||||
0: Const(
|
||||
@ -47,6 +53,8 @@ array(
|
||||
)
|
||||
)
|
||||
2: Stmt_ClassConst(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PROTECTED (2)
|
||||
consts: array(
|
||||
0: Const(
|
||||
@ -60,6 +68,8 @@ array(
|
||||
)
|
||||
)
|
||||
3: Stmt_ClassConst(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PRIVATE (4)
|
||||
consts: array(
|
||||
0: Const(
|
||||
|
@ -6,6 +6,8 @@ final class A {}
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_FINAL (32)
|
||||
name: Identifier(
|
||||
name: A
|
||||
|
@ -14,6 +14,8 @@ abstract class A {
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_ABSTRACT (16)
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -23,6 +25,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
props: array(
|
||||
@ -35,6 +39,8 @@ array(
|
||||
)
|
||||
)
|
||||
1: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_STATIC (8)
|
||||
type: null
|
||||
props: array(
|
||||
@ -47,6 +53,8 @@ array(
|
||||
)
|
||||
)
|
||||
2: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_ABSTRACT (16)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -58,6 +66,8 @@ array(
|
||||
stmts: null
|
||||
)
|
||||
3: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_FINAL (32)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -70,6 +80,8 @@ array(
|
||||
)
|
||||
)
|
||||
4: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_STATIC (8)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -82,6 +94,8 @@ array(
|
||||
)
|
||||
)
|
||||
5: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_STATIC | MODIFIER_FINAL (40)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -94,6 +108,8 @@ array(
|
||||
)
|
||||
)
|
||||
6: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
|
@ -8,6 +8,8 @@ interface A extends C, D {
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Interface(
|
||||
attrGroups: array(
|
||||
)
|
||||
name: Identifier(
|
||||
name: A
|
||||
)
|
||||
@ -25,6 +27,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
|
@ -5,6 +5,8 @@ Invalid modifier combination
|
||||
Multiple access type modifiers are not allowed from 1:24 to 1:29
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -14,6 +16,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
type: null
|
||||
props: array(
|
||||
@ -34,6 +38,8 @@ array(
|
||||
Multiple access type modifiers are not allowed from 1:24 to 1:32
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -43,6 +49,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC | MODIFIER_PROTECTED (3)
|
||||
type: null
|
||||
props: array(
|
||||
@ -63,6 +71,8 @@ array(
|
||||
Multiple abstract modifiers are not allowed from 1:26 to 1:33
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -72,6 +82,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_ABSTRACT (16)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -91,6 +103,8 @@ array(
|
||||
Multiple static modifiers are not allowed from 1:24 to 1:29
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -100,6 +114,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_STATIC (8)
|
||||
type: null
|
||||
props: array(
|
||||
@ -120,6 +136,8 @@ array(
|
||||
Multiple final modifiers are not allowed from 1:23 to 1:27
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -129,6 +147,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_FINAL (32)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -149,6 +169,8 @@ array(
|
||||
Cannot use the final modifier on an abstract class member from 1:26 to 1:30
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -158,6 +180,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_ABSTRACT | MODIFIER_FINAL (48)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -178,6 +202,8 @@ array(
|
||||
Syntax error, unexpected T_FINAL, expecting T_CLASS from 1:16 to 1:20
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_FINAL (32)
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -200,6 +226,8 @@ array(
|
||||
Properties cannot be declared abstract from 1:17 to 1:24
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -209,6 +237,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_ABSTRACT (16)
|
||||
type: null
|
||||
props: array(
|
||||
@ -229,6 +259,8 @@ array(
|
||||
Properties cannot be declared final from 1:17 to 1:21
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -238,6 +270,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_FINAL (32)
|
||||
type: null
|
||||
props: array(
|
||||
|
@ -5,6 +5,8 @@ Invalid class name
|
||||
Cannot use 'self' as class name as it is reserved from 1:13 to 1:16
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: self
|
||||
@ -22,6 +24,8 @@ array(
|
||||
Cannot use 'PARENT' as class name as it is reserved from 1:13 to 1:18
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: PARENT
|
||||
@ -45,6 +49,8 @@ array(
|
||||
Cannot use 'self' as class name as it is reserved from 1:23 to 1:26
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -66,6 +72,8 @@ array(
|
||||
Cannot use 'PARENT' as class name as it is reserved from 1:23 to 1:28
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -87,6 +95,8 @@ array(
|
||||
Cannot use 'static' as class name as it is reserved from 1:23 to 1:28
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -108,6 +118,8 @@ array(
|
||||
Cannot use 'self' as interface name as it is reserved from 1:26 to 1:29
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -130,6 +142,8 @@ array(
|
||||
Cannot use 'PARENT' as interface name as it is reserved from 1:26 to 1:31
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -152,6 +166,8 @@ array(
|
||||
Cannot use 'static' as interface name as it is reserved from 1:26 to 1:31
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -174,6 +190,8 @@ array(
|
||||
Cannot use 'self' as class name as it is reserved from 1:17 to 1:20
|
||||
array(
|
||||
0: Stmt_Interface(
|
||||
attrGroups: array(
|
||||
)
|
||||
name: Identifier(
|
||||
name: self
|
||||
)
|
||||
@ -189,6 +207,8 @@ array(
|
||||
Cannot use 'PARENT' as class name as it is reserved from 1:17 to 1:22
|
||||
array(
|
||||
0: Stmt_Interface(
|
||||
attrGroups: array(
|
||||
)
|
||||
name: Identifier(
|
||||
name: PARENT
|
||||
)
|
||||
@ -210,6 +230,8 @@ array(
|
||||
Cannot use 'self' as interface name as it is reserved from 1:27 to 1:30
|
||||
array(
|
||||
0: Stmt_Interface(
|
||||
attrGroups: array(
|
||||
)
|
||||
name: Identifier(
|
||||
name: A
|
||||
)
|
||||
@ -230,6 +252,8 @@ array(
|
||||
Cannot use 'PARENT' as interface name as it is reserved from 1:27 to 1:32
|
||||
array(
|
||||
0: Stmt_Interface(
|
||||
attrGroups: array(
|
||||
)
|
||||
name: Identifier(
|
||||
name: A
|
||||
)
|
||||
@ -250,6 +274,8 @@ array(
|
||||
Cannot use 'static' as interface name as it is reserved from 1:27 to 1:32
|
||||
array(
|
||||
0: Stmt_Interface(
|
||||
attrGroups: array(
|
||||
)
|
||||
name: Identifier(
|
||||
name: A
|
||||
)
|
||||
|
@ -10,6 +10,8 @@ class A {
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -19,6 +21,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
props: array(
|
||||
@ -31,6 +35,8 @@ array(
|
||||
)
|
||||
)
|
||||
1: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -43,6 +49,8 @@ array(
|
||||
)
|
||||
)
|
||||
2: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_ABSTRACT | MODIFIER_STATIC (24)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
|
@ -11,6 +11,8 @@ class A {
|
||||
!!php7
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -20,6 +22,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
type: Identifier(
|
||||
name: string
|
||||
@ -34,6 +38,8 @@ array(
|
||||
)
|
||||
)
|
||||
1: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PROTECTED | MODIFIER_STATIC (10)
|
||||
type: Name(
|
||||
parts: array(
|
||||
@ -50,6 +56,8 @@ array(
|
||||
)
|
||||
)
|
||||
2: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PRIVATE (4)
|
||||
type: NullableType(
|
||||
type: Identifier(
|
||||
|
@ -13,6 +13,8 @@ class Point {
|
||||
!!php7
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: Point
|
||||
@ -22,6 +24,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -29,6 +33,8 @@ array(
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
type: Identifier(
|
||||
name: float
|
||||
@ -43,6 +49,8 @@ array(
|
||||
)
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PROTECTED (2)
|
||||
type: Identifier(
|
||||
name: array
|
||||
@ -58,6 +66,8 @@ array(
|
||||
)
|
||||
)
|
||||
2: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PRIVATE (4)
|
||||
type: Identifier(
|
||||
name: string
|
||||
|
@ -18,6 +18,8 @@ class A extends B implements C, D {
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -41,6 +43,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassConst(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
consts: array(
|
||||
0: Const(
|
||||
@ -62,6 +66,8 @@ array(
|
||||
)
|
||||
)
|
||||
1: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
type: null
|
||||
props: array(
|
||||
@ -84,6 +90,8 @@ array(
|
||||
)
|
||||
)
|
||||
2: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PROTECTED (2)
|
||||
type: null
|
||||
props: array(
|
||||
@ -96,6 +104,8 @@ array(
|
||||
)
|
||||
)
|
||||
3: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PRIVATE (4)
|
||||
type: null
|
||||
props: array(
|
||||
@ -108,6 +118,8 @@ array(
|
||||
)
|
||||
)
|
||||
4: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -120,6 +132,8 @@ array(
|
||||
)
|
||||
)
|
||||
5: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC | MODIFIER_STATIC (9)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -127,6 +141,8 @@ array(
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -142,6 +158,8 @@ array(
|
||||
)
|
||||
)
|
||||
6: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC | MODIFIER_FINAL (33)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -158,6 +176,8 @@ array(
|
||||
)
|
||||
)
|
||||
7: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PROTECTED (2)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -170,6 +190,8 @@ array(
|
||||
)
|
||||
)
|
||||
8: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PRIVATE (4)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
|
@ -5,6 +5,8 @@ Some special methods cannot be static
|
||||
Constructor __construct() cannot be static from 1:17 to 1:22
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -14,6 +16,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_STATIC (8)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -34,6 +38,8 @@ array(
|
||||
Destructor __destruct() cannot be static from 1:17 to 1:22
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -43,6 +49,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_STATIC (8)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -63,6 +71,8 @@ array(
|
||||
Clone method __clone() cannot be static from 1:17 to 1:22
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -72,6 +82,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_STATIC (8)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -92,6 +104,8 @@ array(
|
||||
Constructor __CONSTRUCT() cannot be static from 1:17 to 1:22
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -101,6 +115,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_STATIC (8)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -121,6 +137,8 @@ array(
|
||||
Destructor __Destruct() cannot be static from 1:17 to 1:22
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -130,6 +148,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_STATIC (8)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -150,6 +170,8 @@ array(
|
||||
Clone method __cLoNe() cannot be static from 1:17 to 1:22
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
@ -159,6 +181,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_STATIC (8)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
|
@ -8,6 +8,8 @@ class Test {
|
||||
!!php7
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: Test
|
||||
@ -17,6 +19,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC | MODIFIER_STATIC (9)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
|
@ -23,11 +23,15 @@ class B {
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Trait(
|
||||
attrGroups: array(
|
||||
)
|
||||
name: Identifier(
|
||||
name: A
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -42,6 +46,8 @@ array(
|
||||
)
|
||||
)
|
||||
1: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: B
|
||||
|
@ -6,12 +6,16 @@ function test(bool $a, Int $b, FLOAT $c, StRiNg $d, iterable $e, object $f, mixe
|
||||
!!php7
|
||||
array(
|
||||
0: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: test
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: Identifier(
|
||||
name: bool
|
||||
@ -24,6 +28,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: Identifier(
|
||||
name: int
|
||||
@ -36,6 +42,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
2: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: Identifier(
|
||||
name: float
|
||||
@ -48,6 +56,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
3: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: Identifier(
|
||||
name: string
|
||||
@ -60,6 +70,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
4: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: Identifier(
|
||||
name: iterable
|
||||
@ -72,6 +84,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
5: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: Identifier(
|
||||
name: object
|
||||
@ -84,6 +98,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
6: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: Identifier(
|
||||
name: mixed
|
||||
|
@ -7,12 +7,16 @@ function &a($b) {}
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: a
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: true
|
||||
@ -28,12 +32,16 @@ array(
|
||||
)
|
||||
)
|
||||
1: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: true
|
||||
name: Identifier(
|
||||
name: a
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
|
@ -17,6 +17,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: A
|
||||
|
@ -16,12 +16,16 @@ function a(
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: a
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -38,6 +42,8 @@ array(
|
||||
)
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -50,6 +56,8 @@ array(
|
||||
)
|
||||
)
|
||||
2: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -69,6 +77,8 @@ array(
|
||||
)
|
||||
)
|
||||
3: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -83,6 +93,8 @@ array(
|
||||
)
|
||||
)
|
||||
4: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -97,6 +109,8 @@ array(
|
||||
)
|
||||
)
|
||||
5: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -110,6 +124,8 @@ array(
|
||||
)
|
||||
)
|
||||
6: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -123,6 +139,8 @@ array(
|
||||
)
|
||||
)
|
||||
7: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -144,6 +162,8 @@ array(
|
||||
)
|
||||
)
|
||||
8: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
|
@ -8,12 +8,16 @@ function test(?Foo $bar, ?string $foo) : ?Baz {
|
||||
!!php7
|
||||
array(
|
||||
0: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: test
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: NullableType(
|
||||
type: Name(
|
||||
@ -30,6 +34,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: NullableType(
|
||||
type: Identifier(
|
||||
|
@ -8,12 +8,16 @@ function foo($bar, ) {
|
||||
!!php7
|
||||
array(
|
||||
0: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: foo
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -42,6 +46,8 @@ class Foo
|
||||
!!php7
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: Foo
|
||||
@ -51,6 +57,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
@ -58,6 +66,8 @@ array(
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -68,6 +78,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -93,10 +105,14 @@ fn($foo, ) => $bar;
|
||||
array(
|
||||
0: Stmt_Expression(
|
||||
expr: Expr_ArrowFunction(
|
||||
attrGroups: array(
|
||||
)
|
||||
static: false
|
||||
byRef: false
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
|
@ -9,6 +9,8 @@ function test4() : Foo\Bar {}
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: test1
|
||||
@ -20,6 +22,8 @@ array(
|
||||
)
|
||||
)
|
||||
1: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: test2
|
||||
@ -33,6 +37,8 @@ array(
|
||||
)
|
||||
)
|
||||
2: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: test3
|
||||
@ -46,6 +52,8 @@ array(
|
||||
)
|
||||
)
|
||||
3: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: test4
|
||||
|
@ -9,6 +9,8 @@ function a() {
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: a
|
||||
|
@ -6,12 +6,16 @@ function a($b, array $c, callable $d, E $f) {}
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: a
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -22,6 +26,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: Identifier(
|
||||
name: array
|
||||
@ -34,6 +40,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
2: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: Identifier(
|
||||
name: callable
|
||||
@ -46,6 +54,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
3: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: Name(
|
||||
parts: array(
|
||||
|
@ -11,6 +11,8 @@ function test(A|B $a): int|false {}
|
||||
!!php7
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: Test
|
||||
@ -20,6 +22,8 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
type: UnionType(
|
||||
types: array(
|
||||
@ -48,12 +52,16 @@ array(
|
||||
)
|
||||
)
|
||||
1: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: test
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: UnionType(
|
||||
types: array(
|
||||
|
@ -8,12 +8,16 @@ function test($a, Type &... $b) {}
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: test
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -24,6 +28,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -39,12 +45,16 @@ array(
|
||||
)
|
||||
)
|
||||
1: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: test
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -55,6 +65,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: true
|
||||
@ -70,12 +82,16 @@ array(
|
||||
)
|
||||
)
|
||||
2: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: test
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -86,6 +102,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: Name(
|
||||
parts: array(
|
||||
@ -105,12 +123,16 @@ array(
|
||||
)
|
||||
)
|
||||
3: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: test
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
@ -121,6 +143,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: Name(
|
||||
parts: array(
|
||||
|
@ -6,12 +6,16 @@ function foo(...$foo = []) {}
|
||||
Variadic parameter cannot have a default value from 2:24 to 2:25
|
||||
array(
|
||||
0: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: foo
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
byRef: false
|
||||
|
@ -33,6 +33,8 @@ function gen() {
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: gen
|
||||
|
@ -17,6 +17,8 @@ function gen() {
|
||||
!!php7
|
||||
array(
|
||||
0: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: gen
|
||||
|
@ -10,6 +10,8 @@ function gen() {
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: gen
|
||||
|
@ -19,4 +19,4 @@ $a?->b($c)?->d;
|
||||
$a?->b($c)();
|
||||
new $a?->b();
|
||||
"{$a?->b}";
|
||||
"{$a}?->b";
|
||||
"{$a?->b}";
|
61
test/code/prettyPrinter/stmt/attributes.test
Normal file
61
test/code/prettyPrinter/stmt/attributes.test
Normal file
@ -0,0 +1,61 @@
|
||||
Attributes
|
||||
-----
|
||||
<?php
|
||||
|
||||
#[
|
||||
A1,
|
||||
A2(),
|
||||
A3(0),
|
||||
A4(x: 1),
|
||||
]
|
||||
function a() {
|
||||
}
|
||||
|
||||
#[A5]
|
||||
class C {
|
||||
#[A6]
|
||||
public function m(
|
||||
#[A7] $param,
|
||||
) {}
|
||||
#[A12]
|
||||
public $prop;
|
||||
}
|
||||
|
||||
#[A8]
|
||||
interface I {}
|
||||
#[A9]
|
||||
trait T {}
|
||||
|
||||
$x = #[A10] function() {};
|
||||
$y = #[A11] fn() => 0;
|
||||
new #[A13] class {};
|
||||
-----
|
||||
!!php7
|
||||
#[A1, A2, A3(0), A4(x: 1)]
|
||||
function a()
|
||||
{
|
||||
}
|
||||
#[A5]
|
||||
class C
|
||||
{
|
||||
#[A6]
|
||||
public function m(#[A7] $param)
|
||||
{
|
||||
}
|
||||
#[A12]
|
||||
public $prop;
|
||||
}
|
||||
#[A8]
|
||||
interface I
|
||||
{
|
||||
}
|
||||
#[A9]
|
||||
trait T
|
||||
{
|
||||
}
|
||||
$x = #[A10] function () {
|
||||
};
|
||||
$y = #[A11] fn() => 0;
|
||||
new #[A13] class
|
||||
{
|
||||
};
|
@ -101,6 +101,7 @@ switch ($testType) {
|
||||
| Zend.tests.bug74947
|
||||
# pretty print differences due to negative LNumbers
|
||||
| Zend.tests.neg_num_string
|
||||
| Zend.tests.numeric_strings.neg_num_string
|
||||
| Zend.tests.bug72918
|
||||
# pretty print difference due to nop statements
|
||||
| ext.mbstring.tests.htmlent
|
||||
|
Reference in New Issue
Block a user