Interface,ce 依赖关系处理,排序

pull/1/head
韩天峰 7 months ago
parent f8100988c4
commit 6ff687e1da
  1. 3
      composer.json
  2. 64
      composer.lock
  3. 3
      src/Php/ClassLikeDef.php
  4. 12
      src/Php/CompilerBase.php
  5. 79
      src/Php/Translator.php
  6. 34
      src/template/extension.cc.php

@ -1,7 +1,8 @@
{
"require": {
"nikic/php-parser": "5.6.1",
"league/climate": "^3.10"
"league/climate": "^3.10",
"marcj/topsort": "^2.0"
},
"require-dev": {
"phpunit/phpunit": "^10.4",

64
composer.lock generated

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "dff0db7b08aac2e595d7436d35f1ac3c",
"content-hash": "d4e35915568beccdcd533360bf30a206",
"packages": [
{
"name": "league/climate",
@ -72,6 +72,68 @@
},
"time": "2024-11-18T09:09:55+00:00"
},
{
"name": "marcj/topsort",
"version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/marcj/topsort.php.git",
"reference": "972f58e42b5f110a0a1d8433247f65248abcfd5c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/marcj/topsort.php/zipball/972f58e42b5f110a0a1d8433247f65248abcfd5c",
"reference": "972f58e42b5f110a0a1d8433247f65248abcfd5c",
"shasum": ""
},
"require": {
"php": ">=7.3"
},
"require-dev": {
"codeclimate/php-test-reporter": "dev-master",
"phpunit/phpunit": "^9",
"symfony/console": "~2.5 || ~3.0 || ~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"autoload": {
"psr-4": {
"MJS\\TopSort\\": "src/",
"MJS\\TopSort\\Tests\\": "tests/Tests/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Marc J. Schmidt",
"email": "marc@marcjschmidt.de"
}
],
"description": "High-Performance TopSort/Dependency resolving algorithm",
"keywords": [
"dependency resolving",
"topological sort",
"topsort"
],
"support": {
"issues": "https://github.com/marcj/topsort.php/issues",
"source": "https://github.com/marcj/topsort.php/tree/2.0.0"
},
"funding": [
{
"url": "https://github.com/marcj",
"type": "github"
}
],
"time": "2020-09-24T12:39:55+00:00"
},
{
"name": "nikic/php-parser",
"version": "v5.6.1",

@ -5,7 +5,8 @@ namespace PhpAot\Php;
class ClassLikeDef
{
public string $name;
public string $namespace = '';
public string $namespace;
public string $extends = '';
public function __construct(string $name, string $namespace = '')
{

@ -82,6 +82,7 @@ class CompilerBase extends \PhpAot\Core\Translator
protected array $useNamespaces = [];
protected array $useFunctions = [];
protected string $class = '';
protected string $interface = '';
/**
* @var array<string, ClassDef>
*/
@ -91,8 +92,18 @@ class CompilerBase extends \PhpAot\Core\Translator
* @var array<string, ClassDef>
*/
protected array $classesDefineInFile = [];
/**
* @var array<string, InterfaceDef>
*/
protected array $interfacesDefineInFile = [];
/**
* @var array<string>
*/
protected array $classCeList = [];
protected array $classCeInfo = [];
protected FunctionDef $functionDef;
protected ClassDef $classDef;
protected InterfaceDef $interfaceDef;
protected array $globalVars = [
'_GET' => self::TYPE_ARRAY,
'_POST' => self::TYPE_ARRAY,
@ -203,6 +214,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$this->indentLevel = 0;
$this->strictTypes = false;
$this->classesDefineInFile = [];
$this->interfaceDefineInFile = [];
}
protected function resetNamespace(): void

@ -2,6 +2,7 @@
namespace PhpAot\Php;
use MJS\TopSort\Implementations\StringSort;
use PhpParser\Modifiers;
use PhpParser\Node;
use PhpParser\NodeTraverser;
@ -131,25 +132,33 @@ class Translator extends Preprocessor
return self::PREFIX . 'register_class_' . $name;
}
protected function getRegisterClassFunctionCeList(ClassDef $classDef): array
protected function getRegisterClassFunctionCeList(ClassDef|InterfaceDef $classDef): array
{
$list = [];
$parentCe = $this->getParentClassCe($classDef);
$implements = $this->getImplementCe($classDef);
if ($parentCe) {
if ($parentCe !== '') {
$list = [$parentCe];
}
// interface 没有 implements
if ($classDef instanceof InterfaceDef) {
return $list;
}
$implements = $this->getImplementCe($classDef);
return array_merge($list, $implements);
}
public function getRegisterClassFunctionArgs(ClassDef $classDef): string
public function getRegisterClassFunctionArgs(ClassDef|InterfaceDef $classDef): string
{
return implode(', ', $this->getRegisterClassFunctionCeList($classDef));
}
private function getRegisterClassFunctionArgDef(ClassDef $classDef): string
private function getRegisterClassFunctionArgDef(ClassDef|InterfaceDef $classDef): string
{
return 'zend_class_entry *' . implode(', zend_class_entry *', $this->getRegisterClassFunctionCeList($classDef));
$depsCeList = $this->getRegisterClassFunctionCeList($classDef);
if (empty($depsCeList)) {
return '';
}
return 'zend_class_entry *' . implode(', zend_class_entry *', $depsCeList);
}
protected function getClassCe(ClassLikeDef $classDef): string
@ -157,7 +166,7 @@ class Translator extends Preprocessor
return self::PREFIX . 'class_entry_' . $classDef->getNamespacedName();
}
protected function getParentClassCe(ClassDef $classDef): string
protected function getParentClassCe(ClassLikeDef $classDef): string
{
if (!$classDef->extends) {
return '';
@ -165,7 +174,7 @@ class Translator extends Preprocessor
return self::PREFIX . 'class_entry_' . $classDef->extends;
}
private function getImplementCe(ClassLikeDef $classDef): array
private function getImplementCe(ClassDef $classDef): array
{
return array_map(fn($v) => self::PREFIX . 'class_entry_' . $v, $classDef->implements);
}
@ -217,6 +226,10 @@ class Translator extends Preprocessor
$cppCode .= $this->genClassWrapper($classDef);
}
foreach ($this->interfacesDefineInFile as $interfaceDef) {
$cppCode .= $this->genClassWrapper($interfaceDef);
}
return $this->genIncludeHeaderFiles() . $cppCode;
}
@ -265,9 +278,45 @@ class Translator extends Preprocessor
return ob_get_clean();
}
protected function genClassCeList(): void
{
$sorter = new StringSort();
foreach ($this->interfacesDefineInFile as $interfaceDef) {
$ce = $this->getClassCe($interfaceDef);
$parentCe = $this->getParentClassCe($interfaceDef);
$deps = [];
if ($parentCe !== '') {
$deps[] = $parentCe;
}
$this->classCeInfo[$ce] = [
'deps' => $deps,
'func' => $this->getRegisterClassFunction($interfaceDef->getNamespacedName()),
'args' => $this->getRegisterClassFunctionArgs($interfaceDef),
'argDef' => $this->getRegisterClassFunctionArgDef($interfaceDef),
];
$sorter->add($ce, $deps);
}
foreach ($this->classesDefineInFile as $classDef) {
$ce = $this->getClassCe($classDef);
$depsCeList = $this->getRegisterClassFunctionCeList($classDef);
$this->classCeInfo[$ce] = [
'deps' => $depsCeList,
'func' => $this->getRegisterClassFunction($classDef->getNamespacedName()),
'args' => $this->getRegisterClassFunctionArgs($classDef),
'argDef' => $this->getRegisterClassFunctionArgDef($classDef),
];
$sorter->add($ce, $depsCeList);
}
$this->classCeList = $sorter->sort();
}
public function genExtension(string $file): void
{
$this->localHeaders = [];
$this->genClassCeList();
$code = $this->render('extension.cc.php');
$this->writeFile($file, $code);
$this->formatCppCode($file);
@ -342,7 +391,7 @@ class Translator extends Preprocessor
protected function getMethodName(Node\Stmt\ClassMethod $v): string
{
return strtolower($this->parseIdentifier($v->name));
return $this->parseIdentifier($v->name);
}
protected function getNativeMethodName(ClassDef $classDef, MethodDef $methodDef): string
@ -498,7 +547,7 @@ class Translator extends Preprocessor
}
protected function genClassWrapper(ClassDef $classDef): string
protected function genClassWrapper(ClassDef|InterfaceDef $classDef): string
{
$cppCode = '';
$name = $classDef->getNamespacedName();
@ -508,10 +557,13 @@ class Translator extends Preprocessor
$cppCode .= $this->getIndent() . 'return register_class_' . $name . '(' . $param . ');' . PHP_EOL;
$cppCode .= '}' . PHP_EOL . PHP_EOL;
if ($classDef instanceof ClassDef) {
$methods = $classDef->methods;
foreach ($methods as $methodDef) {
$cppCode .= $this->genMethodWrapper($classDef, $methodDef);
}
}
return $cppCode;
}
@ -705,9 +757,12 @@ class Translator extends Preprocessor
return $list;
}
private function parseInterface(Node $v): void
private function parseInterface(Node\Stmt\Interface_ $v): void
{
$name = $this->parseIdentifier($v->name);
$this->interfaces[$name] = new InterfaceDef($name, $this->namespace);
$this->interface = $name;
$this->interfaceDef = new InterfaceDef($name, $this->namespace);
$this->interfaces[$name] = $this->interfaceDef;
$this->interfacesDefineInFile[$this->interface] = $this->interfaceDef;
}
}

@ -14,20 +14,13 @@ foreach ($this->globalVars as $name => $type):
<?= Translator::TYPE_VAR ?> <?= $name ?>;
<?php endforeach; ?>
// class entries
<?php
foreach ($this->classes as $classDef) :
?>
zend_class_entry * <?= $this->getClassCe($classDef) ?>;
<?php endforeach; ?>
// class register functions
<?php
foreach ($this->classes as $classDef):
$name = $classDef->getNamespacedName();
$argDef = $this->getRegisterClassFunctionArgDef($classDef);
foreach ($this->classCeList as $ce):
$info = $this->classCeInfo[$ce];
?>
extern zend_class_entry *<?= $this->getRegisterClassFunction($name) ?>(<?= $argDef ?>);
zend_class_entry * <?= $ce ?>;
extern zend_class_entry *<?= $info['func'] ?>(<?= $info['argDef'] ?>);
<?php endforeach; ?>
// literal strings
@ -59,23 +52,12 @@ static const zend_function_entry ext_functions[] = {
};
static PHP_MINIT_FUNCTION(app) {
// class
<?php
foreach ($this->classes as $classDef):
$name = $classDef->getNamespacedName();
$params = $this->getRegisterClassFunctionArgs($classDef);
$fn = $this->getRegisterClassFunction($name);
?>
<?=$this->getClassCe($classDef)?> = <?= $fn ?>(<?= $params ?>);
<?php endforeach; ?>
// class/interface class entries
<?php
foreach ($this->interfaces as $interfaceDef):
$name = $interfaceDef->name;
$fn = $this->getRegisterClassFunction($name);
foreach ($this->classCeList as $ce):
$info = $this->classCeInfo[$ce];
?>
<?=$this->getClassCe($interfaceDef)?> = <?= $fn ?>();
<?=$ce?> = <?= $info['func'] ?>(<?= $info['args'] ?>);
<?php endforeach; ?>
return SUCCESS;

Loading…
Cancel
Save