mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-12 23:14:18 +01:00
N°4789 - Parse datamodel module.xxx.php files instead of interpreting them (#746)
* N°4789 - Parse datamodel module.xxx.php files instead of interpreting them - refactoring all in a dedicated service first * N°4789 - fix broken setup + tests * N°4789 - replace legacy eval by module file parsing * N°4789 - handle constants and if conditional structures * N°4789 - compute boolean expressions * N°4789 - make autoselect and dependencies work as well * cleanup * N°4789 - fix BeforeWritingConfig calls during setup * N°4789 - refactor and split in ModuleDiscoveryEvaluationService + handle ModuleInstallerAPI methods calls during setup * N°4789 - PR review changes with Romain * PR review + code cleanup + added usecases and test cover * temp evaluation work * replace eval by iTop custom evaluation classes * move PhpParser/Evaluation classes in a specific namespave + composer dumpautoload * fix broken setup * fix broken setup * complete Evaluators list + autoload * cleanup useless testing resources * cleanup + replace last eval call in VariableEvaluator * fix few Evaluators code * enhance nikic evaluators + test with/without nikic lib * Evaluator fixes/enhancements + tests * bump to nikic fork temporarly * bump nikic-parser fork + use only nikic fork evaluation + cleanup itop redondant evaluators * review with Romain: use distinct whitelists in setup time/runtime + move ModuleFileParser internal logic into ModuleFileReader * PhpExpressionEvaluator used via constructor and not as a service * dumpautoload again after rebase
This commit is contained in:
@@ -24,7 +24,7 @@
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "5.0-dev"
|
||||
"dev-master": "5.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
namespace PhpParser;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Scalar;
|
||||
use Exception;
|
||||
|
||||
use function array_merge;
|
||||
|
||||
@@ -30,6 +33,12 @@ class ConstExprEvaluator {
|
||||
/** @var callable|null */
|
||||
private $fallbackEvaluator;
|
||||
|
||||
/** @var array $functionsWhiteList */
|
||||
private $functionsWhiteList;
|
||||
|
||||
/** @var array $staticCallsWhitelist */
|
||||
private $staticCallsWhitelist;
|
||||
|
||||
/**
|
||||
* Create a constant expression evaluator.
|
||||
*
|
||||
@@ -44,6 +53,17 @@ class ConstExprEvaluator {
|
||||
"Expression of type {$expr->getType()} cannot be evaluated"
|
||||
);
|
||||
};
|
||||
|
||||
$this->functionsWhiteList = [];
|
||||
$this->staticCallsWhitelist = [];
|
||||
}
|
||||
|
||||
public function setFunctionsWhitelist(array $functionsWhiteList): void {
|
||||
$this->functionsWhiteList = $functionsWhiteList;
|
||||
}
|
||||
|
||||
public function setStaticCallsWhitelist(array $staticCallsWhitelist): void {
|
||||
$this->staticCallsWhitelist = $staticCallsWhitelist;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,6 +135,10 @@ class ConstExprEvaluator {
|
||||
return $this->evaluateArray($expr);
|
||||
}
|
||||
|
||||
if ($expr instanceof Expr\Variable) {
|
||||
return $this->evaluateVariable($expr);
|
||||
}
|
||||
|
||||
// Unary operators
|
||||
if ($expr instanceof Expr\UnaryPlus) {
|
||||
return +$this->evaluate($expr->expr);
|
||||
@@ -145,6 +169,38 @@ class ConstExprEvaluator {
|
||||
return $this->evaluateConstFetch($expr);
|
||||
}
|
||||
|
||||
if ($expr instanceof Expr\Isset_) {
|
||||
return $this->evaluateIsset($expr);
|
||||
}
|
||||
|
||||
if ($expr instanceof Expr\ClassConstFetch) {
|
||||
return $this->evaluateClassConstFetch($expr);
|
||||
}
|
||||
|
||||
if ($expr instanceof Expr\Cast) {
|
||||
return $this->evaluateCast($expr);
|
||||
}
|
||||
|
||||
if ($expr instanceof Expr\StaticPropertyFetch) {
|
||||
return $this->evaluateStaticPropertyFetch($expr);
|
||||
}
|
||||
|
||||
if ($expr instanceof Expr\FuncCall) {
|
||||
return $this->evaluateFuncCall($expr);
|
||||
}
|
||||
|
||||
if ($expr instanceof Expr\StaticCall) {
|
||||
return $this->evaluateStaticCall($expr);
|
||||
}
|
||||
|
||||
if ($expr instanceof Expr\NullsafePropertyFetch||$expr instanceof Expr\PropertyFetch) {
|
||||
return $this->evaluatePropertyFetch($expr);
|
||||
}
|
||||
|
||||
if ($expr instanceof Expr\NullsafeMethodCall||$expr instanceof Expr\MethodCall) {
|
||||
return $this->evaluateMethodCall($expr);
|
||||
}
|
||||
|
||||
return ($this->fallbackEvaluator)($expr);
|
||||
}
|
||||
|
||||
@@ -175,12 +231,15 @@ class ConstExprEvaluator {
|
||||
|
||||
/** @return mixed */
|
||||
private function evaluateBinaryOp(Expr\BinaryOp $expr) {
|
||||
if ($expr instanceof Expr\BinaryOp\Coalesce
|
||||
&& $expr->left instanceof Expr\ArrayDimFetch
|
||||
) {
|
||||
// This needs to be special cased to respect BP_VAR_IS fetch semantics
|
||||
return $this->evaluate($expr->left->var)[$this->evaluate($expr->left->dim)]
|
||||
?? $this->evaluate($expr->right);
|
||||
if ($expr instanceof Expr\BinaryOp\Coalesce) {
|
||||
try {
|
||||
$var = $this->evaluate($expr->left);
|
||||
} catch(\Throwable $t) {
|
||||
//left expression cannot be evaluated (! isset for exeample)
|
||||
return $this->evaluate($expr->right);
|
||||
}
|
||||
|
||||
return $var ?? $this->evaluate($expr->right);
|
||||
}
|
||||
|
||||
// The evaluate() calls are repeated in each branch, because some of the operators are
|
||||
@@ -225,13 +284,272 @@ class ConstExprEvaluator {
|
||||
|
||||
/** @return mixed */
|
||||
private function evaluateConstFetch(Expr\ConstFetch $expr) {
|
||||
$name = $expr->name->toLowerString();
|
||||
switch ($name) {
|
||||
case 'null': return null;
|
||||
case 'false': return false;
|
||||
case 'true': return true;
|
||||
}
|
||||
try {
|
||||
$name = $expr->name;
|
||||
if(! is_string($name)) {
|
||||
//PHP_VERSION_ID usecase
|
||||
$name = $name->name;
|
||||
}
|
||||
|
||||
if (defined($name)) {
|
||||
return constant($name);
|
||||
}
|
||||
} catch(\Throwable $t) {}
|
||||
|
||||
return ($this->fallbackEvaluator)($expr);
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
private function evaluateIsset(Expr\Isset_ $expr) {
|
||||
try {
|
||||
foreach ($expr->vars as $var) {
|
||||
$var = $this->evaluate($var);
|
||||
if (! isset($var)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch(\Throwable $t) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** @return mixed */
|
||||
private function evaluateClassConstFetch(Expr\ClassConstFetch $expr) {
|
||||
try {
|
||||
$classname = $expr->class->name;
|
||||
$property = $expr->name->name;
|
||||
|
||||
if ('class' === $property) {
|
||||
return $classname;
|
||||
}
|
||||
|
||||
if (class_exists($classname)) {
|
||||
$class = new \ReflectionClass($classname);
|
||||
if (array_key_exists($property, $class->getConstants())) {
|
||||
$oReflectionConstant = $class->getReflectionConstant($property);
|
||||
if ($oReflectionConstant->isPublic()) {
|
||||
return $class->getConstant($property);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(\Throwable $t) {}
|
||||
|
||||
return ($this->fallbackEvaluator)($expr);
|
||||
}
|
||||
|
||||
/** @return mixed */
|
||||
private function evaluateCast(Expr\Cast $expr) {
|
||||
try {
|
||||
$subexpr = $this->evaluate($expr->expr);
|
||||
$type = get_class($expr);
|
||||
switch ($type) {
|
||||
case Expr\Cast\Array_::class:
|
||||
return (array) $subexpr;
|
||||
|
||||
case Expr\Cast\Bool_::class:
|
||||
return (bool) $subexpr;
|
||||
|
||||
case Expr\Cast\Double::class:
|
||||
switch ($expr->getAttribute("kind")) {
|
||||
case Expr\Cast\Double::KIND_DOUBLE:
|
||||
return (double) $subexpr;
|
||||
|
||||
case Expr\Cast\Double::KIND_FLOAT:
|
||||
case Expr\Cast\Double::KIND_REAL:
|
||||
return (float) $subexpr;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Expr\Cast\Int_::class:
|
||||
return (int) $subexpr;
|
||||
|
||||
case Expr\Cast\Object_::class:
|
||||
return (object) $subexpr;
|
||||
|
||||
case Expr\Cast\String_::class:
|
||||
return (string) $subexpr;
|
||||
}
|
||||
} catch(\Throwable $t) {}
|
||||
|
||||
return ($this->fallbackEvaluator)($expr);
|
||||
}
|
||||
|
||||
/** @return mixed */
|
||||
private function evaluateStaticPropertyFetch(Expr\StaticPropertyFetch $expr) {
|
||||
try {
|
||||
$classname = $expr->class->name;
|
||||
if ($expr->name instanceof Identifier) {
|
||||
$property = $expr->name->name;
|
||||
} else {
|
||||
$property = $this->evaluate($expr->name);
|
||||
}
|
||||
|
||||
if (class_exists($classname)) {
|
||||
$class = new \ReflectionClass($classname);
|
||||
if (array_key_exists($property, $class->getStaticProperties())) {
|
||||
$oReflectionProperty = $class->getProperty($property);
|
||||
if ($oReflectionProperty->isPublic()) {
|
||||
return $class->getStaticPropertyValue($property);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (\Throwable $t) {}
|
||||
|
||||
return ($this->fallbackEvaluator)($expr);
|
||||
}
|
||||
|
||||
/** @return mixed */
|
||||
private function evaluateFuncCall(Expr\FuncCall $expr) {
|
||||
try {
|
||||
$name = $expr->name;
|
||||
if ($name instanceof Name) {
|
||||
$function = $name->name;
|
||||
} else {
|
||||
$function = $this->evaluate($name);
|
||||
}
|
||||
|
||||
if (! in_array($function, $this->functionsWhiteList)) {
|
||||
throw new Exception("FuncCall $function not supported");
|
||||
}
|
||||
|
||||
$args=[];
|
||||
foreach ($expr->args as $arg) {
|
||||
/** @var \PhpParser\Node\Arg $arg */
|
||||
$args[]=$arg->value->value;
|
||||
}
|
||||
|
||||
$reflection_function = new \ReflectionFunction($function);
|
||||
return $reflection_function->invoke(...$args);
|
||||
}
|
||||
catch (\Throwable $t) {}
|
||||
|
||||
return ($this->fallbackEvaluator)($expr);
|
||||
}
|
||||
|
||||
/** @return mixed */
|
||||
private function evaluateVariable(Expr\Variable $expr) {
|
||||
try {
|
||||
$name = $expr->name;
|
||||
if (array_key_exists($name, get_defined_vars())) {
|
||||
return $$name;
|
||||
}
|
||||
|
||||
if (array_key_exists($name, $GLOBALS)) {
|
||||
global $$name;
|
||||
return $$name;
|
||||
}
|
||||
} catch (\Throwable $t) {
|
||||
}
|
||||
|
||||
return ($this->fallbackEvaluator)($expr);
|
||||
}
|
||||
|
||||
/** @return mixed */
|
||||
private function evaluateStaticCall(Expr\StaticCall $expr) {
|
||||
try {
|
||||
$class = $expr->class->name;
|
||||
if ($expr->name instanceof Identifier) {
|
||||
$method = $expr->name->name;
|
||||
} else {
|
||||
$method = $this->evaluate($expr->name);
|
||||
}
|
||||
|
||||
$static_call_description = "$class::$method";
|
||||
if (! in_array($static_call_description, $this->staticCallsWhitelist)) {
|
||||
throw new Exception("StaticCall $static_call_description not supported");
|
||||
}
|
||||
|
||||
$args=[];
|
||||
foreach ($expr->args as $arg) {
|
||||
/** @var \PhpParser\Node\Arg $arg */
|
||||
$args[]=$arg->value->value;
|
||||
}
|
||||
|
||||
$class = new \ReflectionClass($class);
|
||||
$method = $class->getMethod($method);
|
||||
if ($method->isPublic()) {
|
||||
return $method->invokeArgs(null, $args);
|
||||
}
|
||||
} catch (\Throwable $t) {}
|
||||
|
||||
return ($this->fallbackEvaluator)($expr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \PhpParser\Node\Expr\NullsafePropertyFetch|\PhpParser\Node\Expr\PropertyFetch $expr
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function evaluatePropertyFetch($expr) {
|
||||
try {
|
||||
$var = $this->evaluate($expr->var);
|
||||
} catch (\Throwable $t) {
|
||||
$var = null;
|
||||
}
|
||||
|
||||
if (! is_null($var)) {
|
||||
try {
|
||||
if ($expr->name instanceof Identifier) {
|
||||
$name = $expr->name->name;
|
||||
} else {
|
||||
$name = $this->evaluate($expr->name);
|
||||
}
|
||||
|
||||
$reflectionClass = new \ReflectionClass(get_class($var));
|
||||
$property = $reflectionClass->getProperty($name);
|
||||
if ($property->isPublic()) {
|
||||
return $property->getValue($var);
|
||||
}
|
||||
}
|
||||
catch (\Throwable $t) {}
|
||||
} else if ($expr instanceof Expr\NullsafePropertyFetch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ($this->fallbackEvaluator)($expr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\NullsafeMethodCall $expr
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function evaluateMethodCall($expr) {
|
||||
try {
|
||||
$var = $this->evaluate($expr->var);
|
||||
} catch (\Throwable $t) {
|
||||
$var = null;
|
||||
}
|
||||
|
||||
if (! is_null($var)) {
|
||||
try {
|
||||
$args = [];
|
||||
foreach ($expr->args as $arg) {
|
||||
/** @var \PhpParser\Node\Arg $arg */
|
||||
$args[] = $arg->value->value;
|
||||
}
|
||||
|
||||
if ($expr->name instanceof Identifier) {
|
||||
$name = $expr->name->name;
|
||||
} else {
|
||||
$name = $this->evaluate($expr->name);
|
||||
}
|
||||
|
||||
$reflectionClass = new \ReflectionClass(get_class($var));
|
||||
$method = $reflectionClass->getMethod($name);
|
||||
if ($method->isPublic()) {
|
||||
return $method->invokeArgs($var, $args);
|
||||
}
|
||||
}
|
||||
catch (\Throwable $t) {}
|
||||
} else if ($expr instanceof Expr\NullsafeMethodCall) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ($this->fallbackEvaluator)($expr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,11 @@ namespace PhpParser\Node\Expr;
|
||||
require __DIR__ . '/../ArrayItem.php';
|
||||
|
||||
if (false) {
|
||||
// For classmap-authoritative support.
|
||||
/**
|
||||
* For classmap-authoritative support.
|
||||
*
|
||||
* @deprecated use \PhpParser\Node\ArrayItem instead.
|
||||
*/
|
||||
class ArrayItem extends \PhpParser\Node\ArrayItem {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,10 @@ namespace PhpParser\Node\Expr\Cast;
|
||||
use PhpParser\Node\Expr\Cast;
|
||||
|
||||
class Bool_ extends Cast {
|
||||
// For use in "kind" attribute
|
||||
public const KIND_BOOL = 1; // "bool" syntax
|
||||
public const KIND_BOOLEAN = 2; // "boolean" syntax
|
||||
|
||||
public function getType(): string {
|
||||
return 'Expr_Cast_Bool';
|
||||
}
|
||||
|
||||
@@ -5,6 +5,10 @@ namespace PhpParser\Node\Expr\Cast;
|
||||
use PhpParser\Node\Expr\Cast;
|
||||
|
||||
class Int_ extends Cast {
|
||||
// For use in "kind" attribute
|
||||
public const KIND_INT = 1; // "int" syntax
|
||||
public const KIND_INTEGER = 2; // "integer" syntax
|
||||
|
||||
public function getType(): string {
|
||||
return 'Expr_Cast_Int';
|
||||
}
|
||||
|
||||
@@ -5,6 +5,10 @@ namespace PhpParser\Node\Expr\Cast;
|
||||
use PhpParser\Node\Expr\Cast;
|
||||
|
||||
class String_ extends Cast {
|
||||
// For use in "kind" attribute
|
||||
public const KIND_STRING = 1; // "string" syntax
|
||||
public const KIND_BINARY = 2; // "binary" syntax
|
||||
|
||||
public function getType(): string {
|
||||
return 'Expr_Cast_String';
|
||||
}
|
||||
|
||||
@@ -5,7 +5,11 @@ namespace PhpParser\Node\Expr;
|
||||
require __DIR__ . '/../ClosureUse.php';
|
||||
|
||||
if (false) {
|
||||
// For classmap-authoritative support.
|
||||
/**
|
||||
* For classmap-authoritative support.
|
||||
*
|
||||
* @deprecated use \PhpParser\Node\ClosureUse instead.
|
||||
*/
|
||||
class ClosureUse extends \PhpParser\Node\ClosureUse {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ class Param extends NodeAbstract {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->hooks === []) {
|
||||
if (!$this->isPromoted()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,11 @@ namespace PhpParser\Node\Scalar;
|
||||
require __DIR__ . '/Float_.php';
|
||||
|
||||
if (false) {
|
||||
// For classmap-authoritative support.
|
||||
/**
|
||||
* For classmap-authoritative support.
|
||||
*
|
||||
* @deprecated use \PhpParser\Node\Scalar\Float_ instead.
|
||||
*/
|
||||
class DNumber extends Float_ {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,11 @@ namespace PhpParser\Node\Scalar;
|
||||
require __DIR__ . '/InterpolatedString.php';
|
||||
|
||||
if (false) {
|
||||
// For classmap-authoritative support.
|
||||
/**
|
||||
* For classmap-authoritative support.
|
||||
*
|
||||
* @deprecated use \PhpParser\Node\Scalar\InterpolatedString instead.
|
||||
*/
|
||||
class Encapsed extends InterpolatedString {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,11 @@ use PhpParser\Node\InterpolatedStringPart;
|
||||
require __DIR__ . '/../InterpolatedStringPart.php';
|
||||
|
||||
if (false) {
|
||||
// For classmap-authoritative support.
|
||||
/**
|
||||
* For classmap-authoritative support.
|
||||
*
|
||||
* @deprecated use \PhpParser\Node\InterpolatedStringPart instead.
|
||||
*/
|
||||
class EncapsedStringPart extends InterpolatedStringPart {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,11 @@ namespace PhpParser\Node\Scalar;
|
||||
require __DIR__ . '/Int_.php';
|
||||
|
||||
if (false) {
|
||||
// For classmap-authoritative support.
|
||||
/**
|
||||
* For classmap-authoritative support.
|
||||
*
|
||||
* @deprecated use \PhpParser\Node\Scalar\Int_ instead.
|
||||
*/
|
||||
class LNumber extends Int_ {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ class String_ extends Scalar {
|
||||
// If it overflowed to float, treat as INT_MAX, it will throw an error anyway.
|
||||
return self::codePointToUtf8(\is_int($dec) ? $dec : \PHP_INT_MAX);
|
||||
} else {
|
||||
return chr(octdec($str));
|
||||
return chr(octdec($str) & 255);
|
||||
}
|
||||
},
|
||||
$str
|
||||
|
||||
@@ -7,7 +7,11 @@ use PhpParser\Node\DeclareItem;
|
||||
require __DIR__ . '/../DeclareItem.php';
|
||||
|
||||
if (false) {
|
||||
// For classmap-authoritative support.
|
||||
/**
|
||||
* For classmap-authoritative support.
|
||||
*
|
||||
* @deprecated use \PhpParser\Node\DeclareItem instead.
|
||||
*/
|
||||
class DeclareDeclare extends DeclareItem {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,11 @@ use PhpParser\Node\PropertyItem;
|
||||
require __DIR__ . '/../PropertyItem.php';
|
||||
|
||||
if (false) {
|
||||
// For classmap-authoritative support.
|
||||
/**
|
||||
* For classmap-authoritative support.
|
||||
*
|
||||
* @deprecated use \PhpParser\Node\PropertyItem instead.
|
||||
*/
|
||||
class PropertyProperty extends PropertyItem {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,11 @@ namespace PhpParser\Node\Stmt;
|
||||
require __DIR__ . '/../StaticVar.php';
|
||||
|
||||
if (false) {
|
||||
// For classmap-authoritative support.
|
||||
/**
|
||||
* For classmap-authoritative support.
|
||||
*
|
||||
* @deprecated use \PhpParser\Node\StaticVar instead.
|
||||
*/
|
||||
class StaticVar extends \PhpParser\Node\StaticVar {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,11 @@ use PhpParser\Node\UseItem;
|
||||
require __DIR__ . '/../UseItem.php';
|
||||
|
||||
if (false) {
|
||||
// For classmap-authoritative support.
|
||||
/**
|
||||
* For classmap-authoritative support.
|
||||
*
|
||||
* @deprecated use \PhpParser\Node\UseItem instead.
|
||||
*/
|
||||
class UseUse extends UseItem {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2478,7 +2478,9 @@ class Php7 extends \PhpParser\ParserAbstract
|
||||
$self->semValue = new Expr\Include_($self->semStack[$stackPos-(2-2)], Expr\Include_::TYPE_REQUIRE_ONCE, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
|
||||
},
|
||||
487 => static function ($self, $stackPos) {
|
||||
$self->semValue = new Expr\Cast\Int_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
|
||||
$attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]);
|
||||
$attrs['kind'] = $self->getIntCastKind($self->semStack[$stackPos-(2-1)]);
|
||||
$self->semValue = new Expr\Cast\Int_($self->semStack[$stackPos-(2-2)], $attrs);
|
||||
},
|
||||
488 => static function ($self, $stackPos) {
|
||||
$attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]);
|
||||
@@ -2486,7 +2488,9 @@ class Php7 extends \PhpParser\ParserAbstract
|
||||
$self->semValue = new Expr\Cast\Double($self->semStack[$stackPos-(2-2)], $attrs);
|
||||
},
|
||||
489 => static function ($self, $stackPos) {
|
||||
$self->semValue = new Expr\Cast\String_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
|
||||
$attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]);
|
||||
$attrs['kind'] = $self->getStringCastKind($self->semStack[$stackPos-(2-1)]);
|
||||
$self->semValue = new Expr\Cast\String_($self->semStack[$stackPos-(2-2)], $attrs);
|
||||
},
|
||||
490 => static function ($self, $stackPos) {
|
||||
$self->semValue = new Expr\Cast\Array_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
|
||||
@@ -2495,7 +2499,9 @@ class Php7 extends \PhpParser\ParserAbstract
|
||||
$self->semValue = new Expr\Cast\Object_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
|
||||
},
|
||||
492 => static function ($self, $stackPos) {
|
||||
$self->semValue = new Expr\Cast\Bool_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
|
||||
$attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]);
|
||||
$attrs['kind'] = $self->getBoolCastKind($self->semStack[$stackPos-(2-1)]);
|
||||
$self->semValue = new Expr\Cast\Bool_($self->semStack[$stackPos-(2-2)], $attrs);
|
||||
},
|
||||
493 => static function ($self, $stackPos) {
|
||||
$self->semValue = new Expr\Cast\Unset_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
|
||||
@@ -2686,10 +2692,10 @@ class Php7 extends \PhpParser\ParserAbstract
|
||||
561 => static function ($self, $stackPos) {
|
||||
$attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]); $attrs['kind'] = Expr\Array_::KIND_LONG;
|
||||
$self->semValue = new Expr\Array_($self->semStack[$stackPos-(4-3)], $attrs);
|
||||
$self->createdArrays->attach($self->semValue);
|
||||
$self->createdArrays->offsetSet($self->semValue);
|
||||
},
|
||||
562 => static function ($self, $stackPos) {
|
||||
$self->semValue = $self->semStack[$stackPos-(1-1)]; $self->createdArrays->attach($self->semValue);
|
||||
$self->semValue = $self->semStack[$stackPos-(1-1)]; $self->createdArrays->offsetSet($self->semValue);
|
||||
},
|
||||
563 => static function ($self, $stackPos) {
|
||||
$self->semValue = Scalar\String_::fromString($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]), $self->phpVersion->supportsUnicodeEscapes());
|
||||
|
||||
@@ -2479,7 +2479,9 @@ class Php8 extends \PhpParser\ParserAbstract
|
||||
$self->semValue = new Expr\Include_($self->semStack[$stackPos-(2-2)], Expr\Include_::TYPE_REQUIRE_ONCE, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
|
||||
},
|
||||
490 => static function ($self, $stackPos) {
|
||||
$self->semValue = new Expr\Cast\Int_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
|
||||
$attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]);
|
||||
$attrs['kind'] = $self->getIntCastKind($self->semStack[$stackPos-(2-1)]);
|
||||
$self->semValue = new Expr\Cast\Int_($self->semStack[$stackPos-(2-2)], $attrs);
|
||||
},
|
||||
491 => static function ($self, $stackPos) {
|
||||
$attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]);
|
||||
@@ -2487,7 +2489,9 @@ class Php8 extends \PhpParser\ParserAbstract
|
||||
$self->semValue = new Expr\Cast\Double($self->semStack[$stackPos-(2-2)], $attrs);
|
||||
},
|
||||
492 => static function ($self, $stackPos) {
|
||||
$self->semValue = new Expr\Cast\String_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
|
||||
$attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]);
|
||||
$attrs['kind'] = $self->getStringCastKind($self->semStack[$stackPos-(2-1)]);
|
||||
$self->semValue = new Expr\Cast\String_($self->semStack[$stackPos-(2-2)], $attrs);
|
||||
},
|
||||
493 => static function ($self, $stackPos) {
|
||||
$self->semValue = new Expr\Cast\Array_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
|
||||
@@ -2496,7 +2500,9 @@ class Php8 extends \PhpParser\ParserAbstract
|
||||
$self->semValue = new Expr\Cast\Object_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
|
||||
},
|
||||
495 => static function ($self, $stackPos) {
|
||||
$self->semValue = new Expr\Cast\Bool_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
|
||||
$attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]);
|
||||
$attrs['kind'] = $self->getBoolCastKind($self->semStack[$stackPos-(2-1)]);
|
||||
$self->semValue = new Expr\Cast\Bool_($self->semStack[$stackPos-(2-2)], $attrs);
|
||||
},
|
||||
496 => static function ($self, $stackPos) {
|
||||
$self->semValue = new Expr\Cast\Unset_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
|
||||
@@ -2687,10 +2693,10 @@ class Php8 extends \PhpParser\ParserAbstract
|
||||
564 => static function ($self, $stackPos) {
|
||||
$attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]); $attrs['kind'] = Expr\Array_::KIND_LONG;
|
||||
$self->semValue = new Expr\Array_($self->semStack[$stackPos-(4-3)], $attrs);
|
||||
$self->createdArrays->attach($self->semValue);
|
||||
$self->createdArrays->offsetSet($self->semValue);
|
||||
},
|
||||
565 => static function ($self, $stackPos) {
|
||||
$self->semValue = $self->semStack[$stackPos-(1-1)]; $self->createdArrays->attach($self->semValue);
|
||||
$self->semValue = $self->semStack[$stackPos-(1-1)]; $self->createdArrays->offsetSet($self->semValue);
|
||||
},
|
||||
566 => static function ($self, $stackPos) {
|
||||
$self->semValue = Scalar\String_::fromString($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]), $self->phpVersion->supportsUnicodeEscapes());
|
||||
|
||||
@@ -736,6 +736,33 @@ abstract class ParserAbstract implements Parser {
|
||||
return Double::KIND_DOUBLE;
|
||||
}
|
||||
|
||||
protected function getIntCastKind(string $cast): int {
|
||||
$cast = strtolower($cast);
|
||||
if (strpos($cast, 'integer') !== false) {
|
||||
return Expr\Cast\Int_::KIND_INTEGER;
|
||||
}
|
||||
|
||||
return Expr\Cast\Int_::KIND_INT;
|
||||
}
|
||||
|
||||
protected function getBoolCastKind(string $cast): int {
|
||||
$cast = strtolower($cast);
|
||||
if (strpos($cast, 'boolean') !== false) {
|
||||
return Expr\Cast\Bool_::KIND_BOOLEAN;
|
||||
}
|
||||
|
||||
return Expr\Cast\Bool_::KIND_BOOL;
|
||||
}
|
||||
|
||||
protected function getStringCastKind(string $cast): int {
|
||||
$cast = strtolower($cast);
|
||||
if (strpos($cast, 'binary') !== false) {
|
||||
return Expr\Cast\String_::KIND_BINARY;
|
||||
}
|
||||
|
||||
return Expr\Cast\String_::KIND_STRING;
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $attributes */
|
||||
protected function parseLNumber(string $str, array $attributes, bool $allowInvalidOctal = false): Int_ {
|
||||
try {
|
||||
@@ -976,7 +1003,7 @@ abstract class ParserAbstract implements Parser {
|
||||
}
|
||||
|
||||
protected function fixupArrayDestructuring(Array_ $node): Expr\List_ {
|
||||
$this->createdArrays->detach($node);
|
||||
$this->createdArrays->offsetUnset($node);
|
||||
return new Expr\List_(array_map(function (Node\ArrayItem $item) {
|
||||
if ($item->value instanceof Expr\Error) {
|
||||
// We used Error as a placeholder for empty elements, which are legal for destructuring.
|
||||
|
||||
Reference in New Issue
Block a user