refactor: 引入 parseWritableIdentifier 替代手动 inAssignExpr 设置

pull/14/head
韩天峰 2 months ago
parent 6afb8e3689
commit bffa660427
  1. 73
      src/Php/CompilerBase.php
  2. 43
      src/Php/Parser/AssignOpTrait.php

@ -107,6 +107,7 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont
protected const string NATIVE_PROPERTY_VALUE_VAR = 'var';
protected const string NATIVE_PROPERTY_VALUE_DYNAMIC = 'dynamic';
protected const string ATTR_ARRAY_DIM_FETCH_UPDATE = 'aotArrayDimFetchUpdate';
/**
* Keyword methods (to* builtins) with mandated return types.
@ -625,7 +626,7 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont
case 'Expr_Array':
return $this->parseArray($expr);
case 'Expr_ArrayDimFetch':
return $this->parseArrayDimFetch($expr, $this->context->inAssignExpr);
return $this->parseArrayDimFetch($expr);
case 'Expr_PropertyFetch':
return $this->parsePropertyFetch($expr, $this->context->inAssignExpr);
case 'Expr_NullsafePropertyFetch':
@ -2933,12 +2934,8 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont
protected function parsePreInc(Expr\PreInc $expr): string
{
$this->assertNotNullsafeWriteContext($expr->var);
$oriInAssignExpr = $this->context->inAssignExpr;
$this->context->inAssignExpr = true;
$result = $this->genDynamicPropIncDec($expr->var, '+', true);
if ($result !== null) {
$this->context->inAssignExpr = $oriInAssignExpr;
return $result;
}
@ -2946,8 +2943,7 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont
if ($type === self::TYPE_BIGINT || $type === self::TYPE_DECIMAL || $type === self::TYPE_BIGFLOAT) {
$this->fatalError($expr, 'Cannot use ++ on ' . $type . '. Use += 1 instead (Big* types are immutable).');
}
$result = '++' . $this->parseIdentifier($expr->var);
$this->context->inAssignExpr = $oriInAssignExpr;
$result = '++' . $this->parseWritableIdentifier($expr->var);
return $result;
}
@ -3016,8 +3012,48 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont
return 'php::global(' . $this->parseIdentifier($node->dim) . ')';
}
protected function parseArrayDimFetch(Expr\ArrayDimFetch $node, bool $write): string
protected function parseWritableIdentifier(NodeAbstract $expr): string
{
if ($expr instanceof Expr\ArrayDimFetch) {
return $this->parseArrayDimFetchUpdate($expr);
}
$oriInAssignExpr = $this->context->inAssignExpr;
$this->context->inAssignExpr = true;
$code = $this->parseIdentifier($expr);
$this->context->inAssignExpr = $oriInAssignExpr;
return $code;
}
protected function parseArrayDimFetchRead(Expr\ArrayDimFetch $node): string
{
return $this->parseArrayDimFetchWithUpdate($node, false);
}
protected function parseArrayDimFetchUpdate(Expr\ArrayDimFetch $node): string
{
return $this->parseArrayDimFetchWithUpdate($node, true);
}
protected function parseArrayDimFetchWithUpdate(Expr\ArrayDimFetch $node, bool $update): string
{
$attributes = $node->getAttributes();
$node->setAttribute(self::ATTR_ARRAY_DIM_FETCH_UPDATE, $update);
try {
return $this->parseArrayDimFetch($node);
} finally {
$node->setAttributes($attributes);
}
}
protected function isArrayDimFetchUpdate(Expr\ArrayDimFetch $node): bool
{
return $node->getAttribute(self::ATTR_ARRAY_DIM_FETCH_UPDATE, false) === true;
}
protected function parseArrayDimFetch(Expr\ArrayDimFetch $node): string
{
$write = $this->isArrayDimFetchUpdate($node);
if ($this->isStdContainerExpr($node)) {
if ($write && $node->dim === null) {
return $this->parseIdentifier($node->var);
@ -3025,7 +3061,9 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont
return $this->parseStdContainerDimFetch($node);
}
$var = $this->parseIdentifier($node->var);
$var = $write && $node->var instanceof Expr\ArrayDimFetch
? $this->parseArrayDimFetchUpdate($node->var)
: $this->parseIdentifier($node->var);
if ($this->isVarExpr($node->var)) {
if ($var === 'GLOBALS') {
return $this->parseGlobalsArrayDimFetch($node);
@ -4030,10 +4068,7 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont
}
if ($this->isVarExpr($expr->var) or $this->isPropertyFetch($expr->var) or $this->isArrayDimFetch($expr->var)) {
$oriInAssignExpr = $this->context->inAssignExpr;
$this->context->inAssignExpr = true;
$var = $this->parseIdentifier($expr->var);
$this->context->inAssignExpr = $oriInAssignExpr;
$var = $this->parseWritableIdentifier($expr->var);
if ($this->isVarExpr($expr->var) and !$this->hasVar($var)) {
$this->errorUndefinedVariable($expr->var);
}
@ -4213,12 +4248,8 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont
protected function parsePreDec(Expr\PreDec $expr): string
{
$this->assertNotNullsafeWriteContext($expr->var);
$oriInAssignExpr = $this->context->inAssignExpr;
$this->context->inAssignExpr = true;
$result = $this->genDynamicPropIncDec($expr->var, '-', true);
if ($result !== null) {
$this->context->inAssignExpr = $oriInAssignExpr;
return $result;
}
@ -4226,8 +4257,7 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont
if ($type === self::TYPE_BIGINT || $type === self::TYPE_DECIMAL || $type === self::TYPE_BIGFLOAT) {
$this->fatalError($expr, 'Cannot use -- on ' . $type . '. Use -= 1 instead (Big* types are immutable).');
}
$result = '--' . $this->parseIdentifier($expr->var);
$this->context->inAssignExpr = $oriInAssignExpr;
$result = '--' . $this->parseWritableIdentifier($expr->var);
return $result;
}
@ -5206,10 +5236,7 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont
$code .= $this->parseForeachItemAsList($nestedTmpVar, $item->value->items);
continue;
}
$oriInAssignExpr = $this->context->inAssignExpr;
$this->context->inAssignExpr = true;
$var = $this->parseIdentifier($item->value);
$this->context->inAssignExpr = $oriInAssignExpr;
$var = $this->parseWritableIdentifier($item->value);
if ($this->isVarExpr($item->value) and !$this->hasVar($var)) {
$this->addLocalVar($var, self::TYPE_VAR);
}

@ -29,10 +29,7 @@ trait AssignOpTrait
$this->addLocalVar($tmp, self::TYPE_VAR);
return '((' . $tmp . ' = ' . $value . ', ' . $target . ' = ' . $tmp . '), ' . $tmp . ')';
}
$oriInAssignExpr = $this->context->inAssignExpr;
$this->context->inAssignExpr = true;
$array = $this->parseIdentifier($left->var);
$this->context->inAssignExpr = $oriInAssignExpr;
$array = $this->parseWritableIdentifier($left->var);
$code = '';
if (!$this->hasVar($array) and $this->isVarExpr($left->var)) {
$this->addLocalVar($array, self::TYPE_ARRAY);
@ -125,10 +122,7 @@ trait AssignOpTrait
$code .= "{$nestedTmp} = {$tmpVar}.item({$key}); ";
$code .= $this->parseAssignToList($item->value, new Variable($nestedTmp));
} else {
$oriInAssignExpr = $this->context->inAssignExpr;
$this->context->inAssignExpr = true;
$var = $this->parseIdentifier($item->value);
$this->context->inAssignExpr = $oriInAssignExpr;
$var = $this->parseWritableIdentifier($item->value);
if ($this->isVarExpr($item->value) and !$this->hasVar($var)) {
$this->addLocalVar($var, self::TYPE_VAR);
}
@ -157,10 +151,7 @@ trait AssignOpTrait
}
if ($this->isVarExpr($left)) {
$oriInAssignExpr = $this->context->inAssignExpr;
$this->context->inAssignExpr = true;
$var = $this->parseIdentifier($left);
$this->context->inAssignExpr = $oriInAssignExpr;
$var = $this->parseWritableIdentifier($left);
if ($var === 'this_') {
$this->fatalError($left, 'Cannot re-assign $this');
}
@ -282,10 +273,7 @@ trait AssignOpTrait
$this->assertCanAssignPropertyWrite($propertyWriteTarget, $right);
}
$oriInAssignExpr = $this->context->inAssignExpr;
$this->context->inAssignExpr = true;
$var = $this->parseIdentifier($left);
$this->context->inAssignExpr = $oriInAssignExpr;
$var = $this->parseWritableIdentifier($left);
$rightExpr = $this->parseAssignRightExpr($right);
if ($propertyWriteTarget !== null) {
$rightExpr = $this->wrapPropertyWriteTypeCheck($propertyWriteTarget, $right, $rightExpr);
@ -334,10 +322,7 @@ trait AssignOpTrait
protected function parseAssignOp(Expr\AssignOp $node, string $op): string
{
$this->assertNotNullsafeWriteContext($node->var);
$oriInAssignExpr = $this->context->inAssignExpr;
$this->context->inAssignExpr = true;
$var = $this->parseIdentifier($node->var);
$this->context->inAssignExpr = $oriInAssignExpr;
$var = $this->parseWritableIdentifier($node->var);
$expr = $this->parseIdentifier($node->expr);
$propertyWriteTarget = $this->preparePropertyWriteTarget($node->var);
$this->guardLiteralDivisionByZero($node->expr, $op);
@ -386,7 +371,7 @@ trait AssignOpTrait
$tmpVar = $this->genTmpVarName();
$this->addLocalVar($tmpVar, $rightType);
$dim = $this->parseIdentifier($node->var->dim);
$readVar = $this->parseArrayDimFetch($node->var, false);
$readVar = $this->parseArrayDimFetchRead($node->var);
$binaryOp = $this->removeAssignOp($op);
if ($binaryOp === '.') {
@ -512,10 +497,7 @@ trait AssignOpTrait
protected function parseArrayDimStore($array, $dim, $var): string
{
$oriInAssignExpr = $this->context->inAssignExpr;
$this->context->inAssignExpr = true;
$id = $this->parseIdentifier($array);
$this->context->inAssignExpr = $oriInAssignExpr;
$id = $this->parseWritableIdentifier($array);
return $id . '.offsetSet(' . $dim . ', ' . $var . ')';
}
@ -542,9 +524,7 @@ trait AssignOpTrait
$this->fatalError($expr->expr, 'Cannot take reference of a nullsafe chain');
}
$this->context->inAssignExpr = true;
$left = $this->parseIdentifier($expr->var);
$this->context->inAssignExpr = false;
$left = $this->parseWritableIdentifier($expr->var);
if ($this->isVarExpr($expr->var)) {
if (!$this->hasVar($left)) {
@ -567,7 +547,7 @@ trait AssignOpTrait
$rightExpr = $tmpVar . ' = ' . $this->emitDynamicPropertyFetchRef($expr->expr, $expr);
} elseif ($this->isArrayDimFetch($expr->expr)) {
$left = $this->parseIdentifier($expr->var);
$array = $this->parseIdentifier($expr->expr->var);
$array = $this->parseWritableIdentifier($expr->expr->var);
if ($expr->expr->dim == null) {
$this->fatalError($expr, 'Cannot assign reference to array dim fetch without dim');
}
@ -602,10 +582,7 @@ trait AssignOpTrait
$this->checkLeftValue($expr->var);
$isset = $this->parseChainedExpr($expr->var, self::OP_ISSET);
$inAssignExpr = $this->context->inAssignExpr;
$this->context->inAssignExpr = true;
$var = $this->parseIdentifier($expr->var);
$this->context->inAssignExpr = $inAssignExpr;
$var = $this->parseWritableIdentifier($expr->var);
$propertyWriteTarget = $this->preparePropertyWriteTarget($expr->var);
if ($propertyWriteTarget !== null) {

Loading…
Cancel
Save