diff --git a/examples/right-assoc.php b/examples/right-assoc.php new file mode 100644 index 00000000..0c1cdd6a --- /dev/null +++ b/examples/right-assoc.php @@ -0,0 +1,9 @@ +val = $i->val = $j->val = 999; + +$h->val = 343; +var_dump($h); +var_dump($i); +var_dump($j); + diff --git a/src/Php/AstNodeType.php b/src/Php/AstNodeType.php index a81acf47..fee75bee 100644 --- a/src/Php/AstNodeType.php +++ b/src/Php/AstNodeType.php @@ -8,6 +8,10 @@ use PhpParser\Node; trait AstNodeType { + protected function isArrayDimFetch(NodeAbstract $expr): bool + { + return $expr instanceof Expr\ArrayDimFetch; + } protected function isVarExpr(NodeAbstract $expr): bool { return $expr instanceof Expr\Variable; diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 53ffc085..c361135a 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -807,39 +807,56 @@ class CompilerBase extends \PhpAot\Core\Translator return "$array.setProperty($propName, " . $this->trimBrackets($this->parseExpr($right)) . ")"; } + protected function parseRightAssociativeAssign(NodeAbstract $left, Node\Expr\Assign $right): string + { + $checkVarFn = function ($var) { + if ($this->isArrayDimFetch($var)) { + $array = $this->parseIdentifier($var->var); + if (!$this->hasVar($array)) { + $this->addLocalVar($array, self::TYPE_ARRAY); + } + } + }; + + $checkVarFn($left); + $chain[] = $left; + $next = $right; + while ($next->getType() === 'Expr_Assign') { + $var = $next->var; + $checkVarFn($var); + $chain[] = $var; + $next = $next->expr; + } + + $tmpVar = $this->genTmpVarName(); + $this->addLocalVar($tmpVar, self::TYPE_VAR); + + // 翻转赋值链 + $chain = array_reverse($chain); + $list = []; + + $list[] = $this->getIndent() . $tmpVar . ' = ' . $this->parseExpr($next); + $right = new Variable($tmpVar); + foreach ($chain as $var) { + $list[] = $this->getIndent() . $this->parseFinallyAssign($var, $right); + } + return implode(";\n" . $this->getIndent(), $list); + } + protected function parseAssign(Node\Expr\Assign $v): string { $left = $v->var; $right = $v->expr; - if ($left->getType() === self::EXPR_ARRAY_DIM_FETCH) { + if ($right->getType() === 'Expr_Assign') { + return $this->parseRightAssociativeAssign($left, $right); + } elseif ($left->getType() === self::EXPR_ARRAY_DIM_FETCH) { return $this->parseAssignArrayDim($left, $right); } elseif ($left->getType() === 'Expr_StaticPropertyFetch') { $class = $this->identifierToStr($left->class); $propName = $this->identifierToStr($left->name); $value = $this->trimBrackets($this->parseExpr($right)); return "php::setStaticProperty($class, $propName, $value)"; - } elseif ($right->getType() === 'Expr_Assign') { - $chain[] = $left; - while ($right->getType() === 'Expr_Assign') { - $chain[] = $right->var; - $right = $right->expr; - } - // 翻转赋值链 - $chain = array_reverse($chain); - // 取最后一个变量作为第一行的 left,右值为表达式 - $left = array_shift($chain); - $list[] = $this->parseFinallyAssign($left, $right); - /** - * 构造赋值链 - * a = b = c = d = (expr) -> d = (expr); c = d; b = c; a = b; - */ - $right = $left; - foreach ($chain as $left) { - $list[] = $this->getIndent() . $this->parseFinallyAssign($left, $right); - $right = $left; - } - return implode(";\n" . $this->getIndent(), $list); } return $this->parseFinallyAssign($left, $right); } @@ -870,6 +887,7 @@ class CompilerBase extends \PhpAot\Core\Translator $this->indentLevel--; return $code . '}'; } + $this->inAssignExpr = true; $var = $this->parseIdentifier($left); $this->inAssignExpr = false; @@ -1472,10 +1490,15 @@ class CompilerBase extends \PhpAot\Core\Translator { $var = $this->parseIdentifier($node->var); if ($node->dim === null) { - $this->fatalError($node, 'Unsupported operand types: null + array'); + if (!$write) { + $this->fatalError($node, 'Cannot use [] for reading'); + } else { + return $var . '.newItem()'; + } + } else { + $dim = $this->trimBrackets($this->parseIdentifier($node->dim)); + return $var . '.item(' . $dim . ', ' . $this->escapeBool($write) . ')'; } - $dim = $this->parseIdentifier($node->dim); - return $var . '.item(' . $this->trimBrackets($dim) . ', ' . $this->escapeBool($write) . ')'; } protected function parseArrayDimStore($array, $dim, $var): string diff --git a/tests/aot/right-associative.phpt b/tests/aot/right-associative.phpt new file mode 100644 index 00000000..b6e12d8d --- /dev/null +++ b/tests/aot/right-associative.phpt @@ -0,0 +1,65 @@ +--TEST-- +right associative +--FILE-- +val = $i->val = $j->val = 999; +var_dump($h); +var_dump($i); +var_dump($j); + +$k['val'] = $l['val'] = $m['val'] = 888; +var_dump($k); +var_dump($l); +var_dump($m); +?> +--EXPECTF-- +int(100) +int(100) +int(100) +array(1) { + [0]=> + int(23) +} +array(1) { + [0]=> + int(23) +} +array(1) { + [0]=> + int(23) +} +object(stdClass)#1 (1) { + ["val"]=> + int(999) +} +object(stdClass)#1 (1) { + ["val"]=> + int(999) +} +object(stdClass)#1 (1) { + ["val"]=> + int(999) +} +array(1) { + ["val"]=> + int(888) +} +array(1) { + ["val"]=> + int(888) +} +array(1) { + ["val"]=> + int(888) +} \ No newline at end of file