pull/1/head
韩天峰 10 months ago
parent f8830edb3b
commit 4d75f54c0d
  1. 22
      bin/compiler.php
  2. 34
      bin/encryptor.php
  3. 16
      examples/call.php
  4. 16
      examples/const_c_array.php
  5. 2
      examples/expr1.php
  6. 18
      examples/fcall.php
  7. 2
      examples/hello.php
  8. 14
      examples/ns.php
  9. 22
      examples/ns2.php
  10. 191
      src/Php/Translator.php

@ -3,37 +3,23 @@
require dirname(__DIR__) . '/vendor/autoload.php'; require dirname(__DIR__) . '/vendor/autoload.php';
use PhpAot\Php\Translator; use PhpAot\Php\Translator;
use PhpAot\Php\Visitor;
use PhpParser\Error;
use PhpParser\NodeTraverser;
use PhpParser\ParserFactory;
use PhpParser\PrettyPrinter;
define('DEBUG', true); define('DEBUG', true);
$traverser = new NodeTraverser;
$prettyPrinter = new PrettyPrinter\Standard;
$traverser->addVisitor(new Visitor());
if (empty($argv[1])) { if (empty($argv[1])) {
die("php compiler.php [file]\n"); die("php compiler.php [file]\n");
} }
$file = $argv[1];
$code = file_get_contents($file);
$parser = (new ParserFactory())->createForNewestSupportedVersion();
try { try {
$ast = $parser->parse($code); $file = $argv[1];
$stmts = $traverser->traverse($ast); $translator = new Translator();
$translator = new Translator($stmts);
$translator->setIndent(' '); $translator->setIndent(' ');
$code = $translator->convert(); $code = $translator->convert($file);
$info = pathinfo($file); $info = pathinfo($file);
$cppFile = './tmp/' . $info['filename'] . '.cc'; $cppFile = './tmp/' . $info['filename'] . '.cc';
$translator->save($code, $cppFile); $translator->save($code, $cppFile);
$translator->compileFile($cppFile); // $translator->compileFile($cppFile);
} catch (Error $error) { } catch (Error $error) {
echo "Parse error: {$error->getMessage()}\n"; echo "Parse error: {$error->getMessage()}\n";
return; return;

@ -1,34 +0,0 @@
<?php
require dirname(__DIR__) . '/vendor/autoload.php';
use PhpAot\Php\Encryptor;
use PhpParser\Error;
use PhpParser\NodeTraverser;
use PhpParser\ParserFactory;
define('DEBUG', true);
$traverser = new NodeTraverser;
$traverser->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;
}

@ -0,0 +1,16 @@
<?php
function fn1()
{
echo "fn1\n";
fn2();
}
function fn2()
{
echo __FUNCTION__ . "\n";
}
fn1();
include __DIR__ . '/expr1.php';
expr1();

@ -0,0 +1,16 @@
<?php
$bytes = random_bytes(2 * 1024 * 1024);
$out = 'static const unsigned char data[] = {';
for ($i = 0; $i < strlen($bytes); $i++) {
$out .= ord($bytes[$i]) . ', ';
if ($i % 32 == 0) {
$out .= "\n\t";
}
}
$out .= '};' . PHP_EOL;
file_put_contents(__DIR__ . '/const_c_array.c', $out);

@ -6,7 +6,7 @@ function expr1()
echo $b . "\n"; echo $b . "\n";
} }
$a = random_int() % 100 > 50 ? 1 : 2; $a = random_int(128, 512) % 100 > 50 ? 1 : 2;
$c = $a ** $b; $c = $a ** $b;
$c--; $c--;
--$c; --$c;

@ -0,0 +1,18 @@
<?php
function foo(int $a, int $b): int {
return $a + $b;
}
class A {
function foo(int $a, int $b): int
{
return $a + $b;
}
}
//foo(1, 2);
//max(1, 2, 3);
$o = new A;
$o->foo(1, 2);

@ -27,5 +27,7 @@ function main(int $argc, array $argv): int
echo "value:=" . ($a + $b); echo "value:=" . ($a + $b);
echo "value:=", $a, $b;
return $a * $b; return $a * $b;
} }

@ -0,0 +1,14 @@
<?php
namespace Foo1\Bar;
class Tex {
const FOO = 1;
public $a = 1;
public function foo(int $a, int $b): int
{
$o = new \stdClass($a, $b);
$c = clone $o;
return $a + $b;
}
}

@ -0,0 +1,22 @@
<?php
namespace Foo1\Bar {
use \StdClass;
function foo(int $a, int $b): int
{
return $a + $b;
}
function foo2(): stdClass
{
return new stdClass();
}
}
namespace Foo2\Bar {
function foo2(int $a, int $b): int
{
return $a + $b;
}
}

@ -5,10 +5,14 @@ namespace PhpAot\Php;
use PhpParser\Node; use PhpParser\Node;
use PhpParser\Node\Expr\Variable; use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier; use PhpParser\Node\Identifier;
use PhpAot\Php\Visitor;
use PhpParser\Error;
use PhpParser\NodeTraverser;
use PhpParser\ParserFactory;
use PhpParser\PrettyPrinter;
class Translator extends \PhpAot\Core\Translator class Translator extends \PhpAot\Core\Translator
{ {
protected array $stmts;
protected string $phpxDir = '~/workspace/phpx'; protected string $phpxDir = '~/workspace/phpx';
protected string $lang = 'PHP'; protected string $lang = 'PHP';
protected array $typeMap = []; protected array $typeMap = [];
@ -21,11 +25,14 @@ class Translator extends \PhpAot\Core\Translator
'phpx.h', 'phpx.h',
]; ];
protected string $namespace = '';
protected array $uses = [];
protected string $class = '';
const PREFIX = 'php_'; const PREFIX = 'php_';
public function __construct(array $stmts) public function __construct()
{ {
$this->stmts = $stmts;
} }
public function parseHeaders(): string public function parseHeaders(): string
@ -42,13 +49,37 @@ class Translator extends \PhpAot\Core\Translator
$this->phpxDir = $dir; $this->phpxDir = $dir;
} }
public function convert() public function convert(string $file)
{ {
$code = ''; $parser = (new ParserFactory())->createForNewestSupportedVersion();
$code .= $this->parseHeaders(); $phpCode = file_get_contents($file);
$code .= $this->parseStmts($this->stmts); $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) public function save($code, $file)
@ -72,9 +103,18 @@ class Translator extends \PhpAot\Core\Translator
return $this->zendTypeMap[$type] ?? 'zval *'; 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) { if ($v->returnType) {
$returnType = $this->getZendType($this->parseIdentifier($v->returnType)); $returnType = $this->getZendType($this->parseIdentifier($v->returnType));
} else { } else {
@ -92,6 +132,11 @@ class Translator extends \PhpAot\Core\Translator
return $code; return $code;
} }
protected function writeLog($msg)
{
echo $msg . PHP_EOL;
}
protected function parseIdentifier($expr) protected function parseIdentifier($expr)
{ {
$type = $expr->getType(); $type = $expr->getType();
@ -127,15 +172,13 @@ class Translator extends \PhpAot\Core\Translator
$lines = []; $lines = [];
foreach ($stmts as $v) { foreach ($stmts as $v) {
$class = $v->getType(); $class = $v->getType();
$this->writeLog('Line ' . $this->getLine($v) . ': ' . $class);
switch ($class) { switch ($class) {
case 'Stmt_Function':
$lines[] = $this->parseFunctionDef($v);
break;
case 'Stmt_Expression': case 'Stmt_Expression':
$lines[] = $this->parseExpr($v->expr) . ';'; $lines[] = $this->parseExpr($v->expr) . ';';
break; break;
case 'Stmt_Echo': case 'Stmt_Echo':
$lines[] = $this->parseEcho($v) . ';'; $this->parseEcho($v, $lines);
break; break;
case 'Stmt_Return': case 'Stmt_Return':
$lines[] = $this->parseReturn($v) . ';'; $lines[] = $this->parseReturn($v) . ';';
@ -249,6 +292,12 @@ class Translator extends \PhpAot\Core\Translator
return $this->parseTernary($expr); return $this->parseTernary($expr);
case 'Expr_FuncCall': case 'Expr_FuncCall':
return $this->parseFuncCall($expr); 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_Int':
case 'Scalar_Float': case 'Scalar_Float':
case 'Scalar_String': 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 ($v->exprs as $expr) {
foreach ($exprs as $expr) { $lines[] = 'php::echo(' . $this->parseExpr($expr) . ');';
$code .= $this->parseExpr($expr);
} }
return $code;
} }
private function parseBinaryOpPlus(mixed $expr) private function parseBinaryOpPlus(mixed $expr): string
{ {
$left = $this->parseIdentifier($expr->left); $left = $this->parseIdentifier($expr->left);
$right = $this->parseIdentifier($expr->right); $right = $this->parseIdentifier($expr->right);
@ -295,12 +337,12 @@ class Translator extends \PhpAot\Core\Translator
return $left . ' + ' . $right; return $left . ' + ' . $right;
} }
private function parseReturn(mixed $v) private function parseReturn(mixed $v): string
{ {
return 'return ' . $this->parseExpr($v->expr); return 'return ' . $this->parseExpr($v->expr);
} }
private function parseBinaryOpMul(mixed $expr) private function parseBinaryOpMul(mixed $expr): string
{ {
$left = $this->parseIdentifier($expr->left); $left = $this->parseIdentifier($expr->left);
$right = $this->parseIdentifier($expr->right); $right = $this->parseIdentifier($expr->right);
@ -308,7 +350,7 @@ class Translator extends \PhpAot\Core\Translator
return $left . ' * ' . $right; return $left . ' * ' . $right;
} }
private function detectType($var, $expr) private function detectType($var, $expr): string
{ {
$exprType = $expr->getType(); $exprType = $expr->getType();
switch ($exprType) { switch ($exprType) {
@ -326,7 +368,7 @@ class Translator extends \PhpAot\Core\Translator
} }
} }
private function parseArray($node) private function parseArray($node): string
{ {
$items = $node->items; $items = $node->items;
$list = []; $list = [];
@ -350,11 +392,11 @@ class Translator extends \PhpAot\Core\Translator
$name = $type->name; $name = $type->name;
switch ($name) { switch ($name) {
case 'int': case 'int':
return 'zend_long'; return 'php::Int';
case 'array': case 'array':
return 'php::Array'; return 'php::Array';
case 'float': case 'float':
return 'double'; return 'php::Float';
default: default:
debug($type); debug($type);
} }
@ -410,7 +452,7 @@ class Translator extends \PhpAot\Core\Translator
$left = $this->parseIdentifier($expr->left); $left = $this->parseIdentifier($expr->left);
$right = $this->parseIdentifier($expr->right); $right = $this->parseIdentifier($expr->right);
return $left . ' + ' . $right; return 'concat(' . $left . ', ' . $right . ')';
} }
private function parseFor(mixed $v): string private function parseFor(mixed $v): string
@ -666,7 +708,7 @@ class Translator extends \PhpAot\Core\Translator
return $left . ' != ' . $right; return $left . ' != ' . $right;
} }
private function parseBinaryOpLogicalAnd(mixed $expr): string private function parseBinaryOpLogicalAnd(Node $expr): string
{ {
$left = $this->parseIdentifier($expr->left); $left = $this->parseIdentifier($expr->left);
$right = $this->parseIdentifier($expr->right); $right = $this->parseIdentifier($expr->right);
@ -674,7 +716,7 @@ class Translator extends \PhpAot\Core\Translator
return $left . ' && ' . $right; return $left . ' && ' . $right;
} }
private function parseBinaryOpLogicalOr(mixed $expr): string private function parseBinaryOpLogicalOr(Node $expr): string
{ {
$left = $this->parseIdentifier($expr->left); $left = $this->parseIdentifier($expr->left);
$right = $this->parseIdentifier($expr->right); $right = $this->parseIdentifier($expr->right);
@ -682,7 +724,7 @@ class Translator extends \PhpAot\Core\Translator
return $left . ' || ' . $right; return $left . ' || ' . $right;
} }
private function parseBinaryOpLogicalXor(mixed $expr): string private function parseBinaryOpLogicalXor(Node $expr): string
{ {
$left = $this->parseIdentifier($expr->left); $left = $this->parseIdentifier($expr->left);
$right = $this->parseIdentifier($expr->right); $right = $this->parseIdentifier($expr->right);
@ -690,13 +732,13 @@ class Translator extends \PhpAot\Core\Translator
return $left . ' ^ ' . $right; return $left . ' ^ ' . $right;
} }
private function parseBooleanNot(mixed $expr): string private function parseBooleanNot(Node $expr): string
{ {
$expr = $this->parseExpr($expr->expr); $expr = $this->parseExpr($expr->expr);
return '!' . $expr; return '!' . $expr;
} }
private function parseWhile(mixed $v): string private function parseWhile(Node $v): string
{ {
$cond = $this->parseExpr($v->cond); $cond = $this->parseExpr($v->cond);
$stmts = $v->stmts; $stmts = $v->stmts;
@ -710,7 +752,7 @@ class Translator extends \PhpAot\Core\Translator
return $code; return $code;
} }
private function parseBinaryOpSmallerOrEqual(mixed $expr): string private function parseBinaryOpSmallerOrEqual(Node $expr): string
{ {
$left = $this->parseIdentifier($expr->left); $left = $this->parseIdentifier($expr->left);
$right = $this->parseIdentifier($expr->right); $right = $this->parseIdentifier($expr->right);
@ -718,7 +760,7 @@ class Translator extends \PhpAot\Core\Translator
return $left . ' <= ' . $right; return $left . ' <= ' . $right;
} }
private function parseBinaryOpGreaterOrEqual(mixed $expr): string private function parseBinaryOpGreaterOrEqual(Node $expr): string
{ {
$left = $this->parseIdentifier($expr->left); $left = $this->parseIdentifier($expr->left);
$right = $this->parseIdentifier($expr->right); $right = $this->parseIdentifier($expr->right);
@ -726,12 +768,12 @@ class Translator extends \PhpAot\Core\Translator
return $left . ' >= ' . $right; return $left . ' >= ' . $right;
} }
private function parsePrint(mixed $expr): string private function parsePrint(Node $expr): string
{ {
return 'php::echo(' . $this->parseExpr($expr->expr) . ')'; return 'php::echo(' . $this->parseExpr($expr->expr) . ')';
} }
private function parseDo(mixed $v): string private function parseDo(Node $v): string
{ {
$stmts = $v->stmts; $stmts = $v->stmts;
$cond = $this->parseExpr($v->cond); $cond = $this->parseExpr($v->cond);
@ -745,11 +787,76 @@ class Translator extends \PhpAot\Core\Translator
return $code; return $code;
} }
private function parseBinaryOpIdentical(mixed $expr): string private function parseBinaryOpIdentical(Node $expr): string
{ {
$left = $this->parseIdentifier($expr->left); $left = $this->parseIdentifier($expr->left);
$right = $this->parseIdentifier($expr->right); $right = $this->parseIdentifier($expr->right);
return 'php::same(' . $left . ', ' . $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;
}
} }

Loading…
Cancel
Save