mirror of
https://github.com/nikic/PHP-Parser.git
synced 2025-06-25 17:43:47 +02:00
Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
32cdab9a03 | |||
c2403aa729 | |||
051ad218f8 | |||
1bcbb2179f | |||
05c01865ea | |||
2a5e81f7ca | |||
e453389866 | |||
402b6cf345 | |||
54103d8387 | |||
a6303e50c9 | |||
44fc92194b | |||
844c228bf2 | |||
6d2584bdf1 | |||
21a61ece15 | |||
8f8e47b6c1 | |||
0aad06bce3 | |||
80a680bf59 | |||
cfc54e30a4 | |||
05e84f7201 | |||
73ccbabbe7 |
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -1,5 +1,6 @@
|
||||
/.github export-ignore
|
||||
/doc export-ignore
|
||||
/grammar export-ignore
|
||||
/test export-ignore
|
||||
/test_old export-ignore
|
||||
.editorconfig export-ignore
|
||||
|
14
.github/workflows/main.yml
vendored
14
.github/workflows/main.yml
vendored
@ -5,9 +5,9 @@ on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
tests_70:
|
||||
tests_71:
|
||||
runs-on: "ubuntu-latest"
|
||||
name: "PHP 7.0 Unit Tests"
|
||||
name: "PHP 7.1 Unit Tests"
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v3"
|
||||
@ -15,7 +15,7 @@ jobs:
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
with:
|
||||
coverage: "xdebug"
|
||||
php-version: "7.0"
|
||||
php-version: "7.1"
|
||||
tools: composer:v2
|
||||
- name: "Install dependencies"
|
||||
run: |
|
||||
@ -34,13 +34,13 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
php-version:
|
||||
- "7.1"
|
||||
- "7.2"
|
||||
- "7.3"
|
||||
- "7.4"
|
||||
- "8.0"
|
||||
- "8.1"
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v3"
|
||||
@ -70,9 +70,9 @@ jobs:
|
||||
run: "composer update --no-progress --prefer-dist"
|
||||
- name: "Tests"
|
||||
run: "test_old/run-php-src.sh 7.3.21"
|
||||
test_old_80_70:
|
||||
test_old_80_71:
|
||||
runs-on: "ubuntu-latest"
|
||||
name: "PHP 8.1 Code on PHP 7.0 Integration Tests"
|
||||
name: "PHP 8.1 Code on PHP 7.1 Integration Tests"
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v3"
|
||||
@ -80,7 +80,7 @@ jobs:
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
with:
|
||||
coverage: "none"
|
||||
php-version: "7.0"
|
||||
php-version: "7.1"
|
||||
tools: composer:v2
|
||||
- name: "Install PHP 8 dependencies"
|
||||
run: "composer update --no-progress --prefer-dist"
|
||||
|
47
CHANGELOG.md
47
CHANGELOG.md
@ -1,3 +1,50 @@
|
||||
Version 4.19.0 (2024-03-16)
|
||||
---------------------------
|
||||
|
||||
### Changed
|
||||
|
||||
* Do not use implicitly nullable parameters, which are deprecated in PHP 8.4.
|
||||
* Remove support for running on PHP 7.0, which does not support explicitly nullable parameters.
|
||||
|
||||
Version 4.18.0 (2023-12-10)
|
||||
---------------------------
|
||||
|
||||
### Added
|
||||
|
||||
* Added methods `ParserFactory::createForNewestSupportedVersion()` and
|
||||
`ParserFactory::createForHostVersion()` for forward-compatibility with PHP-Parser 5.0.
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fixed missing name resolution of class constant types.
|
||||
* Fixed class members being dropped if an error is encountered while parsing a later class member
|
||||
(when error recovery is enabeld).
|
||||
|
||||
### Changed
|
||||
|
||||
* The `grammar/` directory has been excluded from exported git archives.
|
||||
|
||||
Version 4.17.1 (2023-08-13)
|
||||
---------------------------
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fixed phpdoc mismatches for `ClassConst::$type` introduced in previous release.
|
||||
|
||||
Version 4.17.0 (2023-08-13)
|
||||
---------------------------
|
||||
|
||||
### Added
|
||||
|
||||
* [PHP 8.3] Added support for typed class constants.
|
||||
* [PHP 8.3] Added supprot for dynamic class constant fetch.
|
||||
* [PHP 8.3] Added support for readonly anonymous classes.
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fixed missing required parentheses when pretty printing new with an expression class name.
|
||||
* Fixed missing required parentheses when pretty printing `(CONST)::$x` and similar.
|
||||
|
||||
Version 4.16.0 (2023-06-25)
|
||||
---------------------------
|
||||
|
||||
|
@ -6,7 +6,7 @@ PHP Parser
|
||||
This is a PHP 5.2 to PHP 8.2 parser written in PHP. Its purpose is to simplify static code analysis and
|
||||
manipulation.
|
||||
|
||||
[**Documentation for version 4.x**][doc_4_x] (stable; for running on PHP >= 7.0; for parsing PHP 5.2 to PHP 8.2).
|
||||
[**Documentation for version 4.x**][doc_4_x] (stable; for running on PHP >= 7.1; for parsing PHP 5.2 to PHP 8.2).
|
||||
|
||||
[Documentation for version 3.x][doc_3_x] (unsupported; for running on PHP >= 5.5; for parsing PHP 5.2 to PHP 7.2).
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.0",
|
||||
"php": ">=7.1",
|
||||
"ext-tokenizer": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
|
@ -34,7 +34,7 @@ The parser supports parsing PHP 5.2-8.0, with the following exceptions:
|
||||
|
||||
As the parser is based on the tokens returned by `token_get_all` (which is only able to lex the PHP
|
||||
version it runs on), additionally a wrapper for emulating tokens from newer versions is provided.
|
||||
This allows to parse PHP 7.4 source code running on PHP 7.0, for example. This emulation is somewhat
|
||||
This allows to parse PHP 7.4 source code running on PHP 7.1, for example. This emulation is somewhat
|
||||
hacky and not perfect, but it should work well on any sane code.
|
||||
|
||||
What output does it produce?
|
||||
|
@ -469,7 +469,7 @@ static_var:
|
||||
;
|
||||
|
||||
class_statement_list_ex:
|
||||
class_statement_list_ex class_statement { if ($2 !== null) { push($1, $2); } }
|
||||
class_statement_list_ex class_statement { if ($2 !== null) { push($1, $2); } else { $$ = $1; } }
|
||||
| /* empty */ { init(); }
|
||||
;
|
||||
|
||||
|
@ -221,7 +221,10 @@ non_empty_class_const_list:
|
||||
;
|
||||
|
||||
class_const:
|
||||
identifier_maybe_reserved '=' expr { $$ = Node\Const_[$1, $3]; }
|
||||
T_STRING '=' expr
|
||||
{ $$ = Node\Const_[new Node\Identifier($1, stackAttributes(#1)), $3]; }
|
||||
| semi_reserved '=' expr
|
||||
{ $$ = Node\Const_[new Node\Identifier($1, stackAttributes(#1)), $3]; }
|
||||
;
|
||||
|
||||
inner_statement_list_ex:
|
||||
@ -705,7 +708,7 @@ static_var:
|
||||
;
|
||||
|
||||
class_statement_list_ex:
|
||||
class_statement_list_ex class_statement { if ($2 !== null) { push($1, $2); } }
|
||||
class_statement_list_ex class_statement { if ($2 !== null) { push($1, $2); } else { $$ = $1; } }
|
||||
| /* empty */ { init(); }
|
||||
;
|
||||
|
||||
@ -722,6 +725,9 @@ class_statement:
|
||||
| optional_attributes method_modifiers T_CONST class_const_list semi
|
||||
{ $$ = new Stmt\ClassConst($4, $2, attributes(), $1);
|
||||
$this->checkClassConst($$, #2); }
|
||||
| optional_attributes method_modifiers T_CONST type_expr class_const_list semi
|
||||
{ $$ = new Stmt\ClassConst($5, $2, attributes(), $1, $4);
|
||||
$this->checkClassConst($$, #2); }
|
||||
| optional_attributes method_modifiers T_FUNCTION optional_ref identifier_maybe_reserved '(' parameter_list ')'
|
||||
optional_return_type method_body
|
||||
{ $$ = Stmt\ClassMethod[$5, ['type' => $2, 'byRef' => $4, 'params' => $7, 'returnType' => $9, 'stmts' => $10, 'attrGroups' => $1]];
|
||||
@ -943,8 +949,8 @@ expr:
|
||||
;
|
||||
|
||||
anonymous_class:
|
||||
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);
|
||||
optional_attributes class_entry_type ctor_arguments extends_from implements_list '{' class_statement_list '}'
|
||||
{ $$ = array(Stmt\Class_[null, ['type' => $2, 'extends' => $4, 'implements' => $5, 'stmts' => $7, 'attrGroups' => $1]], $3);
|
||||
$this->checkClass($$[0], -1); }
|
||||
;
|
||||
|
||||
@ -1040,6 +1046,8 @@ constant:
|
||||
class_constant:
|
||||
class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier_maybe_reserved
|
||||
{ $$ = Expr\ClassConstFetch[$1, $3]; }
|
||||
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM '{' expr '}'
|
||||
{ $$ = Expr\ClassConstFetch[$1, $4]; }
|
||||
/* We interpret an isolated FOO:: as an unfinished class constant fetch. It could also be
|
||||
an unfinished static property fetch or unfinished scoped call. */
|
||||
| class_name_or_var T_PAAMAYIM_NEKUDOTAYIM error
|
||||
|
@ -19,6 +19,8 @@ class ClassConst implements PhpParser\Builder
|
||||
|
||||
/** @var Node\AttributeGroup[] */
|
||||
protected $attributeGroups = [];
|
||||
/** @var Identifier|Node\Name|Node\ComplexType */
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* Creates a class constant builder
|
||||
@ -116,6 +118,19 @@ class ClassConst implements PhpParser\Builder
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the constant type.
|
||||
*
|
||||
* @param string|Node\Name|Identifier|Node\ComplexType $type
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setType($type) {
|
||||
$this->type = BuilderHelpers::normalizeType($type);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the built class node.
|
||||
*
|
||||
@ -126,7 +141,8 @@ class ClassConst implements PhpParser\Builder
|
||||
$this->constants,
|
||||
$this->flags,
|
||||
$this->attributes,
|
||||
$this->attributeGroups
|
||||
$this->attributeGroups,
|
||||
$this->type
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -349,15 +349,15 @@ class BuilderFactory
|
||||
/**
|
||||
* Creates a class constant fetch node.
|
||||
*
|
||||
* @param string|Name|Expr $class Class name
|
||||
* @param string|Identifier $name Constant name
|
||||
* @param string|Name|Expr $class Class name
|
||||
* @param string|Identifier|Expr $name Constant name
|
||||
*
|
||||
* @return Expr\ClassConstFetch
|
||||
*/
|
||||
public function classConstFetch($class, $name): Expr\ClassConstFetch {
|
||||
return new Expr\ClassConstFetch(
|
||||
BuilderHelpers::normalizeNameOrExpr($class),
|
||||
BuilderHelpers::normalizeIdentifier($name)
|
||||
BuilderHelpers::normalizeIdentifierOrExpr($name)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ class ConstExprEvaluator
|
||||
*
|
||||
* @param callable|null $fallbackEvaluator To call if subexpression cannot be evaluated
|
||||
*/
|
||||
public function __construct(callable $fallbackEvaluator = null) {
|
||||
public function __construct(?callable $fallbackEvaluator = null) {
|
||||
$this->fallbackEvaluator = $fallbackEvaluator ?? function(Expr $expr) {
|
||||
throw new ConstExprEvaluationException(
|
||||
"Expression of type {$expr->getType()} cannot be evaluated"
|
||||
|
@ -19,6 +19,8 @@ class PrintableNewAnonClassNode extends Expr
|
||||
{
|
||||
/** @var Node\AttributeGroup[] PHP attribute groups */
|
||||
public $attrGroups;
|
||||
/** @var int Modifiers */
|
||||
public $flags;
|
||||
/** @var Node\Arg[] Arguments */
|
||||
public $args;
|
||||
/** @var null|Node\Name Name of extended class */
|
||||
@ -29,11 +31,12 @@ class PrintableNewAnonClassNode extends Expr
|
||||
public $stmts;
|
||||
|
||||
public function __construct(
|
||||
array $attrGroups, array $args, Node\Name $extends = null, array $implements,
|
||||
array $attrGroups, int $flags, array $args, ?Node\Name $extends = null, array $implements,
|
||||
array $stmts, array $attributes
|
||||
) {
|
||||
parent::__construct($attributes);
|
||||
$this->attrGroups = $attrGroups;
|
||||
$this->flags = $flags;
|
||||
$this->args = $args;
|
||||
$this->extends = $extends;
|
||||
$this->implements = $implements;
|
||||
@ -46,7 +49,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(
|
||||
$class->attrGroups, $newNode->args, $class->extends, $class->implements,
|
||||
$class->attrGroups, $class->flags, $newNode->args, $class->extends, $class->implements,
|
||||
$class->stmts, $newNode->getAttributes()
|
||||
);
|
||||
}
|
||||
@ -56,6 +59,6 @@ class PrintableNewAnonClassNode extends Expr
|
||||
}
|
||||
|
||||
public function getSubNodeNames() : array {
|
||||
return ['attrGroups', 'args', 'extends', 'implements', 'stmts'];
|
||||
return ['attrGroups', 'flags', 'args', 'extends', 'implements', 'stmts'];
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ class Lexer
|
||||
* @param ErrorHandler|null $errorHandler Error handler to use for lexing errors. Defaults to
|
||||
* ErrorHandler\Throwing
|
||||
*/
|
||||
public function startLexing(string $code, ErrorHandler $errorHandler = null) {
|
||||
public function startLexing(string $code, ?ErrorHandler $errorHandler = null) {
|
||||
if (null === $errorHandler) {
|
||||
$errorHandler = new ErrorHandler\Throwing();
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ class Emulative extends Lexer
|
||||
}
|
||||
}
|
||||
|
||||
public function startLexing(string $code, ErrorHandler $errorHandler = null) {
|
||||
public function startLexing(string $code, ?ErrorHandler $errorHandler = null) {
|
||||
$emulators = array_filter($this->emulators, function($emulator) use($code) {
|
||||
return $emulator->isEmulationNeeded($code);
|
||||
});
|
||||
|
@ -36,7 +36,7 @@ class NameContext
|
||||
*
|
||||
* @param Name|null $namespace Null is the global namespace
|
||||
*/
|
||||
public function startNamespace(Name $namespace = null) {
|
||||
public function startNamespace(?Name $namespace = null) {
|
||||
$this->namespace = $namespace;
|
||||
$this->origAliases = $this->aliases = [
|
||||
Stmt\Use_::TYPE_NORMAL => [],
|
||||
|
@ -27,7 +27,7 @@ class Arg extends NodeAbstract
|
||||
*/
|
||||
public function __construct(
|
||||
Expr $value, bool $byRef = false, bool $unpack = false, array $attributes = [],
|
||||
Identifier $name = null
|
||||
?Identifier $name = null
|
||||
) {
|
||||
$this->attributes = $attributes;
|
||||
$this->name = $name;
|
||||
|
@ -18,7 +18,7 @@ class ArrayDimFetch extends Expr
|
||||
* @param null|Expr $dim Array index / dim
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $var, Expr $dim = null, array $attributes = []) {
|
||||
public function __construct(Expr $var, ?Expr $dim = null, array $attributes = []) {
|
||||
$this->attributes = $attributes;
|
||||
$this->var = $var;
|
||||
$this->dim = $dim;
|
||||
|
@ -23,7 +23,7 @@ class ArrayItem extends Expr
|
||||
* @param bool $byRef Whether to assign by reference
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $value, Expr $key = null, bool $byRef = false, array $attributes = [], bool $unpack = false) {
|
||||
public function __construct(Expr $value, ?Expr $key = null, bool $byRef = false, array $attributes = [], bool $unpack = false) {
|
||||
$this->attributes = $attributes;
|
||||
$this->key = $key;
|
||||
$this->value = $value;
|
||||
|
@ -10,15 +10,15 @@ class ClassConstFetch extends Expr
|
||||
{
|
||||
/** @var Name|Expr Class name */
|
||||
public $class;
|
||||
/** @var Identifier|Error Constant name */
|
||||
/** @var Identifier|Expr|Error Constant name */
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* Constructs a class const fetch node.
|
||||
*
|
||||
* @param Name|Expr $class Class name
|
||||
* @param string|Identifier|Error $name Constant name
|
||||
* @param array $attributes Additional attributes
|
||||
* @param Name|Expr $class Class name
|
||||
* @param string|Identifier|Expr|Error $name Constant name
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($class, $name, array $attributes = []) {
|
||||
$this->attributes = $attributes;
|
||||
@ -29,7 +29,7 @@ class ClassConstFetch extends Expr
|
||||
public function getSubNodeNames() : array {
|
||||
return ['class', 'name'];
|
||||
}
|
||||
|
||||
|
||||
public function getType() : string {
|
||||
return 'Expr_ClassConstFetch';
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ class Exit_ extends Expr
|
||||
* @param null|Expr $expr Expression
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $expr = null, array $attributes = []) {
|
||||
public function __construct(?Expr $expr = null, array $attributes = []) {
|
||||
$this->attributes = $attributes;
|
||||
$this->expr = $expr;
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ class Yield_ extends Expr
|
||||
* @param null|Expr $key Key expression
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $value = null, Expr $key = null, array $attributes = []) {
|
||||
public function __construct(?Expr $value = null, ?Expr $key = null, array $attributes = []) {
|
||||
$this->attributes = $attributes;
|
||||
$this->key = $key;
|
||||
$this->value = $value;
|
||||
|
@ -162,7 +162,7 @@ class Name extends NodeAbstract
|
||||
*
|
||||
* @return static|null Sliced name
|
||||
*/
|
||||
public function slice(int $offset, int $length = null) {
|
||||
public function slice(int $offset, ?int $length = null) {
|
||||
$numParts = count($this->parts);
|
||||
|
||||
$realOffset = $offset < 0 ? $offset + $numParts : $offset;
|
||||
|
@ -34,7 +34,7 @@ class Param extends NodeAbstract
|
||||
* @param AttributeGroup[] $attrGroups PHP attribute groups
|
||||
*/
|
||||
public function __construct(
|
||||
$var, Expr $default = null, $type = null,
|
||||
$var, ?Expr $default = null, $type = null,
|
||||
bool $byRef = false, bool $variadic = false,
|
||||
array $attributes = [],
|
||||
int $flags = 0,
|
||||
|
@ -15,7 +15,7 @@ class Break_ extends Node\Stmt
|
||||
* @param null|Node\Expr $num Number of loops to break
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Node\Expr $num = null, array $attributes = []) {
|
||||
public function __construct(?Node\Expr $num = null, array $attributes = []) {
|
||||
$this->attributes = $attributes;
|
||||
$this->num = $num;
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ class Catch_ extends Node\Stmt
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(
|
||||
array $types, Expr\Variable $var = null, array $stmts = [], array $attributes = []
|
||||
array $types, ?Expr\Variable $var = null, array $stmts = [], array $attributes = []
|
||||
) {
|
||||
$this->attributes = $attributes;
|
||||
$this->types = $types;
|
||||
|
@ -10,31 +10,36 @@ class ClassConst extends Node\Stmt
|
||||
public $flags;
|
||||
/** @var Node\Const_[] Constant declarations */
|
||||
public $consts;
|
||||
/** @var Node\AttributeGroup[] */
|
||||
/** @var Node\AttributeGroup[] PHP attribute groups */
|
||||
public $attrGroups;
|
||||
/** @var Node\Identifier|Node\Name|Node\ComplexType|null Type declaration */
|
||||
public $type;
|
||||
|
||||
/**
|
||||
* Constructs a class const list node.
|
||||
*
|
||||
* @param Node\Const_[] $consts Constant declarations
|
||||
* @param int $flags Modifiers
|
||||
* @param array $attributes Additional attributes
|
||||
* @param Node\AttributeGroup[] $attrGroups PHP attribute groups
|
||||
* @param Node\Const_[] $consts Constant declarations
|
||||
* @param int $flags Modifiers
|
||||
* @param array $attributes Additional attributes
|
||||
* @param Node\AttributeGroup[] $attrGroups PHP attribute groups
|
||||
* @param null|string|Node\Identifier|Node\Name|Node\ComplexType $type Type declaration
|
||||
*/
|
||||
public function __construct(
|
||||
array $consts,
|
||||
int $flags = 0,
|
||||
array $attributes = [],
|
||||
array $attrGroups = []
|
||||
array $attrGroups = [],
|
||||
$type = null
|
||||
) {
|
||||
$this->attributes = $attributes;
|
||||
$this->flags = $flags;
|
||||
$this->consts = $consts;
|
||||
$this->attrGroups = $attrGroups;
|
||||
$this->type = \is_string($type) ? new Node\Identifier($type) : $type;
|
||||
}
|
||||
|
||||
public function getSubNodeNames() : array {
|
||||
return ['attrGroups', 'flags', 'consts'];
|
||||
return ['attrGroups', 'flags', 'type', 'consts'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -15,7 +15,7 @@ class Continue_ extends Node\Stmt
|
||||
* @param null|Node\Expr $num Number of loops to continue
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Node\Expr $num = null, array $attributes = []) {
|
||||
public function __construct(?Node\Expr $num = null, array $attributes = []) {
|
||||
$this->attributes = $attributes;
|
||||
$this->num = $num;
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ class Declare_ extends Node\Stmt
|
||||
* @param Node\Stmt[]|null $stmts Statements
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(array $declares, array $stmts = null, array $attributes = []) {
|
||||
public function __construct(array $declares, ?array $stmts = null, array $attributes = []) {
|
||||
$this->attributes = $attributes;
|
||||
$this->declares = $declares;
|
||||
$this->stmts = $stmts;
|
||||
|
@ -20,7 +20,7 @@ class EnumCase extends Node\Stmt
|
||||
* @param AttributeGroup[] $attrGroups PHP attribute groups
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($name, Node\Expr $expr = null, array $attrGroups = [], array $attributes = []) {
|
||||
public function __construct($name, ?Node\Expr $expr = null, array $attrGroups = [], array $attributes = []) {
|
||||
parent::__construct($attributes);
|
||||
$this->name = \is_string($name) ? new Node\Identifier($name) : $name;
|
||||
$this->expr = $expr;
|
||||
|
@ -22,7 +22,7 @@ class Namespace_ extends Node\Stmt
|
||||
* @param null|Node\Stmt[] $stmts Statements
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Node\Name $name = null, $stmts = [], array $attributes = []) {
|
||||
public function __construct(?Node\Name $name = null, $stmts = [], array $attributes = []) {
|
||||
$this->attributes = $attributes;
|
||||
$this->name = $name;
|
||||
$this->stmts = $stmts;
|
||||
|
@ -18,7 +18,7 @@ class PropertyProperty extends Node\Stmt
|
||||
* @param null|Node\Expr $default Default value
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($name, Node\Expr $default = null, array $attributes = []) {
|
||||
public function __construct($name, ?Node\Expr $default = null, array $attributes = []) {
|
||||
$this->attributes = $attributes;
|
||||
$this->name = \is_string($name) ? new Node\VarLikeIdentifier($name) : $name;
|
||||
$this->default = $default;
|
||||
|
@ -15,7 +15,7 @@ class Return_ extends Node\Stmt
|
||||
* @param null|Node\Expr $expr Expression
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Node\Expr $expr = null, array $attributes = []) {
|
||||
public function __construct(?Node\Expr $expr = null, array $attributes = []) {
|
||||
$this->attributes = $attributes;
|
||||
$this->expr = $expr;
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ class StaticVar extends Node\Stmt
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(
|
||||
Expr\Variable $var, Node\Expr $default = null, array $attributes = []
|
||||
Expr\Variable $var, ?Node\Expr $default = null, array $attributes = []
|
||||
) {
|
||||
$this->attributes = $attributes;
|
||||
$this->var = $var;
|
||||
|
@ -21,7 +21,7 @@ class TryCatch extends Node\Stmt
|
||||
* @param null|Finally_ $finally Optional finally node
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(array $stmts, array $catches, Finally_ $finally = null, array $attributes = []) {
|
||||
public function __construct(array $stmts, array $catches, ?Finally_ $finally = null, array $attributes = []) {
|
||||
$this->attributes = $attributes;
|
||||
$this->stmts = $stmts;
|
||||
$this->catches = $catches;
|
||||
|
@ -39,7 +39,7 @@ class NodeDumper
|
||||
*
|
||||
* @return string Dumped value
|
||||
*/
|
||||
public function dump($node, string $code = null) : string {
|
||||
public function dump($node, ?string $code = null) : string {
|
||||
$this->code = $code;
|
||||
return $this->dumpRecursive($node);
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ class NameResolver extends NodeVisitorAbstract
|
||||
* @param ErrorHandler|null $errorHandler Error handler
|
||||
* @param array $options Options
|
||||
*/
|
||||
public function __construct(ErrorHandler $errorHandler = null, array $options = []) {
|
||||
public function __construct(?ErrorHandler $errorHandler = null, array $options = []) {
|
||||
$this->nameContext = new NameContext($errorHandler ?? new ErrorHandler\Throwing);
|
||||
$this->preserveOriginalNames = $options['preserveOriginalNames'] ?? false;
|
||||
$this->replaceNodes = $options['replaceNodes'] ?? true;
|
||||
@ -118,6 +118,9 @@ class NameResolver extends NodeVisitorAbstract
|
||||
$this->addNamespacedName($const);
|
||||
}
|
||||
} else if ($node instanceof Stmt\ClassConst) {
|
||||
if (null !== $node->type) {
|
||||
$node->type = $this->resolveType($node->type);
|
||||
}
|
||||
$this->resolveAttrGroups($node);
|
||||
} else if ($node instanceof Stmt\EnumCase) {
|
||||
$this->resolveAttrGroups($node);
|
||||
@ -161,7 +164,7 @@ class NameResolver extends NodeVisitorAbstract
|
||||
return null;
|
||||
}
|
||||
|
||||
private function addAlias(Stmt\UseUse $use, int $type, Name $prefix = null) {
|
||||
private function addAlias(Stmt\UseUse $use, int $type, ?Name $prefix = null) {
|
||||
// Add prefix for group uses
|
||||
$name = $prefix ? Name::concat($prefix, $use->name) : $use->name;
|
||||
// Type is determined either by individual element or whole use declaration
|
||||
|
@ -14,5 +14,5 @@ interface Parser
|
||||
* @return Node\Stmt[]|null Array of statements (or null non-throwing error handler is used and
|
||||
* the parser was unable to recover from an error).
|
||||
*/
|
||||
public function parse(string $code, ErrorHandler $errorHandler = null);
|
||||
public function parse(string $code, ?ErrorHandler $errorHandler = null);
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ class Multiple implements Parser
|
||||
$this->parsers = $parsers;
|
||||
}
|
||||
|
||||
public function parse(string $code, ErrorHandler $errorHandler = null) {
|
||||
public function parse(string $code, ?ErrorHandler $errorHandler = null) {
|
||||
if (null === $errorHandler) {
|
||||
$errorHandler = new ErrorHandler\Throwing;
|
||||
}
|
||||
|
@ -1738,7 +1738,7 @@ class Php5 extends \PhpParser\ParserAbstract
|
||||
$this->semValue = new Stmt\StaticVar($this->semStack[$stackPos-(3-1)], $this->semStack[$stackPos-(3-3)], $this->startAttributeStack[$stackPos-(3-1)] + $this->endAttributes);
|
||||
},
|
||||
259 => function ($stackPos) {
|
||||
if ($this->semStack[$stackPos-(2-2)] !== null) { $this->semStack[$stackPos-(2-1)][] = $this->semStack[$stackPos-(2-2)]; $this->semValue = $this->semStack[$stackPos-(2-1)]; }
|
||||
if ($this->semStack[$stackPos-(2-2)] !== null) { $this->semStack[$stackPos-(2-1)][] = $this->semStack[$stackPos-(2-2)]; $this->semValue = $this->semStack[$stackPos-(2-1)]; } else { $this->semValue = $this->semStack[$stackPos-(2-1)]; }
|
||||
},
|
||||
260 => function ($stackPos) {
|
||||
$this->semValue = array();
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -155,7 +155,7 @@ abstract class ParserAbstract implements Parser
|
||||
* @return Node\Stmt[]|null Array of statements (or null non-throwing error handler is used and
|
||||
* the parser was unable to recover from an error).
|
||||
*/
|
||||
public function parse(string $code, ErrorHandler $errorHandler = null) {
|
||||
public function parse(string $code, ?ErrorHandler $errorHandler = null) {
|
||||
$this->errorHandler = $errorHandler ?: new ErrorHandler\Throwing;
|
||||
|
||||
$this->lexer->startLexing($code, $this->errorHandler);
|
||||
|
@ -2,6 +2,9 @@
|
||||
|
||||
namespace PhpParser;
|
||||
|
||||
use PhpParser\Lexer\Emulative;
|
||||
use PhpParser\Parser\Php7;
|
||||
|
||||
class ParserFactory
|
||||
{
|
||||
const PREFER_PHP7 = 1;
|
||||
@ -18,7 +21,7 @@ class ParserFactory
|
||||
*
|
||||
* @return Parser The parser instance
|
||||
*/
|
||||
public function create(int $kind, Lexer $lexer = null, array $parserOptions = []) : Parser {
|
||||
public function create(int $kind, ?Lexer $lexer = null, array $parserOptions = []) : Parser {
|
||||
if (null === $lexer) {
|
||||
$lexer = new Lexer\Emulative();
|
||||
}
|
||||
@ -41,4 +44,33 @@ class ParserFactory
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a parser targeting the newest version supported by this library. Code for older
|
||||
* versions will be accepted if there have been no relevant backwards-compatibility breaks in
|
||||
* PHP.
|
||||
*
|
||||
* All supported lexer attributes (comments, startLine, endLine, startTokenPos, endTokenPos,
|
||||
* startFilePos, endFilePos) will be enabled.
|
||||
*/
|
||||
public function createForNewestSupportedVersion(): Parser {
|
||||
return new Php7(new Emulative($this->getLexerOptions()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a parser targeting the host PHP version, that is the PHP version we're currently
|
||||
* running on. This parser will not use any token emulation.
|
||||
*
|
||||
* All supported lexer attributes (comments, startLine, endLine, startTokenPos, endTokenPos,
|
||||
* startFilePos, endFilePos) will be enabled.
|
||||
*/
|
||||
public function createForHostVersion(): Parser {
|
||||
return new Php7(new Lexer($this->getLexerOptions()));
|
||||
}
|
||||
|
||||
private function getLexerOptions(): array {
|
||||
return ['usedAttributes' => [
|
||||
'comments', 'startLine', 'endLine', 'startTokenPos', 'endTokenPos', 'startFilePos', 'endFilePos',
|
||||
]];
|
||||
}
|
||||
}
|
||||
|
@ -529,7 +529,7 @@ class Standard extends PrettyPrinterAbstract
|
||||
}
|
||||
|
||||
protected function pExpr_StaticCall(Expr\StaticCall $node) {
|
||||
return $this->pDereferenceLhs($node->class) . '::'
|
||||
return $this->pStaticDereferenceLhs($node->class) . '::'
|
||||
. ($node->name instanceof Expr
|
||||
? ($node->name instanceof Expr\Variable
|
||||
? $this->p($node->name)
|
||||
@ -606,7 +606,7 @@ class Standard extends PrettyPrinterAbstract
|
||||
}
|
||||
|
||||
protected function pExpr_ClassConstFetch(Expr\ClassConstFetch $node) {
|
||||
return $this->pDereferenceLhs($node->class) . '::' . $this->p($node->name);
|
||||
return $this->pStaticDereferenceLhs($node->class) . '::' . $this->pObjectProperty($node->name);
|
||||
}
|
||||
|
||||
protected function pExpr_PropertyFetch(Expr\PropertyFetch $node) {
|
||||
@ -618,7 +618,7 @@ class Standard extends PrettyPrinterAbstract
|
||||
}
|
||||
|
||||
protected function pExpr_StaticPropertyFetch(Expr\StaticPropertyFetch $node) {
|
||||
return $this->pDereferenceLhs($node->class) . '::$' . $this->pObjectProperty($node->name);
|
||||
return $this->pStaticDereferenceLhs($node->class) . '::$' . $this->pObjectProperty($node->name);
|
||||
}
|
||||
|
||||
protected function pExpr_ShellExec(Expr\ShellExec $node) {
|
||||
@ -814,7 +814,9 @@ class Standard extends PrettyPrinterAbstract
|
||||
protected function pStmt_ClassConst(Stmt\ClassConst $node) {
|
||||
return $this->pAttrGroups($node->attrGroups)
|
||||
. $this->pModifiers($node->flags)
|
||||
. 'const ' . $this->pCommaSeparated($node->consts) . ';';
|
||||
. 'const '
|
||||
. (null !== $node->type ? $this->p($node->type) . ' ' : '')
|
||||
. $this->pCommaSeparated($node->consts) . ';';
|
||||
}
|
||||
|
||||
protected function pStmt_Function(Stmt\Function_ $node) {
|
||||
@ -1067,6 +1069,14 @@ class Standard extends PrettyPrinterAbstract
|
||||
}
|
||||
}
|
||||
|
||||
protected function pStaticDereferenceLhs(Node $node) {
|
||||
if (!$this->staticDereferenceLhsRequiresParens($node)) {
|
||||
return $this->p($node);
|
||||
} else {
|
||||
return '(' . $this->p($node) . ')';
|
||||
}
|
||||
}
|
||||
|
||||
protected function pCallLhs(Node $node) {
|
||||
if (!$this->callLhsRequiresParens($node)) {
|
||||
return $this->p($node);
|
||||
@ -1075,9 +1085,12 @@ class Standard extends PrettyPrinterAbstract
|
||||
}
|
||||
}
|
||||
|
||||
protected function pNewVariable(Node $node) {
|
||||
// TODO: This is not fully accurate.
|
||||
return $this->pDereferenceLhs($node);
|
||||
protected function pNewVariable(Node $node): string {
|
||||
if (!$this->newOperandRequiresParens($node)) {
|
||||
return $this->p($node);
|
||||
} else {
|
||||
return '(' . $this->p($node) . ')';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21,6 +21,8 @@ abstract class PrettyPrinterAbstract
|
||||
const FIXUP_BRACED_NAME = 4; // Name operand that may require bracing
|
||||
const FIXUP_VAR_BRACED_NAME = 5; // Name operand that may require ${} bracing
|
||||
const FIXUP_ENCAPSED = 6; // Encapsed string part
|
||||
const FIXUP_NEW = 7; // New/instanceof operand
|
||||
const FIXUP_STATIC_DEREF_LHS = 8; // LHS of static dereferencing operation
|
||||
|
||||
protected $precedenceMap = [
|
||||
// [precedence, associativity]
|
||||
@ -977,6 +979,19 @@ abstract class PrettyPrinterAbstract
|
||||
return '(' . $this->p($subNode) . ')';
|
||||
}
|
||||
break;
|
||||
case self::FIXUP_STATIC_DEREF_LHS:
|
||||
if ($this->staticDereferenceLhsRequiresParens($subNode)
|
||||
&& !$this->origTokens->haveParens($subStartPos, $subEndPos)
|
||||
) {
|
||||
return '(' . $this->p($subNode) . ')';
|
||||
}
|
||||
break;
|
||||
case self::FIXUP_NEW:
|
||||
if ($this->newOperandRequiresParens($subNode)
|
||||
&& !$this->origTokens->haveParens($subStartPos, $subEndPos)) {
|
||||
return '(' . $this->p($subNode) . ')';
|
||||
}
|
||||
break;
|
||||
case self::FIXUP_BRACED_NAME:
|
||||
case self::FIXUP_VAR_BRACED_NAME:
|
||||
if ($subNode instanceof Expr
|
||||
@ -1047,13 +1062,26 @@ abstract class PrettyPrinterAbstract
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the LHS of a dereferencing operation must be wrapped in parenthesis.
|
||||
* Determines whether the LHS of an array/object operation must be wrapped in parentheses.
|
||||
*
|
||||
* @param Node $node LHS of dereferencing operation
|
||||
*
|
||||
* @return bool Whether parentheses are required
|
||||
*/
|
||||
protected function dereferenceLhsRequiresParens(Node $node) : bool {
|
||||
// A constant can occur on the LHS of an array/object deref, but not a static deref.
|
||||
return $this->staticDereferenceLhsRequiresParens($node)
|
||||
&& !$node instanceof Expr\ConstFetch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the LHS of a static operation must be wrapped in parentheses.
|
||||
*
|
||||
* @param Node $node LHS of dereferencing operation
|
||||
*
|
||||
* @return bool Whether parentheses are required
|
||||
*/
|
||||
protected function staticDereferenceLhsRequiresParens(Node $node): bool {
|
||||
return !($node instanceof Expr\Variable
|
||||
|| $node instanceof Node\Name
|
||||
|| $node instanceof Expr\ArrayDimFetch
|
||||
@ -1066,10 +1094,31 @@ abstract class PrettyPrinterAbstract
|
||||
|| $node instanceof Expr\StaticCall
|
||||
|| $node instanceof Expr\Array_
|
||||
|| $node instanceof Scalar\String_
|
||||
|| $node instanceof Expr\ConstFetch
|
||||
|| $node instanceof Expr\ClassConstFetch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether an expression used in "new" or "instanceof" requires parentheses.
|
||||
*
|
||||
* @param Node $node New or instanceof operand
|
||||
*
|
||||
* @return bool Whether parentheses are required
|
||||
*/
|
||||
protected function newOperandRequiresParens(Node $node): bool {
|
||||
if ($node instanceof Node\Name || $node instanceof Expr\Variable) {
|
||||
return false;
|
||||
}
|
||||
if ($node instanceof Expr\ArrayDimFetch || $node instanceof Expr\PropertyFetch ||
|
||||
$node instanceof Expr\NullsafePropertyFetch
|
||||
) {
|
||||
return $this->newOperandRequiresParens($node->var);
|
||||
}
|
||||
if ($node instanceof Expr\StaticPropertyFetch) {
|
||||
return $this->newOperandRequiresParens($node->class);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print modifiers, including trailing whitespace.
|
||||
*
|
||||
@ -1171,7 +1220,7 @@ abstract class PrettyPrinterAbstract
|
||||
Expr\PostDec::class => ['var' => self::FIXUP_PREC_LEFT],
|
||||
Expr\Instanceof_::class => [
|
||||
'expr' => self::FIXUP_PREC_LEFT,
|
||||
'class' => self::FIXUP_PREC_RIGHT, // TODO: FIXUP_NEW_VARIABLE
|
||||
'class' => self::FIXUP_NEW,
|
||||
],
|
||||
Expr\Ternary::class => [
|
||||
'cond' => self::FIXUP_PREC_LEFT,
|
||||
@ -1179,10 +1228,13 @@ abstract class PrettyPrinterAbstract
|
||||
],
|
||||
|
||||
Expr\FuncCall::class => ['name' => self::FIXUP_CALL_LHS],
|
||||
Expr\StaticCall::class => ['class' => self::FIXUP_DEREF_LHS],
|
||||
Expr\StaticCall::class => ['class' => self::FIXUP_STATIC_DEREF_LHS],
|
||||
Expr\ArrayDimFetch::class => ['var' => self::FIXUP_DEREF_LHS],
|
||||
Expr\ClassConstFetch::class => ['var' => self::FIXUP_DEREF_LHS],
|
||||
Expr\New_::class => ['class' => self::FIXUP_DEREF_LHS], // TODO: FIXUP_NEW_VARIABLE
|
||||
Expr\ClassConstFetch::class => [
|
||||
'class' => self::FIXUP_STATIC_DEREF_LHS,
|
||||
'name' => self::FIXUP_BRACED_NAME,
|
||||
],
|
||||
Expr\New_::class => ['class' => self::FIXUP_NEW],
|
||||
Expr\MethodCall::class => [
|
||||
'var' => self::FIXUP_DEREF_LHS,
|
||||
'name' => self::FIXUP_BRACED_NAME,
|
||||
@ -1192,7 +1244,7 @@ abstract class PrettyPrinterAbstract
|
||||
'name' => self::FIXUP_BRACED_NAME,
|
||||
],
|
||||
Expr\StaticPropertyFetch::class => [
|
||||
'class' => self::FIXUP_DEREF_LHS,
|
||||
'class' => self::FIXUP_STATIC_DEREF_LHS,
|
||||
'name' => self::FIXUP_VAR_BRACED_NAME,
|
||||
],
|
||||
Expr\PropertyFetch::class => [
|
||||
@ -1278,6 +1330,7 @@ abstract class PrettyPrinterAbstract
|
||||
'Param->default' => $stripEquals,
|
||||
'Stmt_Break->num' => $stripBoth,
|
||||
'Stmt_Catch->var' => $stripLeft,
|
||||
'Stmt_ClassConst->type' => $stripRight,
|
||||
'Stmt_ClassMethod->returnType' => $stripColon,
|
||||
'Stmt_Class->extends' => ['left' => \T_EXTENDS],
|
||||
'Stmt_Enum->scalarType' => $stripColon,
|
||||
@ -1319,6 +1372,7 @@ abstract class PrettyPrinterAbstract
|
||||
'Stmt_Break->num' => [\T_BREAK, false, ' ', null],
|
||||
'Stmt_Catch->var' => [null, false, ' ', null],
|
||||
'Stmt_ClassMethod->returnType' => [')', false, ' : ', null],
|
||||
'Stmt_ClassConst->type' => [\T_CONST, false, ' ', null],
|
||||
'Stmt_Class->extends' => [null, false, ' extends ', null],
|
||||
'Stmt_Enum->scalarType' => [null, false, ' : ', null],
|
||||
'Stmt_EnumCase->expr' => [null, false, ' = ', null],
|
||||
@ -1508,6 +1562,7 @@ abstract class PrettyPrinterAbstract
|
||||
'Stmt_ClassMethod->flags' => \T_FUNCTION,
|
||||
'Stmt_Class->flags' => \T_CLASS,
|
||||
'Stmt_Property->flags' => \T_VARIABLE,
|
||||
'Expr_PrintableNewAnonClass->flags' => \T_CLASS,
|
||||
'Param->flags' => \T_VARIABLE,
|
||||
//'Stmt_TraitUseAdaptation_Alias->newModifier' => 0, // TODO
|
||||
];
|
||||
|
@ -142,6 +142,18 @@ class ClassConstTest extends \PHPUnit\Framework\TestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function testType() {
|
||||
$node = $this->createClassConstBuilder('TYPE', 1)
|
||||
->setType('int')
|
||||
->getNode();
|
||||
$this->assertEquals(
|
||||
new Stmt\ClassConst(
|
||||
[new Const_('TYPE', new LNumber(1))],
|
||||
0, [], [], new Identifier('int')),
|
||||
$node
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideTestDefaultValues
|
||||
*/
|
||||
|
@ -210,6 +210,10 @@ class BuilderFactoryTest extends \PHPUnit\Framework\TestCase
|
||||
new Expr\ClassConstFetch(new Expr\Variable('foo'), new Identifier('BAR')),
|
||||
$factory->classConstFetch(new Expr\Variable('foo'), 'BAR')
|
||||
);
|
||||
$this->assertEquals(
|
||||
new Expr\ClassConstFetch(new Name('Foo'), new Expr\Variable('foo')),
|
||||
$factory->classConstFetch('Foo', $factory->var('foo'))
|
||||
);
|
||||
}
|
||||
|
||||
public function testVar() {
|
||||
@ -243,7 +247,7 @@ class BuilderFactoryTest extends \PHPUnit\Framework\TestCase
|
||||
public function testInvalidIdentifier() {
|
||||
$this->expectException(\LogicException::class);
|
||||
$this->expectExceptionMessage('Expected string or instance of Node\Identifier');
|
||||
(new BuilderFactory())->classConstFetch('Foo', new Expr\Variable('foo'));
|
||||
(new BuilderFactory())->classConstFetch('Foo', new Name('foo'));
|
||||
}
|
||||
|
||||
public function testInvalidIdentifierOrExpr() {
|
||||
|
@ -189,7 +189,7 @@ class A extends B implements C, D {
|
||||
E::h as i;
|
||||
E::j insteadof F, G;
|
||||
}
|
||||
|
||||
|
||||
#[X]
|
||||
public float $php = 7.4;
|
||||
public ?Foo $person;
|
||||
@ -198,6 +198,10 @@ class A extends B implements C, D {
|
||||
|
||||
#[X]
|
||||
const C = 1;
|
||||
|
||||
public const X A = X::Bar;
|
||||
public const X\Foo B = X\Foo::Bar;
|
||||
public const \X\Foo C = \X\Foo::Bar;
|
||||
}
|
||||
|
||||
#[X]
|
||||
@ -263,6 +267,9 @@ class A extends \NS\B implements \NS\C, \NS\D
|
||||
public \NS\A|\NS\B|int $prop;
|
||||
#[\NS\X]
|
||||
const C = 1;
|
||||
public const \NS\X A = \NS\X::Bar;
|
||||
public const \NS\X\Foo B = \NS\X\Foo::Bar;
|
||||
public const \X\Foo C = \X\Foo::Bar;
|
||||
}
|
||||
#[\NS\X]
|
||||
interface A extends \NS\C, \NS\D
|
||||
|
@ -5,6 +5,8 @@ namespace PhpParser;
|
||||
/* This test is very weak, because PHPUnit's assertEquals assertion is way too slow dealing with the
|
||||
* large objects involved here. So we just do some basic instanceof tests instead. */
|
||||
|
||||
use PhpParser\Node\Stmt\Echo_;
|
||||
|
||||
class ParserFactoryTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
/** @dataProvider provideTestCreate */
|
||||
@ -33,4 +35,26 @@ class ParserFactoryTest extends \PHPUnit\Framework\TestCase
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/** @dataProvider provideTestLexerAttributes */
|
||||
public function testLexerAttributes(Parser $parser) {
|
||||
$stmts = $parser->parse("<?php /* Bar */ echo 'Foo';");
|
||||
$stmt = $stmts[0];
|
||||
$this->assertInstanceOf(Echo_::class, $stmt);
|
||||
$this->assertCount(1, $stmt->getComments());
|
||||
$this->assertSame(1, $stmt->getStartLine());
|
||||
$this->assertSame(1, $stmt->getEndLine());
|
||||
$this->assertSame(3, $stmt->getStartTokenPos());
|
||||
$this->assertSame(6, $stmt->getEndTokenPos());
|
||||
$this->assertSame(16, $stmt->getStartFilePos());
|
||||
$this->assertSame(26, $stmt->getEndFilePos());
|
||||
}
|
||||
|
||||
public function provideTestLexerAttributes() {
|
||||
$factory = new ParserFactory();
|
||||
return [
|
||||
[$factory->createForHostVersion()],
|
||||
[$factory->createForNewestSupportedVersion()],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,12 @@ $foo -> bar;
|
||||
$foo -> bar;
|
||||
self :: $foo;
|
||||
self :: $foo;
|
||||
new Foo();
|
||||
$x instanceof Foo;
|
||||
Foo :: bar;
|
||||
Foo :: $bar;
|
||||
Foo :: bar();
|
||||
Foo :: bar;
|
||||
-----
|
||||
$stmts[0]->expr->name = new Expr\Variable('a');
|
||||
$stmts[1]->expr->name = new Expr\BinaryOp\Concat(new Expr\Variable('a'), new Expr\Variable('b'));
|
||||
@ -54,6 +60,12 @@ $stmts[5]->expr->name = new Expr\Variable('bar');
|
||||
$stmts[6]->expr->name = new Expr\BinaryOp\Concat(new Expr\Variable('a'), new Expr\Variable('b'));
|
||||
$stmts[7]->expr->name = new Node\VarLikeIdentifier('bar');
|
||||
$stmts[8]->expr->name = new Expr\BinaryOp\Concat(new Expr\Variable('a'), new Expr\Variable('b'));
|
||||
$stmts[9]->expr->class = new Scalar\String_('Foo');
|
||||
$stmts[10]->expr->class = new Scalar\String_('Foo');
|
||||
$stmts[11]->expr->class = new Expr\ConstFetch(new Node\Name('FOO'));
|
||||
$stmts[12]->expr->class = new Expr\ConstFetch(new Node\Name('FOO'));
|
||||
$stmts[13]->expr->class = new Expr\ConstFetch(new Node\Name('FOO'));
|
||||
$stmts[14]->expr->name = new Expr\Variable('bar');
|
||||
-----
|
||||
<?php
|
||||
$a ();
|
||||
@ -64,4 +76,10 @@ $foo -> foo;
|
||||
$foo -> {$bar};
|
||||
$foo -> {$a . $b};
|
||||
self :: $bar;
|
||||
self :: ${$a . $b};
|
||||
self :: ${$a . $b};
|
||||
new ('Foo')();
|
||||
$x instanceof ('Foo');
|
||||
(FOO) :: bar;
|
||||
(FOO) :: $bar;
|
||||
(FOO) :: bar();
|
||||
Foo :: {$bar};
|
||||
|
@ -49,6 +49,10 @@ X
|
||||
private
|
||||
$x
|
||||
;
|
||||
|
||||
const
|
||||
X
|
||||
= 1;
|
||||
}
|
||||
|
||||
foreach (
|
||||
@ -86,6 +90,7 @@ $stmts[9]->expr = new Expr\Variable('x');
|
||||
$stmts[10]->extends = new Node\Name\FullyQualified('Bar');
|
||||
$stmts[10]->stmts[0]->returnType = new Node\Name('Y');
|
||||
$stmts[10]->stmts[1]->props[0]->default = new Scalar\DNumber(42.0);
|
||||
$stmts[10]->stmts[2]->type = new Node\Identifier('int');
|
||||
$stmts[11]->keyVar = new Expr\Variable('z');
|
||||
$stmts[12]->vars[0]->default = new Scalar\String_('abc');
|
||||
$stmts[13]->finally = new Stmt\Finally_([]);
|
||||
@ -140,6 +145,10 @@ X extends \Bar
|
||||
private
|
||||
$x = 42.0
|
||||
;
|
||||
|
||||
const int
|
||||
X
|
||||
= 1;
|
||||
}
|
||||
|
||||
foreach (
|
||||
|
@ -54,4 +54,15 @@ function test(
|
||||
= 'z',
|
||||
public T3 $z
|
||||
= 'x',
|
||||
) {}
|
||||
) {}
|
||||
-----
|
||||
<?php
|
||||
new class {};
|
||||
new readonly class {};
|
||||
-----
|
||||
$stmts[0]->expr->class->flags = Stmt\Class_::MODIFIER_READONLY;
|
||||
$stmts[1]->expr->class->flags = 0;
|
||||
-----
|
||||
<?php
|
||||
readonly class {};
|
||||
class {};
|
||||
|
@ -35,6 +35,11 @@ Bar
|
||||
y
|
||||
;
|
||||
}
|
||||
|
||||
const
|
||||
int
|
||||
X
|
||||
= 1;
|
||||
}
|
||||
|
||||
$foo [ $bar ];
|
||||
@ -97,6 +102,7 @@ $stmts[2]->extends = null;
|
||||
$stmts[2]->stmts[0]->returnType = null;
|
||||
$stmts[2]->stmts[1]->props[0]->default = null;
|
||||
$stmts[2]->stmts[2]->adaptations[0]->newName = null;
|
||||
$stmts[2]->stmts[3]->type = null;
|
||||
$stmts[3]->expr->dim = null;
|
||||
$stmts[4]->expr->expr = null;
|
||||
$stmts[5]->expr->if = null;
|
||||
@ -141,6 +147,10 @@ Foo
|
||||
public
|
||||
;
|
||||
}
|
||||
|
||||
const
|
||||
X
|
||||
= 1;
|
||||
}
|
||||
|
||||
$foo [];
|
||||
|
@ -745,6 +745,7 @@ array(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
consts: array(
|
||||
0: Const(
|
||||
name: Identifier(
|
||||
@ -899,12 +900,13 @@ array(
|
||||
<?php
|
||||
|
||||
class Foo {
|
||||
public $bar1;
|
||||
publi $foo;
|
||||
public $bar;
|
||||
}
|
||||
-----
|
||||
!!php7
|
||||
Syntax error, unexpected T_STRING from 4:5 to 4:9
|
||||
Syntax error, unexpected T_STRING from 5:5 to 5:9
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
@ -918,6 +920,20 @@ array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
type: null
|
||||
props: array(
|
||||
0: Stmt_PropertyProperty(
|
||||
name: VarLikeIdentifier(
|
||||
name: bar1
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
)
|
||||
1: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
@ -1508,6 +1524,7 @@ array(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
consts: array(
|
||||
0: Const(
|
||||
name: Identifier(
|
||||
@ -1521,4 +1538,4 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
43
test/code/parser/expr/dynamicClassConst.test
Normal file
43
test/code/parser/expr/dynamicClassConst.test
Normal file
@ -0,0 +1,43 @@
|
||||
Dynamic class constant fetch
|
||||
-----
|
||||
<?php
|
||||
Foo::{bar()};
|
||||
$foo::{bar()};
|
||||
-----
|
||||
!!php7
|
||||
array(
|
||||
0: Stmt_Expression(
|
||||
expr: Expr_ClassConstFetch(
|
||||
class: Name(
|
||||
parts: array(
|
||||
0: Foo
|
||||
)
|
||||
)
|
||||
name: Expr_FuncCall(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: bar
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
1: Stmt_Expression(
|
||||
expr: Expr_ClassConstFetch(
|
||||
class: Expr_Variable(
|
||||
name: foo
|
||||
)
|
||||
name: Expr_FuncCall(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: bar
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
@ -152,6 +152,7 @@ array(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
consts: array(
|
||||
0: Const(
|
||||
name: Identifier(
|
||||
@ -175,6 +176,7 @@ array(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
consts: array(
|
||||
0: Const(
|
||||
name: Identifier(
|
||||
|
@ -205,6 +205,7 @@ array(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
consts: array(
|
||||
0: Const(
|
||||
name: Identifier(
|
||||
|
@ -23,6 +23,7 @@ array(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_STATIC (8)
|
||||
type: null
|
||||
consts: array(
|
||||
0: Const(
|
||||
name: Identifier(
|
||||
@ -61,6 +62,7 @@ array(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_ABSTRACT (16)
|
||||
type: null
|
||||
consts: array(
|
||||
0: Const(
|
||||
name: Identifier(
|
||||
@ -99,6 +101,7 @@ array(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_READONLY (64)
|
||||
type: null
|
||||
consts: array(
|
||||
0: Const(
|
||||
name: Identifier(
|
||||
@ -137,6 +140,7 @@ array(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
type: null
|
||||
consts: array(
|
||||
0: Const(
|
||||
name: Identifier(
|
||||
@ -150,4 +154,4 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -27,6 +27,7 @@ array(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
consts: array(
|
||||
0: Const(
|
||||
name: Identifier(
|
||||
@ -42,6 +43,7 @@ array(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
type: null
|
||||
consts: array(
|
||||
0: Const(
|
||||
name: Identifier(
|
||||
@ -57,6 +59,7 @@ array(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PROTECTED (2)
|
||||
type: null
|
||||
consts: array(
|
||||
0: Const(
|
||||
name: Identifier(
|
||||
@ -72,6 +75,7 @@ array(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PRIVATE (4)
|
||||
type: null
|
||||
consts: array(
|
||||
0: Const(
|
||||
name: Identifier(
|
||||
@ -87,6 +91,7 @@ array(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_FINAL (32)
|
||||
type: null
|
||||
consts: array(
|
||||
0: Const(
|
||||
name: Identifier(
|
||||
@ -100,4 +105,4 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
26
test/code/parser/stmt/class/readonlyAnonyous.test
Normal file
26
test/code/parser/stmt/class/readonlyAnonyous.test
Normal file
@ -0,0 +1,26 @@
|
||||
Readonly anonymous class
|
||||
-----
|
||||
<?php
|
||||
|
||||
new readonly class {};
|
||||
-----
|
||||
!!php7
|
||||
array(
|
||||
0: Stmt_Expression(
|
||||
expr: Expr_New(
|
||||
class: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_READONLY (64)
|
||||
name: null
|
||||
extends: null
|
||||
implements: array(
|
||||
)
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
@ -46,6 +46,7 @@ array(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
consts: array(
|
||||
0: Const(
|
||||
name: Identifier(
|
||||
|
125
test/code/parser/stmt/class/typedConstants.test
Normal file
125
test/code/parser/stmt/class/typedConstants.test
Normal file
@ -0,0 +1,125 @@
|
||||
Typed constants
|
||||
-----
|
||||
<?php
|
||||
class Test {
|
||||
const int X = 1;
|
||||
private const string Y = "a", Z = "b";
|
||||
const array ARRAY = [];
|
||||
const Foo|Bar|null FOO = null;
|
||||
}
|
||||
-----
|
||||
!!php7
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: Test
|
||||
)
|
||||
extends: null
|
||||
implements: array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_ClassConst(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: Identifier(
|
||||
name: int
|
||||
)
|
||||
consts: array(
|
||||
0: Const(
|
||||
name: Identifier(
|
||||
name: X
|
||||
)
|
||||
value: Scalar_LNumber(
|
||||
value: 1
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
1: Stmt_ClassConst(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PRIVATE (4)
|
||||
type: Identifier(
|
||||
name: string
|
||||
)
|
||||
consts: array(
|
||||
0: Const(
|
||||
name: Identifier(
|
||||
name: Y
|
||||
)
|
||||
value: Scalar_String(
|
||||
value: a
|
||||
)
|
||||
)
|
||||
1: Const(
|
||||
name: Identifier(
|
||||
name: Z
|
||||
)
|
||||
value: Scalar_String(
|
||||
value: b
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
2: Stmt_ClassConst(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: Identifier(
|
||||
name: array
|
||||
)
|
||||
consts: array(
|
||||
0: Const(
|
||||
name: Identifier(
|
||||
name: ARRAY
|
||||
)
|
||||
value: Expr_Array(
|
||||
items: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
3: Stmt_ClassConst(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: UnionType(
|
||||
types: array(
|
||||
0: Name(
|
||||
parts: array(
|
||||
0: Foo
|
||||
)
|
||||
)
|
||||
1: Name(
|
||||
parts: array(
|
||||
0: Bar
|
||||
)
|
||||
)
|
||||
2: Identifier(
|
||||
name: null
|
||||
)
|
||||
)
|
||||
)
|
||||
consts: array(
|
||||
0: Const(
|
||||
name: Identifier(
|
||||
name: FOO
|
||||
)
|
||||
value: Expr_ConstFetch(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: null
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
@ -127,6 +127,7 @@ array(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: null
|
||||
consts: array(
|
||||
0: Const(
|
||||
name: Identifier(
|
||||
|
@ -10,7 +10,9 @@ new class($a) extends A {
|
||||
$this->a = $a;
|
||||
}
|
||||
};
|
||||
new readonly class {};
|
||||
-----
|
||||
!!php7
|
||||
new class
|
||||
{
|
||||
};
|
||||
@ -25,3 +27,6 @@ new class($a) extends A
|
||||
$this->a = $a;
|
||||
}
|
||||
};
|
||||
new readonly class
|
||||
{
|
||||
};
|
||||
|
9
test/code/prettyPrinter/expr/dynamicClassConstFetch.test
Normal file
9
test/code/prettyPrinter/expr/dynamicClassConstFetch.test
Normal file
@ -0,0 +1,9 @@
|
||||
Dynamic class constant fetch
|
||||
-----
|
||||
<?php
|
||||
Foo::{bar()};
|
||||
$foo::{bar()};
|
||||
-----
|
||||
!!php7
|
||||
Foo::{bar()};
|
||||
$foo::{bar()};
|
@ -2,10 +2,22 @@ Parentheses for complex new/instanceof expressions
|
||||
-----
|
||||
<?php
|
||||
new ('a' . 'b');
|
||||
new (x);
|
||||
new (foo());
|
||||
new ('foo');
|
||||
new (x[0]);
|
||||
new (x->y);
|
||||
new ((x)::$y);
|
||||
$x instanceof ('a' . 'b');
|
||||
$x instanceof ($y++);
|
||||
-----
|
||||
!!php7
|
||||
new ('a' . 'b')();
|
||||
new (x)();
|
||||
new (foo())();
|
||||
new ('foo')();
|
||||
new (x[0])();
|
||||
new (x->y)();
|
||||
new ((x)::$y)();
|
||||
$x instanceof ('a' . 'b');
|
||||
$x instanceof ($y++);
|
||||
$x instanceof ($y++);
|
||||
|
@ -11,6 +11,9 @@ A::$$b[$c]();
|
||||
($a->b)();
|
||||
(A::$b)();
|
||||
('a' . 'b')::X;
|
||||
(A)::X;
|
||||
(A)::$x;
|
||||
(A)::x();
|
||||
-----
|
||||
!!php7
|
||||
(function () {
|
||||
@ -22,4 +25,7 @@ $A::{$b[$c]}();
|
||||
A::${$b}[$c]();
|
||||
($a->b)();
|
||||
(A::$b)();
|
||||
('a' . 'b')::X;
|
||||
('a' . 'b')::X;
|
||||
(A)::X;
|
||||
(A)::$x;
|
||||
(A)::x();
|
||||
|
@ -7,7 +7,7 @@ class Foo
|
||||
const A = 1, B = 2;
|
||||
public const C = 3, D = 4;
|
||||
protected const E = 5, F = 6;
|
||||
private const G = 7, H = 8;
|
||||
private const int G = 7, H = 8;
|
||||
}
|
||||
-----
|
||||
!!php7
|
||||
@ -16,5 +16,5 @@ class Foo
|
||||
const A = 1, B = 2;
|
||||
public const C = 3, D = 4;
|
||||
protected const E = 5, F = 6;
|
||||
private const G = 7, H = 8;
|
||||
}
|
||||
private const int G = 7, H = 8;
|
||||
}
|
||||
|
Reference in New Issue
Block a user