pull/1/head
韩天峰 8 months ago
parent 1ab142406a
commit f2d6ee2b63
  1. 111
      .clang-format
  2. 5
      bin/bootstrap.php
  3. 7
      bin/compiler.php
  4. 6
      bin/linker.php
  5. 7
      examples/binary-tree.php
  6. 8
      src/Php/ReturnTypeChanged.php
  7. 239
      src/Php/Translator.php

@ -0,0 +1,111 @@
---
Language: Cpp
# BasedOnStyle: Google
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
- Regex: '^<.*\.h>'
Priority: 1
- Regex: '^<.*'
Priority: 2
- Regex: '.*'
Priority: 3
IncludeIsMainRegex: '([-_](test|unittest))?$'
IndentCaseLabels: false
IndentPPDirectives: None
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: false
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Right
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: true
SpaceAfterCStyleCast: true
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Auto
TabWidth: 8
UseTab: Never

@ -0,0 +1,5 @@
<?php
define("ROOT_PATH", dirname(__DIR__));
define('DEBUG', true);
require ROOT_PATH . '/vendor/autoload.php';

@ -1,18 +1,15 @@
<?php <?php
require __DIR__ . '/bootstrap.php';
require dirname(__DIR__) . '/vendor/autoload.php';
use PhpAot\Php\Translator; use PhpAot\Php\Translator;
define('DEBUG', true);
if (empty($argv[1])) { if (empty($argv[1])) {
die("php compiler.php [file]\n"); die("php compiler.php [file]\n");
} }
try { try {
$file = $argv[1]; $file = $argv[1];
$translator = new Translator(); $translator = new Translator(ROOT_PATH);
$translator->setIndent(' '); $translator->setIndent(' ');
$code = $translator->convert($file); $code = $translator->convert($file);
$info = pathinfo($file); $info = pathinfo($file);

@ -1,7 +1,5 @@
<?php <?php
require __DIR__ . '/bootstrap.php';
require dirname(__DIR__) . '/vendor/autoload.php';
use PhpAot\Php\Translator; use PhpAot\Php\Translator;
@ -11,7 +9,7 @@ if (empty($argv[1])) {
try { try {
$file = $argv[1]; $file = $argv[1];
$translator = new Translator(); $translator = new Translator(ROOT_PATH);
$info = pathinfo($file); $info = pathinfo($file);
$objectFile = './tmp/' . $info['filename'] . '.cc.o'; $objectFile = './tmp/' . $info['filename'] . '.cc.o';
$translator->compileBinary($info['filename'], $objectFile); $translator->compileBinary($info['filename'], $objectFile);

@ -1,5 +1,4 @@
<?php <?php
/* The Computer Language Benchmarks Game /* The Computer Language Benchmarks Game
https://salsa.debian.org/benchmarksgame-team/benchmarksgame/ https://salsa.debian.org/benchmarksgame-team/benchmarksgame/
@ -36,6 +35,8 @@ function startWorker($depth, $iter, $n, $size, $shmId)
if ($pid) { if ($pid) {
return $pid; return $pid;
} else { } else {
var_dump($iter, $n);
echo str_repeat('----', 16).PHP_EOL;
$check = 0; $check = 0;
for ($i = 1; $i <= $iter; ++$i) { for ($i = 1; $i <= $iter; ++$i) {
$t = createTree($depth); $t = createTree($depth);
@ -52,7 +53,7 @@ function main()
{ {
global $argc, $argv; global $argc, $argv;
$minDepth = 4; $minDepth = 4;
$n = ($argc == 2) ? $argv[1] : 1; $n = ($argc == 3) ? $argv[2] : 1;
$maxDepth = max($minDepth + 2, $n); $maxDepth = max($minDepth + 2, $n);
$stretchDepth = $maxDepth + 1; $stretchDepth = $maxDepth + 1;
@ -89,5 +90,3 @@ function main()
echo "long lived tree of depth $maxDepth\t check: ", checkTree($longLivedTree), PHP_EOL; echo "long lived tree of depth $maxDepth\t check: ", checkTree($longLivedTree), PHP_EOL;
} }
main();

@ -0,0 +1,8 @@
<?php
namespace PhpAot\Php;
class ReturnTypeChanged extends \RuntimeException
{
}

@ -2,10 +2,10 @@
namespace PhpAot\Php; namespace PhpAot\Php;
use PhpAot\Php\Visitor;
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\Error;
use PhpParser\NodeTraverser; use PhpParser\NodeTraverser;
use PhpParser\ParserFactory; use PhpParser\ParserFactory;
@ -23,6 +23,9 @@ class Translator extends \PhpAot\Core\Translator
private string $phpxDir = '~/workspace/projects/phpx'; private string $phpxDir = '~/workspace/projects/phpx';
protected string $lang = 'PHP'; protected string $lang = 'PHP';
private array $scope = []; private array $scope = [];
private int $tmpVarIndex = 0;
// 需要插入到函数头部的变量定义代码
private array $definitions = [];
private array $zendTypeMap = [ private array $zendTypeMap = [
'int' => self::TYPE_INT, 'int' => self::TYPE_INT,
'float' => self::TYPE_FLOAT, 'float' => self::TYPE_FLOAT,
@ -36,19 +39,21 @@ class Translator extends \PhpAot\Core\Translator
private array $internalFunctions = []; private array $internalFunctions = [];
private int $optimizeLevel = 5; private int $optimizeLevel = 5;
private bool $verbose = false; private bool $verbose = true;
private string $file; private string $file;
private string $dir; private string $dir;
private string $namespace = ''; private string $namespace = '';
private array $uses = []; private array $uses = [];
private string $class = ''; private string $class = '';
private string $returnType = ''; private FunctionDef $functionDef;
const PREFIX = 'php_'; const PREFIX = 'php_';
private string $rootPath;
public function __construct() public function __construct(string $rootPath)
{ {
$this->rootPath = $rootPath;
} }
public function parseHeaders(): string public function parseHeaders(): string
@ -65,12 +70,9 @@ class Translator extends \PhpAot\Core\Translator
$this->phpxDir = $dir; $this->phpxDir = $dir;
} }
public function convert(string $file) private function doConvert(string $phpCode)
{ {
$parser = (new ParserFactory())->createForNewestSupportedVersion(); $parser = (new ParserFactory())->createForNewestSupportedVersion();
$phpCode = file_get_contents($file);
$this->file = realpath($file);
$this->dir = dirname($this->file);
$ast = $parser->parse($phpCode); $ast = $parser->parse($phpCode);
$traverser = new NodeTraverser; $traverser = new NodeTraverser;
@ -79,6 +81,7 @@ class Translator extends \PhpAot\Core\Translator
$traverser->addVisitor(new Visitor()); $traverser->addVisitor(new Visitor());
$stmts = $traverser->traverse($ast); $stmts = $traverser->traverse($ast);
$this->indentLevel = 0;
$cppCode = $this->parseHeaders(); $cppCode = $this->parseHeaders();
foreach($stmts as $v) { foreach($stmts as $v) {
@ -100,9 +103,26 @@ class Translator extends \PhpAot\Core\Translator
return $cppCode; return $cppCode;
} }
public function save($code, $file) public function convert(string $file): string
{
$phpCode = file_get_contents($file);
$this->file = realpath($file);
$this->dir = dirname($this->file);
while (true) {
try {
return $this->doConvert($phpCode);
} catch (ReturnTypeChanged $e) {
// 某些情况,例如返回值变更,需要重新解析
continue;
}
}
}
public function save(string $code, string $file): void
{ {
file_put_contents($file, $code); file_put_contents($file, $code);
$this->formatCppCode($file);
} }
@ -131,10 +151,16 @@ class Translator extends \PhpAot\Core\Translator
return isset($this->internalFunctions[$name]); return isset($this->internalFunctions[$name]);
} }
private function parseFunctionDef($v): string private function resetScope(): void
{ {
$this->scope = []; $this->scope = [];
$def = new FunctionDef(); $this->definitions = [];
$this->tmpVarIndex = 0;
}
private function parseFunctionDef($v): string
{
$this->resetScope();
$names[] = $this->parseIdentifier($v->name); $names[] = $this->parseIdentifier($v->name);
if ($this->class) { if ($this->class) {
$names[] = strtolower($this->class); $names[] = strtolower($this->class);
@ -144,22 +170,30 @@ class Translator extends \PhpAot\Core\Translator
} }
$name = implode('__', array_reverse($names)); $name = implode('__', array_reverse($names));
if (isset($this->internalFunctions[$name])) {
$this->functionDef = $this->internalFunctions[$name];
} else {
$this->functionDef = new FunctionDef();
$this->functionDef->name = $name;
if ($v->returnType) { if ($v->returnType) {
$this->returnType = $this->getZendType($this->parseIdentifier($v->returnType)); $this->functionDef->returnType = $this->getZendType($this->parseIdentifier($v->returnType));
} else { } else {
$this->returnType = 'void'; $this->functionDef->returnType = 'void';
}
$this->internalFunctions[$name] = $this->functionDef;
} }
$def->name = $name; $params = $this->parseParams($v->params);
$def->returnType = $this->returnType;
$this->internalFunctions[$name] = $def;
$params = $this->parseParams($v->params, $def);
$code = $this->returnType . ' ' . self::PREFIX . $name . '(' . $params . ') {' . PHP_EOL;
$this->indentLevel++; $this->indentLevel++;
$stmts = $this->parseStmts($v->stmts); $stmts = $this->parseStmts($v->stmts);
$this->indentLevel--; $this->indentLevel--;
$code = $this->getReturnType() . ' ' . self::PREFIX . $name . '(' . $params . ') {' . PHP_EOL;
$this->indentLevel++;
foreach ($this->definitions as $definition) {
$code .= $this->getIndent() . $definition . PHP_EOL;
}
$this->indentLevel--;
$code .= $stmts; $code .= $stmts;
$code .= "}\n"; $code .= "}\n";
@ -187,15 +221,17 @@ class Translator extends \PhpAot\Core\Translator
return $expr->getAttribute('rawValue'); return $expr->getAttribute('rawValue');
case 'Scalar_String': case 'Scalar_String':
return '"' . $this->escapeString($expr->value) . '"'; return '"' . $this->escapeString($expr->value) . '"';
case 'Expr_ConstFetch':
return $this->parseConstFetch($expr);
default: default:
return $this->parseExpr($expr); return $this->parseExpr($expr);
} }
} }
private function parseParams($params, FunctionDef $def): string private function parseParams($params): string
{ {
$list = []; $list = [];
$def->argumentCountRequired = count($params); $this->functionDef->argumentCountRequired = count($params);
foreach ($params as $param) { foreach ($params as $param) {
$type = $this->parseType($param->type); $type = $this->parseType($param->type);
$name = $this->parseIdentifier($param->var); $name = $this->parseIdentifier($param->var);
@ -206,10 +242,10 @@ class Translator extends \PhpAot\Core\Translator
$argInfo->name = $name; $argInfo->name = $name;
$argInfo->type = $type; $argInfo->type = $type;
if (isset($param->default)) { if (isset($param->default)) {
$def->argumentCountRequired = count($list) - 1; $this->functionDef->argumentCountRequired = count($list) - 1;
$argInfo->default = $param->default->getAttribute('rawValue'); $argInfo->default = $param->default->getAttribute('rawValue');
} }
$def->arguments[] = $argInfo; $this->functionDef->arguments[] = $argInfo;
} }
return implode(', ', $list); return implode(', ', $list);
} }
@ -233,6 +269,9 @@ class Translator extends \PhpAot\Core\Translator
case 'Stmt_For': case 'Stmt_For':
$lines[] = $this->parseFor($v); $lines[] = $this->parseFor($v);
break; break;
case 'Stmt_Foreach':
$lines[] = $this->parseForeach($v);
break;
case 'Stmt_While': case 'Stmt_While':
$lines[] = $this->parseWhile($v); $lines[] = $this->parseWhile($v);
break; break;
@ -259,6 +298,7 @@ class Translator extends \PhpAot\Core\Translator
} }
} }
$code = ''; $code = '';
foreach ($lines as $line) { foreach ($lines as $line) {
$code .= $this->getIndent() . $line . PHP_EOL; $code .= $this->getIndent() . $line . PHP_EOL;
} }
@ -398,8 +438,12 @@ class Translator extends \PhpAot\Core\Translator
$this->addVar($array, self::TYPE_VAR); $this->addVar($array, self::TYPE_VAR);
$code .= self::TYPE_ARRAY . " $array;\n" . $this->getIndent(); $code .= self::TYPE_ARRAY . " $array;\n" . $this->getIndent();
} }
if ($left->dim === null) {
return $code . "$array.offsetSet(php::null, " . $this->parseExpr($right) . ")";
} else {
$dim = $this->parseIdentifier($left->dim); $dim = $this->parseIdentifier($left->dim);
return $code . "$array.offsetSet($dim, " . $this->parseExpr($right) . ")"; return $code . "$array.offsetSet($dim, " . $this->parseExpr($right) . ")";
}
} elseif ($left->getType() === 'Expr_PropertyFetch') { } elseif ($left->getType() === 'Expr_PropertyFetch') {
$array = $this->parseIdentifier($left->var); $array = $this->parseIdentifier($left->var);
$propName = $this->parseIdentifier($left->name); $propName = $this->parseIdentifier($left->name);
@ -429,19 +473,45 @@ class Translator extends \PhpAot\Core\Translator
} }
} }
private function parseBinaryOpPlus(mixed $expr): string private function parseBinaryOp($left, $right, $op): string
{ {
$left = $this->parseIdentifier($expr->left); $leftExpr = $this->parseIdentifier($left);
$right = $this->parseIdentifier($expr->right); $rightExpr = $this->parseIdentifier($right);
$leftType = $this->detectType($left);
$rightType = $this->detectType($right);
if ($leftType === self::TYPE_FLOAT) {
$rightExpr = $this->convertExprType($rightExpr, self::TYPE_FLOAT, $rightType);
} elseif ($rightType === self::TYPE_FLOAT) {
$leftExpr = $this->convertExprType($leftExpr, self::TYPE_FLOAT, $leftType);
} elseif ($leftType === self::TYPE_INT) {
$rightExpr = $this->convertExprType($rightExpr, self::TYPE_INT, $rightType);
} elseif ($rightType === self::TYPE_INT) {
$leftExpr = $this->convertExprType($leftExpr, self::TYPE_INT, $leftType);
} else {
$leftExpr = $this->convertExprType($leftExpr, self::TYPE_INT, $leftType);
$rightExpr = $this->convertExprType($rightExpr, self::TYPE_INT, $rightType);
}
return $left . ' + ' . $right; return $leftExpr . ' ' .$op .' ' . $rightExpr;
}
private function parseBinaryOpPlus(mixed $expr): string
{
return $this->parseBinaryOp($expr->left, $expr->right, '+');
} }
private function parseReturn(mixed $v): string private function parseReturn(mixed $v): string
{ {
// 实际函数的返回值
$type = $this->detectType($v->expr); $type = $this->detectType($v->expr);
$expr = $this->parseExpr($v->expr); $expr = $this->parseExpr($v->expr);
return 'return ' . $this->convertExprType($expr, $this->returnType, $type); // 函数定义时没有声明返回值,但函数体中有返回值,修改为实际的返回值类型
if ($this->getReturnType() === 'void') {
$this->resetReturnType($type);
}
return 'return ' . $this->convertExprType($expr, $this->getReturnType(), $type);
} }
private function parseBinaryOpMul(mixed $expr): string private function parseBinaryOpMul(mixed $expr): string
@ -462,6 +532,12 @@ class Translator extends \PhpAot\Core\Translator
return isset($this->scope[$name]); return isset($this->scope[$name]);
} }
private function resetReturnType(string $type): void
{
$this->functionDef->returnType = $type;
throw new ReturnTypeChanged;
}
private function detectType($expr): string private function detectType($expr): string
{ {
$exprType = $expr->getType(); $exprType = $expr->getType();
@ -507,7 +583,8 @@ class Translator extends \PhpAot\Core\Translator
if ($item->key) { if ($item->key) {
$list[] = $this->getIndent() . '{ ' . $this->parseIdentifier($item->key) . ', php::Variant(' . $this->parseIdentifier($item->value) . ') }'; $list[] = $this->getIndent() . '{ ' . $this->parseIdentifier($item->key) . ', php::Variant(' . $this->parseIdentifier($item->value) . ') }';
} else { } else {
$list[] = $this->getIndent() . 'php::Variant(' . $this->parseIdentifier($item->value) . ')'; $value = $this->parseIdentifier($item->value);
$list[] = $this->getIndent() . 'php::Variant(' . $value . ')';
} }
} }
$this->indentLevel--; $this->indentLevel--;
@ -708,16 +785,16 @@ class Translator extends \PhpAot\Core\Translator
{ {
$name = $this->parseIdentifier($expr->name); $name = $this->parseIdentifier($expr->name);
if ($this->isInternalFunction($name)) { if ($this->isInternalFunction($name)) {
return self::PREFIX . $name . '(' . $this->parseArgs($expr->args, $name) . ')'; return self::PREFIX . $name . '(' . $this->parseCallArgs($expr->args, $name) . ')';
} }
if (empty($expr->args)) { if (empty($expr->args)) {
return 'php::call("' . $name . '")'; return 'php::call("' . $name . '")';
} else { } else {
return 'php::call("' . $name . '", {' . $this->parseArgs($expr->args, $name) . '})'; return 'php::call("' . $name . '", {' . $this->parseCallArgs($expr->args, $name) . '})';
} }
} }
private function parseArgs($args, string $funcName): string private function parseCallArgs($args, string $funcName): string
{ {
$internalFunction = $this->isInternalFunction($funcName); $internalFunction = $this->isInternalFunction($funcName);
$list_args = []; $list_args = [];
@ -728,6 +805,14 @@ class Translator extends \PhpAot\Core\Translator
} else { } else {
$list_args[] = $this->parseArg($arg); $list_args[] = $this->parseArg($arg);
} }
// 调用了不存在的变量,可能是引用
if ($arg->value->getType() === 'Expr_Variable') {
$name = $this->parseIdentifier($arg->value);
if (!$this->hasVar($name)) {
$this->definitions[] = self::TYPE_VAR . ' ' . $name . ' = php::newReference();';
}
}
} }
return implode(', ', $list_args); return implode(', ', $list_args);
} }
@ -904,13 +989,28 @@ class Translator extends \PhpAot\Core\Translator
return $code; return $code;
} }
private function convertIntExpr(string $expr): string
{
return 'php::to_int(' . $expr . ')';
}
private function convertFloatExpr(string $expr): string
{
return 'php::to_float(' . $expr . ')';
}
private function convertBoolExpr(string $expr): string
{
return 'php::to_bool(' . $expr . ')';
}
private function optimizeBinaryOpCompare(string $left, string $right, string $op): string private function optimizeBinaryOpCompare(string $left, string $right, string $op): string
{ {
if ($this->getDetectedType($left) == self::TYPE_INT and $this->getDetectedType($right) == self::TYPE_VAR) { if ($this->getDetectedType($left) == self::TYPE_INT and $this->getDetectedType($right) == self::TYPE_VAR) {
return $left . ' ' . $op . ' ' . $right . '.toInt()'; return $left . ' ' . $op . ' ' . $this->convertIntExpr($right);
} }
if ($this->getDetectedType($left) == self::TYPE_FLOAT and $this->getDetectedType($right) == self::TYPE_VAR) { if ($this->getDetectedType($left) == self::TYPE_FLOAT and $this->getDetectedType($right) == self::TYPE_VAR) {
return $left . ' ' . $op . ' ' . $right . '.toFloat()'; return $left . ' ' . $op . ' ' . $this->convertFloatExpr($right);
} }
return ''; return '';
} }
@ -960,6 +1060,10 @@ 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);
if ($right === 'nullptr') {
return $left . '.isNull()';
}
return 'php::same(' . $left . ', ' . $right . ')'; return 'php::same(' . $left . ', ' . $right . ')';
} }
@ -970,7 +1074,7 @@ class Translator extends \PhpAot\Core\Translator
if (empty($args)) { if (empty($args)) {
return 'php::newObject("' . $className . '")'; return 'php::newObject("' . $className . '")';
} else { } else {
return 'php::newObject("' . $className . '"(' . $this->parseArgs($args) . ')'; return 'php::newObject("' . $className . '"(' . $this->parseCallArgs($args) . ')';
} }
} }
@ -1036,7 +1140,11 @@ class Translator extends \PhpAot\Core\Translator
private function parseConstFetch(Node $expr) private function parseConstFetch(Node $expr)
{ {
return $this->parseIdentifier($expr->name); $name = $this->parseIdentifier($expr->name);
if ($name === 'null') {
return 'nullptr';
}
return $name;
} }
private function parseUnaryMinus(Node $expr): string private function parseUnaryMinus(Node $expr): string
@ -1096,6 +1204,11 @@ class Translator extends \PhpAot\Core\Translator
return $funcDef->arguments[$index]; return $funcDef->arguments[$index];
} }
private function getReturnType(): string
{
return $this->functionDef->returnType;
}
private function getTypeConvertedArg($arg, $argInfo): string private function getTypeConvertedArg($arg, $argInfo): string
{ {
$expr = $this->parseArg($arg); $expr = $this->parseArg($arg);
@ -1106,13 +1219,13 @@ class Translator extends \PhpAot\Core\Translator
private function convertExprType(string $expr, $leftType, $rightType): string private function convertExprType(string $expr, $leftType, $rightType): string
{ {
if ($leftType === self::TYPE_INT && $rightType !== self::TYPE_INT) { if ($leftType === self::TYPE_INT && $rightType !== self::TYPE_INT) {
return '(' . $expr . ').toInt()'; return $this->convertIntExpr($expr);
} }
if ($leftType === self::TYPE_FLOAT && $rightType !== self::TYPE_FLOAT) { if ($leftType === self::TYPE_FLOAT && $rightType !== self::TYPE_FLOAT) {
return '(' . $expr . ').toFloat()'; return $this->convertFloatExpr($expr);
} }
if ($leftType === self::TYPE_BOOL && $rightType !== self::TYPE_BOOL) { if ($leftType === self::TYPE_BOOL && $rightType !== self::TYPE_BOOL) {
return '(' . $expr . ').toBool()'; return $this->convertBoolExpr($expr);
} }
return $expr; return $expr;
} }
@ -1154,11 +1267,55 @@ class Translator extends \PhpAot\Core\Translator
private function parseAssignOpShiftRight(Node $node): string private function parseAssignOpShiftRight(Node $node): string
{ {
$var = $this->parseIdentifier($node->var); $var = $this->parseIdentifier($node->var);
return $var . ' >> ' . $this->parseIdentifier($node->expr); return $var . ' >>= ' . $this->parseIdentifier($node->expr);
} }
private function parseMagicConstFile(mixed $expr): string private function parseMagicConstFile(mixed $expr): string
{ {
return '"' . $this->escapeString($this->file) . '"'; return '"' . $this->escapeString($this->file) . '"';
} }
private function parseForeach(Node $node)
{
$expr = $this->parseIdentifier($node->expr);
if ($node->keyVar) {
$keyVar = $this->parseIdentifier($node->keyVar);
}
$valueVar = $this->parseIdentifier($node->valueVar);
$iteratorVar = $this->addTmpVar();
$stmts = $node->stmts;
$code = '';
$code .= self::TYPE_ARRAY . " $iteratorVar = " . $expr . ';' . PHP_EOL;
$code .= 'for (auto iter = ' . $iteratorVar . '.begin(); iter != ' . $iteratorVar . '.end(); ++iter) {' . PHP_EOL;
$this->indentLevel++;
if ($node->keyVar) {
$code .= $this->getIndent() . self::TYPE_VAR . ' ' . $keyVar . ' = iter.key();' . PHP_EOL;
$this->addVar($keyVar, self::TYPE_VAR);
}
$code .= $this->getIndent() . self::TYPE_VAR . ' ' . $valueVar . ' = iter.value();' . PHP_EOL;
$this->addVar($valueVar, self::TYPE_VAR);
$code .= $this->parseStmts($stmts);
$this->indentLevel--;
$code .= $this->getIndent() . '}';
return $code;
}
private function formatCppCode(string $file): void
{
$cmd = 'cd ' . $this->rootPath . ' && clang-format -i ' . $file;
$this->writeLog('formatting ' . $file . '...');
$this->writeLog($cmd);
shell_exec($cmd);
}
private function addTmpVar(): string
{
return 'tmp_var_' . $this->tmpVarIndex++;
}
} }

Loading…
Cancel
Save