diff --git a/bin/compiler.php b/bin/compiler.php index f8ffa9bc..a0cb4a0e 100644 --- a/bin/compiler.php +++ b/bin/compiler.php @@ -3,37 +3,23 @@ require dirname(__DIR__) . '/vendor/autoload.php'; use PhpAot\Php\Translator; -use PhpAot\Php\Visitor; -use PhpParser\Error; -use PhpParser\NodeTraverser; -use PhpParser\ParserFactory; -use PhpParser\PrettyPrinter; define('DEBUG', true); -$traverser = new NodeTraverser; -$prettyPrinter = new PrettyPrinter\Standard; - -$traverser->addVisitor(new Visitor()); if (empty($argv[1])) { die("php compiler.php [file]\n"); } -$file = $argv[1]; -$code = file_get_contents($file); - -$parser = (new ParserFactory())->createForNewestSupportedVersion(); try { - $ast = $parser->parse($code); - $stmts = $traverser->traverse($ast); - $translator = new Translator($stmts); + $file = $argv[1]; + $translator = new Translator(); $translator->setIndent(' '); - $code = $translator->convert(); + $code = $translator->convert($file); $info = pathinfo($file); $cppFile = './tmp/' . $info['filename'] . '.cc'; $translator->save($code, $cppFile); - $translator->compileFile($cppFile); +// $translator->compileFile($cppFile); } catch (Error $error) { echo "Parse error: {$error->getMessage()}\n"; return; diff --git a/bin/encryptor.php b/bin/encryptor.php deleted file mode 100644 index b74f72e6..00000000 --- a/bin/encryptor.php +++ /dev/null @@ -1,34 +0,0 @@ -addVisitor(new \PhpAot\Php\Visitor()); - -if (empty($argv[1])) { - die("php compiler.php [file]\n"); -} - -$code = file_get_contents($argv[1]); - -$parser = (new ParserFactory())->createForNewestSupportedVersion(); -try { - $ast = $parser->parse($code); - $stmts = $traverser->traverse($ast); - $encryptor = new Encryptor($stmts); - $code = $encryptor->convert(); - var_dump($code); -// $translator->save($code, './tmp/hello.cc'); -// $translator->compileFile('./tmp/hello.cc'); -} catch (Error $error) { - echo "Parse error: {$error->getMessage()}\n"; - return; -} - diff --git a/examples/call.php b/examples/call.php new file mode 100644 index 00000000..338c62cd --- /dev/null +++ b/examples/call.php @@ -0,0 +1,16 @@ + 50 ? 1 : 2; + $a = random_int(128, 512) % 100 > 50 ? 1 : 2; $c = $a ** $b; $c--; --$c; diff --git a/examples/fcall.php b/examples/fcall.php new file mode 100644 index 00000000..ad9e5614 --- /dev/null +++ b/examples/fcall.php @@ -0,0 +1,18 @@ +foo(1, 2); \ No newline at end of file diff --git a/examples/hello.php b/examples/hello.php index ac515d8d..d6b5a1fe 100644 --- a/examples/hello.php +++ b/examples/hello.php @@ -27,5 +27,7 @@ function main(int $argc, array $argv): int echo "value:=" . ($a + $b); + echo "value:=", $a, $b; + return $a * $b; } diff --git a/examples/ns.php b/examples/ns.php new file mode 100644 index 00000000..3cc48683 --- /dev/null +++ b/examples/ns.php @@ -0,0 +1,14 @@ +stmts = $stmts; } public function parseHeaders(): string @@ -42,13 +49,37 @@ class Translator extends \PhpAot\Core\Translator $this->phpxDir = $dir; } - public function convert() + public function convert(string $file) { - $code = ''; - $code .= $this->parseHeaders(); - $code .= $this->parseStmts($this->stmts); + $parser = (new ParserFactory())->createForNewestSupportedVersion(); + $phpCode = file_get_contents($file); + $ast = $parser->parse($phpCode); - return $code; + $traverser = new NodeTraverser; + $prettyPrinter = new PrettyPrinter\Standard; + + $traverser->addVisitor(new Visitor()); + $stmts = $traverser->traverse($ast); + + $cppCode = $this->parseHeaders(); + + foreach($stmts as $v) { + $type = $v->getType(); + switch ($type) { + case 'Stmt_Namespace': + $cppCode .= $this->parseNamespaceDef($v); + break; + case 'Stmt_Class': + $cppCode .= $this->parseClassDef($v); + break; + case 'Stmt_Function': + $cppCode .= $this->parseFunctionDef($v) . PHP_EOL; + break; + default: + debug($v); + } + } + return $cppCode; } public function save($code, $file) @@ -72,9 +103,18 @@ class Translator extends \PhpAot\Core\Translator return $this->zendTypeMap[$type] ?? 'zval *'; } - private function parseFunctionDef($v) + private function parseFunctionDef($v): string { - $name = $this->parseIdentifier($v->name); + $names[] = $this->parseIdentifier($v->name); + if ($this->class) { + $names[] = strtolower($this->class); + } + if ($this->namespace) { + $names[] = strtolower(str_replace('\\', '_', $this->namespace)); + } + + $name = implode('__', array_reverse($names)); + if ($v->returnType) { $returnType = $this->getZendType($this->parseIdentifier($v->returnType)); } else { @@ -92,6 +132,11 @@ class Translator extends \PhpAot\Core\Translator return $code; } + protected function writeLog($msg) + { + echo $msg . PHP_EOL; + } + protected function parseIdentifier($expr) { $type = $expr->getType(); @@ -127,15 +172,13 @@ class Translator extends \PhpAot\Core\Translator $lines = []; foreach ($stmts as $v) { $class = $v->getType(); + $this->writeLog('Line ' . $this->getLine($v) . ': ' . $class); switch ($class) { - case 'Stmt_Function': - $lines[] = $this->parseFunctionDef($v); - break; case 'Stmt_Expression': $lines[] = $this->parseExpr($v->expr) . ';'; break; case 'Stmt_Echo': - $lines[] = $this->parseEcho($v) . ';'; + $this->parseEcho($v, $lines); break; case 'Stmt_Return': $lines[] = $this->parseReturn($v) . ';'; @@ -249,6 +292,12 @@ class Translator extends \PhpAot\Core\Translator return $this->parseTernary($expr); case 'Expr_FuncCall': return $this->parseFuncCall($expr); + case 'Expr_New': + return $this->parseNew($expr); + case 'Expr_Clone': + return $this->parseClone($expr); + case 'Name_FullyQualified': + return $expr->name; case 'Scalar_Int': case 'Scalar_Float': case 'Scalar_String': @@ -273,21 +322,14 @@ class Translator extends \PhpAot\Core\Translator } } - private function parseEcho(mixed $v) + private function parseEcho(mixed $v, &$lines): void { - return 'php::echo(' . $this->parseExprs($v->exprs) . ')'; - } - - private function parseExprs($exprs) - { - $code = ''; - foreach ($exprs as $expr) { - $code .= $this->parseExpr($expr); + foreach ($v->exprs as $expr) { + $lines[] = 'php::echo(' . $this->parseExpr($expr) . ');'; } - return $code; } - private function parseBinaryOpPlus(mixed $expr) + private function parseBinaryOpPlus(mixed $expr): string { $left = $this->parseIdentifier($expr->left); $right = $this->parseIdentifier($expr->right); @@ -295,12 +337,12 @@ class Translator extends \PhpAot\Core\Translator return $left . ' + ' . $right; } - private function parseReturn(mixed $v) + private function parseReturn(mixed $v): string { return 'return ' . $this->parseExpr($v->expr); } - private function parseBinaryOpMul(mixed $expr) + private function parseBinaryOpMul(mixed $expr): string { $left = $this->parseIdentifier($expr->left); $right = $this->parseIdentifier($expr->right); @@ -308,7 +350,7 @@ class Translator extends \PhpAot\Core\Translator return $left . ' * ' . $right; } - private function detectType($var, $expr) + private function detectType($var, $expr): string { $exprType = $expr->getType(); switch ($exprType) { @@ -326,7 +368,7 @@ class Translator extends \PhpAot\Core\Translator } } - private function parseArray($node) + private function parseArray($node): string { $items = $node->items; $list = []; @@ -350,11 +392,11 @@ class Translator extends \PhpAot\Core\Translator $name = $type->name; switch ($name) { case 'int': - return 'zend_long'; + return 'php::Int'; case 'array': return 'php::Array'; case 'float': - return 'double'; + return 'php::Float'; default: debug($type); } @@ -410,7 +452,7 @@ class Translator extends \PhpAot\Core\Translator $left = $this->parseIdentifier($expr->left); $right = $this->parseIdentifier($expr->right); - return $left . ' + ' . $right; + return 'concat(' . $left . ', ' . $right . ')'; } private function parseFor(mixed $v): string @@ -666,7 +708,7 @@ class Translator extends \PhpAot\Core\Translator return $left . ' != ' . $right; } - private function parseBinaryOpLogicalAnd(mixed $expr): string + private function parseBinaryOpLogicalAnd(Node $expr): string { $left = $this->parseIdentifier($expr->left); $right = $this->parseIdentifier($expr->right); @@ -674,7 +716,7 @@ class Translator extends \PhpAot\Core\Translator return $left . ' && ' . $right; } - private function parseBinaryOpLogicalOr(mixed $expr): string + private function parseBinaryOpLogicalOr(Node $expr): string { $left = $this->parseIdentifier($expr->left); $right = $this->parseIdentifier($expr->right); @@ -682,7 +724,7 @@ class Translator extends \PhpAot\Core\Translator return $left . ' || ' . $right; } - private function parseBinaryOpLogicalXor(mixed $expr): string + private function parseBinaryOpLogicalXor(Node $expr): string { $left = $this->parseIdentifier($expr->left); $right = $this->parseIdentifier($expr->right); @@ -690,13 +732,13 @@ class Translator extends \PhpAot\Core\Translator return $left . ' ^ ' . $right; } - private function parseBooleanNot(mixed $expr): string + private function parseBooleanNot(Node $expr): string { $expr = $this->parseExpr($expr->expr); return '!' . $expr; } - private function parseWhile(mixed $v): string + private function parseWhile(Node $v): string { $cond = $this->parseExpr($v->cond); $stmts = $v->stmts; @@ -710,7 +752,7 @@ class Translator extends \PhpAot\Core\Translator return $code; } - private function parseBinaryOpSmallerOrEqual(mixed $expr): string + private function parseBinaryOpSmallerOrEqual(Node $expr): string { $left = $this->parseIdentifier($expr->left); $right = $this->parseIdentifier($expr->right); @@ -718,7 +760,7 @@ class Translator extends \PhpAot\Core\Translator return $left . ' <= ' . $right; } - private function parseBinaryOpGreaterOrEqual(mixed $expr): string + private function parseBinaryOpGreaterOrEqual(Node $expr): string { $left = $this->parseIdentifier($expr->left); $right = $this->parseIdentifier($expr->right); @@ -726,12 +768,12 @@ class Translator extends \PhpAot\Core\Translator return $left . ' >= ' . $right; } - private function parsePrint(mixed $expr): string + private function parsePrint(Node $expr): string { return 'php::echo(' . $this->parseExpr($expr->expr) . ')'; } - private function parseDo(mixed $v): string + private function parseDo(Node $v): string { $stmts = $v->stmts; $cond = $this->parseExpr($v->cond); @@ -745,11 +787,76 @@ class Translator extends \PhpAot\Core\Translator return $code; } - private function parseBinaryOpIdentical(mixed $expr): string + private function parseBinaryOpIdentical(Node $expr): string { $left = $this->parseIdentifier($expr->left); $right = $this->parseIdentifier($expr->right); return 'php::same(' . $left . ', ' . $right . ')'; } + + private function parseNew(Node $expr): string + { + $className = $this->parseIdentifier($expr->class); + $args = $expr->args; + if (empty($args)) { + return 'new ' . $className . '()'; + } else { + return 'new ' . $className . '(' . $this->parseArgs($args) . ')'; + } + } + + private function parseClone(Node $expr): string + { + $var = $this->parseIdentifier($expr->expr); + return $var . '.clone()'; + } + + private function parseNamespaceDef(Node $node): string + { + $this->namespace = $this->parseIdentifier($node->name); + $code = ''; + foreach($node->stmts as $v2) { + $type2 = $v2->getType(); + switch ($type2) { + case 'Stmt_Class': + $code .= $this->parseClassDef($v2); + break; + case 'Stmt_Function': + $code .= $this->parseFunctionDef($v2) . PHP_EOL; + break; + case 'Stmt_Use': + foreach ($v2->uses as $use) { + $this->uses[] = $use->name->toString(); + } + break; + default: + debug($v2); + } + } + $this->namespace = ''; + $this->uses = []; + return $code; + } + + private function parseClassDef(Node $v): string + { + $this->class = $this->parseIdentifier($v->name); + $code = ''; + foreach($v->stmts as $v) { + $type = $v->getType(); + switch ($type) { + case 'Stmt_ClassConst': + case 'Stmt_Property': + break; + case 'Stmt_ClassMethod': + $code .= $this->parseFunctionDef($v) . PHP_EOL; + break; + default: + debug($v); + } + } + $this->class = ''; + return $code; + } }