diff --git a/examples/binary-tree.php b/examples/binary-tree.php new file mode 100644 index 00000000..9db2cd7c --- /dev/null +++ b/examples/binary-tree.php @@ -0,0 +1,93 @@ + $iterations]; + do { + $minDepth += 2; + if ($minDepth <= $maxDepth) { + $iterations >>= 2; + $depthIterations[$minDepth] = $iterations; + } + } while ($minDepth <= $maxDepth); + + $size = 128; + $shmId = shmop_open(ftok(__FILE__, 'b'), 'c', 0644, $size * (count($depthIterations) + 1)); + $PIDs = []; + $n = 0; + foreach ($depthIterations as $d => $i) { + $PIDs[] = startWorker($d, $i, ++$n, $size, $shmId); + } + foreach ($PIDs as $PID) { + pcntl_waitpid($PID, $status); + } + foreach (range(1, count($depthIterations)) as $n) { + echo trim(shmop_read($shmId, $size * ($n - 1), $size)), PHP_EOL; + } + shmop_delete($shmId); + + echo "long lived tree of depth $maxDepth\t check: ", checkTree($longLivedTree), PHP_EOL; +} + +main(); \ No newline at end of file diff --git a/examples/unset.php b/examples/unset.php new file mode 100644 index 00000000..42664aab --- /dev/null +++ b/examples/unset.php @@ -0,0 +1,11 @@ +hello = 'world'; + unset($array['hello'], $name, $object->hello); + + var_dump($array, $object); +} diff --git a/src/Php/Encryptor.php b/src/Php/Encryptor.php index bd90fe6b..9ca7241a 100644 --- a/src/Php/Encryptor.php +++ b/src/Php/Encryptor.php @@ -125,7 +125,7 @@ class Encryptor extends \PhpAot\Core\Translator case 'Stmt_Switch': break; default: - debug($node); + abort($node); } } @@ -172,7 +172,7 @@ class Encryptor extends \PhpAot\Core\Translator case 'Stmt_Switch': break; default: - debug($v); + abort($v); } } $code = ''; @@ -218,7 +218,7 @@ class Encryptor extends \PhpAot\Core\Translator $this->parseConstFetch($expr); break; default: - debug($expr); + abort($expr); } } @@ -276,7 +276,7 @@ class Encryptor extends \PhpAot\Core\Translator case 'Expr_Array': return 'php::Array'; default: - debug($expr); + abort($expr); } } @@ -310,7 +310,7 @@ class Encryptor extends \PhpAot\Core\Translator case 'float': return 'double'; default: - debug($type); + abort($type); } } diff --git a/src/Php/Translator.php b/src/Php/Translator.php index a7692696..a0d976fd 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -90,7 +90,7 @@ class Translator extends \PhpAot\Core\Translator $cppCode .= $this->parseFunctionDef($v) . PHP_EOL; break; default: - debug($v); + abort($v); } } return $cppCode; @@ -213,7 +213,7 @@ class Translator extends \PhpAot\Core\Translator $lines = []; foreach ($stmts as $v) { $class = $v->getType(); - // $this->writeLog('Line ' . $this->getLine($v) . ': ' . $class); + $this->writeLog('Line ' . $this->getLine($v) . ': ' . $class); switch ($class) { case 'Stmt_Expression': $lines[] = $this->parseExpr($v->expr) . ';'; @@ -245,8 +245,11 @@ class Translator extends \PhpAot\Core\Translator case 'Stmt_Global': $lines[] = $this->parseGlobal($v); break; + case 'Stmt_Unset': + $lines[] = $this->parseUnset($v); + break; default: - debug($v); + abort($v); } } $code = ''; @@ -259,6 +262,7 @@ class Translator extends \PhpAot\Core\Translator private function parseExpr(mixed $expr) { $type = $expr->getType(); + $this->writeLog('Line ' . $this->getLine($expr) . ': ' . $type); switch ($type) { case 'Expr_Assign': return $this->parseAssign($expr); @@ -320,6 +324,8 @@ class Translator extends \PhpAot\Core\Translator return $this->parseArray($expr); case 'Expr_ArrayDimFetch': return $this->parseArrayDimFetch($expr); + case 'Expr_PropertyFetch': + return $this->parsePropertyFetch($expr); case 'Expr_BinaryOp_ShiftLeft': return $this->parseBinaryOpShiftLeft($expr); case 'Expr_BinaryOp_ShiftRight': @@ -364,17 +370,40 @@ class Translator extends \PhpAot\Core\Translator case 'Expr_Exit': return $this->parseExit($expr); default: - debug($expr); + abort($expr); } } private function parseAssign(Node $v): string { - $var = $this->parseIdentifier($v->var); - $expr = $this->parseExpr($v->expr); + $left = $v->var; + $right = $v->expr; + + if ($left->getType() === 'Expr_ArrayDimFetch') { + $array = $this->parseIdentifier($left->var); + $code = ''; + // 这是 PHP 的初始化+赋值写法,需要先创建数组 + if (!$this->hasVar($array)) { + $this->addVar($array, self::TYPE_VAR); + $code .= self::TYPE_ARRAY . " $array;\n" . $this->getIndent(); + } + $dim = $this->parseIdentifier($left->dim); + return $code . "$array.offsetSet($dim, " . $this->parseExpr($right) . ")"; + } elseif ($left->getType() === 'Expr_PropertyFetch') { + $array = $this->parseIdentifier($left->var); + $propName = $this->parseIdentifier($left->name); + return "$array.setProperty(\"$propName\", " . $this->parseExpr($right) . ")"; + } + + $var = $this->parseIdentifier($left); + $expr = $this->parseExpr($right); if (!$this->hasVar($var)) { - $type = $this->detectType($v->expr); + if ($right->getType() === 'Expr_New') { + $type = self::TYPE_OBJECT; + } else { + $type = $this->detectType($right); + } $this->addVar($var, $type); return $type . ' ' . $var . ' = ' . $expr; } else { @@ -493,7 +522,7 @@ class Translator extends \PhpAot\Core\Translator case 'bool': return self::TYPE_BOOL; default: - debug($type); + abort($type); } } @@ -928,9 +957,9 @@ class Translator extends \PhpAot\Core\Translator $className = $this->parseIdentifier($expr->class); $args = $expr->args; if (empty($args)) { - return 'new ' . $className . '()'; + return 'php::newObject("' . $className . '")'; } else { - return 'new ' . $className . '(' . $this->parseArgs($args) . ')'; + return 'php::newObject("' . $className . '"(' . $this->parseArgs($args) . ')'; } } @@ -959,7 +988,7 @@ class Translator extends \PhpAot\Core\Translator } break; default: - debug($v2); + abort($v2); } } $this->namespace = ''; @@ -981,7 +1010,7 @@ class Translator extends \PhpAot\Core\Translator $code .= $this->parseFunctionDef($v) . PHP_EOL; break; default: - debug($v); + abort($v); } } $this->class = ''; @@ -1081,4 +1110,33 @@ class Translator extends \PhpAot\Core\Translator { return 'php::exit(' . $this->parseIdentifier($node->expr) . ')'; } + + private function parseUnset(Node $node): string + { + $vars = $node->vars; + $lines = []; + foreach ($vars as $var) { + $type = $var->getType(); + if ($type === 'Expr_ArrayDimFetch') { + $array = $this->parseIdentifier($var->var); + $dim = $this->parseIdentifier($var->dim); + $lines[] = $array . '.offsetUnset(' . $dim . ');'; + } elseif ($type === 'Expr_PropertyFetch') { + $object = $this->parseIdentifier($var->var); + $propName = $this->parseIdentifier($var->name); + $lines[] = $object . '.unsetProperty("' . $propName . '");'; + } elseif ($type === 'Expr_Variable') { + $name = $this->parseIdentifier($var); + $lines[] = "$name.unset();"; + } else { + abort($var); + } + } + return implode(PHP_EOL . $this->getIndent(), $lines); + } + + private function parsePropertyFetch(mixed $expr): string + { + return $this->parseIdentifier($expr->var) . '.getProperty(' . $this->parseIdentifier($expr->name) . ')'; + } } diff --git a/src/Python/Translator.php b/src/Python/Translator.php index 76f246c0..db1af2c9 100644 --- a/src/Python/Translator.php +++ b/src/Python/Translator.php @@ -84,7 +84,7 @@ class Translator extends \PhpAot\Core\Translator return $this->parseBinOp($attr); default: var_dump(__METHOD__, __LINE__); - debug($attr); + abort($attr); } } @@ -106,7 +106,7 @@ class Translator extends \PhpAot\Core\Translator case 'Attribute': return $this->parseAttribute($fn->value) . '->' . $fn->attr; default: - debug($fn); + abort($fn); } } @@ -240,7 +240,7 @@ class Translator extends \PhpAot\Core\Translator case 'GeneratorExp': return $this->parseGeneratorExp($value); default: - debug($value); + abort($value); break; } } @@ -257,7 +257,7 @@ class Translator extends \PhpAot\Core\Translator $_args[] = $slice->step ? $this->parseTarget($slice->step) : 'null'; return 'PyCore::slice(' . implode(', ', $_args) . ')'; } else { - debug($slice); + abort($slice); } } @@ -298,7 +298,7 @@ class Translator extends \PhpAot\Core\Translator case 'Not': return '!' . $operand; default: - debug($target); + abort($target); break; } break; @@ -329,7 +329,7 @@ class Translator extends \PhpAot\Core\Translator case 'ListComp': return $this->parseListComp($target); default: - debug($target); + abort($target); break; } } @@ -386,7 +386,7 @@ class Translator extends \PhpAot\Core\Translator if ($test->ops) { $ops = $test->ops; if (count($ops) != 1) { - debug($test); + abort($test); } $op = $ops[0]->_type; $comparators = $test->comparators; @@ -458,7 +458,7 @@ class Translator extends \PhpAot\Core\Translator case 'Attribute': return $this->parseAttribute($iter); default: - debug($iter); + abort($iter); } } @@ -475,7 +475,7 @@ class Translator extends \PhpAot\Core\Translator return $value . '[' . $this->parseSlice($node->slice) . ']'; } } else { - debug($node); + abort($node); } } @@ -603,7 +603,7 @@ class Translator extends \PhpAot\Core\Translator $line = $this->parseCall($node) . ';'; break; default: - debug($node); + abort($node); $line = ''; break; } @@ -772,7 +772,7 @@ class Translator extends \PhpAot\Core\Translator $code = '[' . PHP_EOL; foreach ($dict->values as $k => $v) { if (empty($dict->keys[$k])) { - debug($v); + abort($v); } $key = $dict->keys[$k]; $this->indentLevel++; @@ -791,7 +791,7 @@ class Translator extends \PhpAot\Core\Translator case 'Or': return $this->parseOr($value->values); default: - debug($value); + abort($value); break; } } @@ -943,7 +943,7 @@ class Translator extends \PhpAot\Core\Translator $expr = $this->parseValue($value->value); if ($value->format_spec and $value->format_spec->_type == 'JoinedStr') { if (count($value->format_spec->values) != 1) { - debug($value); + abort($value); } $format = $value->format_spec->values[0]->value; if ($format[0] == '.' and $format[-1] == 'f') { @@ -974,6 +974,6 @@ class Translator extends \PhpAot\Core\Translator private function parseGeneratorExp($value) { - debug($value); + abort($value); } } diff --git a/src/functions.php b/src/functions.php index 4f7e5b7e..bdceaa02 100644 --- a/src/functions.php +++ b/src/functions.php @@ -2,7 +2,7 @@ use PhpAot\Core\Translator; -function debug($v) +function abort($v) { /** * @var $translator Translator @@ -25,13 +25,13 @@ function debug($v) function if_empty_debug($if_expr, $v) { if (empty($if_expr)) { - debug($v); + abort($v); } } function if_not_empty_debug($if_expr, $v) { if (!empty($if_expr)) { - debug($v); + abort($v); } }