diff --git a/examples/class/test.php b/examples/class/test.php index 4bbbc83e..fc0e15b8 100644 --- a/examples/class/test.php +++ b/examples/class/test.php @@ -1,5 +1,16 @@ */ @@ -17,15 +16,11 @@ class ClassDef * @var array */ public array $constants = []; - public string $namespace = ''; public array $implements = []; public string $extends = ''; - public function getNamespacedName(): string + public function __construct(string $name, string $namespace = '') { - if ($this->namespace === '') { - return $this->name; - } - return str_replace('\\', '_', $this->namespace . '_' . $this->name); + parent::__construct($name, $namespace); } } \ No newline at end of file diff --git a/src/Php/ClassLikeDef.php b/src/Php/ClassLikeDef.php new file mode 100644 index 00000000..b68f055e --- /dev/null +++ b/src/Php/ClassLikeDef.php @@ -0,0 +1,23 @@ +name = $name; + $this->namespace = $namespace; + } + + public function getNamespacedName(): string + { + if ($this->namespace === '') { + return $this->name; + } + return str_replace('\\', '_', $this->namespace . '_' . $this->name); + } +} \ No newline at end of file diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 7b7a87a1..74c8c5d9 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -86,6 +86,7 @@ class CompilerBase extends \PhpAot\Core\Translator * @var array */ protected array $classes = []; + protected array $interfaces = []; /** * @var array */ @@ -1096,7 +1097,11 @@ class CompilerBase extends \PhpAot\Core\Translator $left = $expr->var; $name = $this->parseIdentifier($left); $type = $this->detectExprType($expr->expr); - $code .= $type . ' ' . $name . ' = ' . '(' . $this->parseIdentifier($expr->expr) . ');'; + // for 循环的变量声明,必须在循环体之外,不能创建 scope tmp var + if ($this->hasVar($name)) { + $this->addLocalVar($name, $type); + } + $code .= $name . ' = ' . '(' . $this->parseIdentifier($expr->expr) . ');'; } $list_cond[] = $this->parseExpr($expr); } diff --git a/src/Php/InterfaceDef.php b/src/Php/InterfaceDef.php new file mode 100644 index 00000000..ba98d66c --- /dev/null +++ b/src/Php/InterfaceDef.php @@ -0,0 +1,7 @@ +fatalError($v, 'Unsupported statement: ' . $type); diff --git a/src/Php/Translator.php b/src/Php/Translator.php index f5c2a795..1eae9c53 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -131,7 +131,28 @@ class Translator extends Preprocessor return self::PREFIX . 'register_class_' . $name; } - protected function getClassCe(ClassDef $classDef): string + protected function getRegisterClassFunctionCeList(ClassDef $classDef): array + { + $list = []; + $parentCe = $this->getParentClassCe($classDef); + $implements = $this->getImplementCe($classDef); + if ($parentCe) { + $list = [$parentCe]; + } + return array_merge($list, $implements); + } + + public function getRegisterClassFunctionArgs(ClassDef $classDef): string + { + return implode(', ', $this->getRegisterClassFunctionCeList($classDef)); + } + + private function getRegisterClassFunctionArgDef(ClassDef $classDef): string + { + return 'zend_class_entry *' . implode(', zend_class_entry *', $this->getRegisterClassFunctionCeList($classDef)); + } + + protected function getClassCe(ClassLikeDef $classDef): string { return self::PREFIX . 'class_entry_' . $classDef->getNamespacedName(); } @@ -144,6 +165,11 @@ class Translator extends Preprocessor return self::PREFIX . 'class_entry_' . $classDef->extends; } + private function getImplementCe(ClassLikeDef $classDef): array + { + return array_map(fn($v) => self::PREFIX . 'class_entry_' . $v, $classDef->implements); + } + protected function doConvert(string $phpCode): string { $this->climate->info('convert: ' . $this->file); @@ -179,6 +205,9 @@ class Translator extends Preprocessor case 'Stmt_Const': $this->parseConstDef($v) . PHP_EOL; break; + case 'Stmt_Interface': + $this->parseInterface($v) . PHP_EOL; + break; default: abort($v); } @@ -389,13 +418,11 @@ class Translator extends Preprocessor $this->genClassStubFile($class, $this->file); } - $this->classDef = new ClassDef(); - $this->classDef->name = $this->class; + $this->classDef = new ClassDef($this->class, $this->namespace); if ($class->extends) { $this->classDef->extends = $this->parseIdentifier($class->extends); } $this->classDef->implements = $this->parseIdentifierList($class->implements); - $this->classDef->namespace = $this->namespace; $this->classes[$this->class] = $this->classDef; $this->classesDefineInFile[$this->class] = $this->classDef; @@ -475,15 +502,9 @@ class Translator extends Preprocessor { $cppCode = ''; $name = $classDef->getNamespacedName(); - - if ($classDef->extends) { - $parentName = 'zend_class_entry *parent_ce'; - $param = 'parent_ce'; - } else { - $parentName = ''; - $param = ''; - } - $cppCode .= 'zend_class_entry *' . $this->getRegisterClassFunction($name) . '(' . $parentName . ') {' . PHP_EOL; + $argsDef = $this->getRegisterClassFunctionArgDef($classDef); + $param = $this->getRegisterClassFunctionArgs($classDef); + $cppCode .= 'zend_class_entry *' . $this->getRegisterClassFunction($name) . '(' . $argsDef . ') {' . PHP_EOL; $cppCode .= $this->getIndent() . 'return register_class_' . $name . '(' . $param . ');' . PHP_EOL; $cppCode .= '}' . PHP_EOL . PHP_EOL; @@ -683,4 +704,10 @@ class Translator extends Preprocessor } return $list; } + + private function parseInterface(Node $v): void + { + $name = $this->parseIdentifier($v->name); + $this->interfaces[$name] = new InterfaceDef($name, $this->namespace); + } } \ No newline at end of file diff --git a/src/template/extension.cc.php b/src/template/extension.cc.php index 319d07d9..cd5a0c34 100644 --- a/src/template/extension.cc.php +++ b/src/template/extension.cc.php @@ -25,9 +25,9 @@ zend_class_entry * getClassCe($classDef) ?>; classes as $classDef): $name = $classDef->getNamespacedName(); - $parentCe = $classDef->extends ? 'zend_class_entry *parent_ce' : ''; + $argDef = $this->getRegisterClassFunctionArgDef($classDef); ?> -extern zend_class_entry *getRegisterClassFunction($name) ?>(); +extern zend_class_entry *getRegisterClassFunction($name) ?>(); // literal strings @@ -59,13 +59,23 @@ static const zend_function_entry ext_functions[] = { }; static PHP_MINIT_FUNCTION(app) { +// class classes as $classDef): $name = $classDef->getNamespacedName(); - $parentCe = $this->getParentClassCe($classDef); + $params = $this->getRegisterClassFunctionArgs($classDef); $fn = $this->getRegisterClassFunction($name); ?> - getClassCe($classDef)?> = (); + getClassCe($classDef)?> = (); + + + +interfaces as $interfaceDef): + $name = $interfaceDef->name; + $fn = $this->getRegisterClassFunction($name); +?> + getClassCe($interfaceDef)?> = (); return SUCCESS; diff --git a/tests/aot/for.phpt b/tests/aot/for.phpt new file mode 100644 index 00000000..0ac682ee --- /dev/null +++ b/tests/aot/for.phpt @@ -0,0 +1,19 @@ +--TEST-- +for statement +--FILE-- + +--EXPECT-- +int(100) +49 \ No newline at end of file diff --git a/tests/aot/foreach.phpt b/tests/aot/foreach.phpt new file mode 100644 index 00000000..1570a7f9 --- /dev/null +++ b/tests/aot/foreach.phpt @@ -0,0 +1,19 @@ +--TEST-- +foreach statement +--FILE-- + +--EXPECT-- +int(4950) +int(199) diff --git a/tests/core/classes/inheritance.phpt b/tests/core/classes/inheritance.phpt new file mode 100644 index 00000000..4024b5e3 --- /dev/null +++ b/tests/core/classes/inheritance.phpt @@ -0,0 +1,58 @@ +--TEST-- +Classes inheritance test +--FILE-- +a."\n"; + echo "b = ".$this->b."\n"; + } + function mul() { + return $this->a*$this->b; + } +}; + +class bar extends foo { + public $c; + function display() { /* alternative display function for class bar */ + echo "This is class bar\n"; + echo "a = ".$this->a."\n"; + echo "b = ".$this->b."\n"; + echo "c = ".$this->c."\n"; + } +}; + +function main() { + $foo1 = new foo; + $foo1->a = 2; + $foo1->b = 5; + $foo1->display(); + echo $foo1->mul()."\n"; + + echo "-----\n"; + + $bar1 = new bar; + $bar1->a = 4; + $bar1->b = 3; + $bar1->c = 12; + $bar1->display(); + echo $bar1->mul()."\n"; +} +?> +--EXPECT-- +This is class foo +a = 2 +b = 5 +10 +----- +This is class bar +a = 4 +b = 3 +c = 12 +12