refactor(compiler): 使用节点属性替代上下文标识处理属性写操作

pull/14/head
韩天峰 2 months ago
parent bffa660427
commit dfc94ac09e
  1. 90
      src/Php/CompilerBase.php
  2. 6
      src/Php/Context/FunctionContext.php

@ -108,6 +108,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';
protected const string ATTR_PROPERTY_FETCH_UPDATE = 'aotPropertyFetchUpdate';
/**
* Keyword methods (to* builtins) with mandated return types.
@ -628,7 +629,7 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont
case 'Expr_ArrayDimFetch':
return $this->parseArrayDimFetch($expr);
case 'Expr_PropertyFetch':
return $this->parsePropertyFetch($expr, $this->context->inAssignExpr);
return $this->parsePropertyFetch($expr);
case 'Expr_NullsafePropertyFetch':
return $this->parseNullsafePropertyFetch($expr);
case 'Expr_NullsafeMethodCall':
@ -3018,11 +3019,26 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont
return $this->parseArrayDimFetchUpdate($expr);
}
$oriInAssignExpr = $this->context->inAssignExpr;
$this->context->inAssignExpr = true;
$code = $this->parseIdentifier($expr);
$this->context->inAssignExpr = $oriInAssignExpr;
return $code;
if ($expr instanceof Expr\PropertyFetch) {
return $this->parsePropertyFetchUpdate($expr);
}
if ($expr instanceof Expr\NullsafePropertyFetch) {
return $this->parseNullsafePropertyFetchUpdate($expr);
}
return $this->parseIdentifier($expr);
}
protected function parseNodeWithUpdateAttribute(NodeAbstract $node, string $attribute, bool $update, callable $parser): string
{
$attributes = $node->getAttributes();
$node->setAttribute($attribute, $update);
try {
return $parser();
} finally {
$node->setAttributes($attributes);
}
}
protected function parseArrayDimFetchRead(Expr\ArrayDimFetch $node): string
@ -3037,13 +3053,12 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont
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);
}
return $this->parseNodeWithUpdateAttribute(
$node,
self::ATTR_ARRAY_DIM_FETCH_UPDATE,
$update,
fn() => $this->parseArrayDimFetch($node)
);
}
protected function isArrayDimFetchUpdate(Expr\ArrayDimFetch $node): bool
@ -3061,9 +3076,7 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont
return $this->parseStdContainerDimFetch($node);
}
$var = $write && $node->var instanceof Expr\ArrayDimFetch
? $this->parseArrayDimFetchUpdate($node->var)
: $this->parseIdentifier($node->var);
$var = $write ? $this->parseWritableIdentifier($node->var) : $this->parseIdentifier($node->var);
if ($this->isVarExpr($node->var)) {
if ($var === 'GLOBALS') {
return $this->parseGlobalsArrayDimFetch($node);
@ -3094,10 +3107,7 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont
return $var . '.newItem()';
}
} else {
$oriInAssignExpr = $this->context->inAssignExpr;
$this->context->inAssignExpr = false;
$dim = $this->parseIdentifier($node->dim);
$this->context->inAssignExpr = $oriInAssignExpr;
return $var . '.item(' . $dim . ', ' . $this->escapeBool($write) . ')';
}
}
@ -5124,12 +5134,38 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont
return null;
}
protected function parsePropertyFetch(Expr\PropertyFetch $expr, bool $update = false): string
protected function parsePropertyFetchRead(Expr\PropertyFetch $expr): string
{
return $this->parsePropertyFetchWithUpdate($expr, false);
}
protected function parsePropertyFetchUpdate(Expr\PropertyFetch $expr): string
{
return $this->parsePropertyFetchWithUpdate($expr, true);
}
protected function parsePropertyFetchWithUpdate(Expr\PropertyFetch $expr, bool $update): string
{
return $this->parseNodeWithUpdateAttribute(
$expr,
self::ATTR_PROPERTY_FETCH_UPDATE,
$update,
fn() => $this->parsePropertyFetch($expr)
);
}
protected function isPropertyFetchUpdate(Expr\PropertyFetch|Expr\NullsafePropertyFetch $expr): bool
{
return $expr->getAttribute(self::ATTR_PROPERTY_FETCH_UPDATE, false) === true;
}
protected function parsePropertyFetch(Expr\PropertyFetch $expr): string
{
$update = $this->isPropertyFetchUpdate($expr);
$object = $expr->var;
$property = $expr->name;
$id = $this->getPropertyIdentifier($expr, $object, $property);
$objectName = $this->parseIdentifier($object);
$objectName = $update ? $this->parseWritableIdentifier($object) : $this->parseIdentifier($object);
if ($this->isVarExpr($object) and !$this->hasVar($objectName)) {
$this->errorUndefinedVariable($object);
}
@ -7460,6 +7496,16 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont
return $this->parseNullsafeExpr($expr);
}
protected function parseNullsafePropertyFetchUpdate(Expr\NullsafePropertyFetch $expr): string
{
return $this->parseNodeWithUpdateAttribute(
$expr,
self::ATTR_PROPERTY_FETCH_UPDATE,
true,
fn() => $this->parseNullsafePropertyFetch($expr)
);
}
protected function parseNullsafeMethodCall(Expr\NullsafeMethodCall $expr): string
{
return $this->parseNullsafeExpr($expr);
@ -7500,12 +7546,12 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont
$tmpFn = $this->genTmpVarName();
$code = $comment . PHP_EOL . 'auto ' . $tmpFn . ' = [&]() -> ' . self::TYPE_VAR . '{' . PHP_EOL;
$update = $this->escapeBool($this->context->inAssignExpr);
foreach ($list as $key => $item) {
$tmpVar = $this->addTmpVar($key !== $last ? self::TYPE_OBJECT : self::TYPE_VAR);
$code .= "if ({$object}.isNull()) { return " . self::VALUE_NULL . '; }';
if ($item[0] == 'property') {
$update = $this->escapeBool($this->isPropertyFetchUpdate($item[2]));
$code .= $this->getIndent() . "{$tmpVar} = {$object}.attr({$item[1]}, {$update});";
} else {
$beforeStmtCount = count($this->context->beforeStmtLines);

@ -59,10 +59,6 @@ class FunctionContext
/** True if any continue N (N > 1) appears in this function. */
public bool $hasMultiLevelContinue = false;
/**
* 赋值表达式的左值,写操作,右值为读操作.
*/
public bool $inAssignExpr = false;
public array $beforeStmtLines = [];
public array $afterStmtLines = [];
public array $objectProps;
@ -96,7 +92,6 @@ class FunctionContext
$this->inClosure = false;
$this->closureReturnTypeCheck = null;
$this->closureReturnTypeStr = '';
$this->inAssignExpr = false;
}
public function enterScope(): void
@ -123,6 +118,5 @@ class FunctionContext
$this->scopeLayouts = [];
$this->scopeLevel = 0;
$this->inLoop = false;
$this->inAssignExpr = false;
}
}

Loading…
Cancel
Save