From: Nikita Popov Date: Fri, 2 Oct 2020 15:07:46 +0000 (+0200) Subject: Add partial namespace support to gen_stub X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=924ac2b98ae558617708180767ae512aa0c13f7a;p=php Add partial namespace support to gen_stub --- diff --git a/build/gen_stub.php b/build/gen_stub.php index 4f3a8514b4..e2c6bb2eb2 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -337,30 +337,73 @@ class ArgInfo { } } -class FunctionName { - /** @var string|null */ +interface FunctionOrMethodName { + public function getDeclaration(): string; + public function getArgInfoName(): string; + public function __toString(): string; +} + +class FunctionName implements FunctionOrMethodName { + /** @var Name */ + private $name; + + public function __construct(Name $name) { + $this->name = $name; + } + + public function getNamespace(): ?string { + if ($this->name->isQualified()) { + return $this->name->slice(0, -1)->toString(); + } + return null; + } + + public function getShortName(): string { + return $this->name->getLast(); + } + + public function getNonNamespacedName(): string { + if ($this->name->isQualified()) { + throw new Exception("Namespaced name not supported here"); + } + return $this->name->toString(); + } + + public function getDeclaration(): string { + return "ZEND_FUNCTION({$this->name->getLast()});\n"; + } + + public function getArgInfoName(): string { + $underscoreName = implode('_', $this->name->parts); + return "arginfo_$underscoreName"; + } + + public function __toString(): string { + return $this->name->toString(); + } +} + +class MethodName implements FunctionOrMethodName { + /** @var string */ public $className; /** @var string */ public $name; - public function __construct(?string $className, string $name) - { + public function __construct(string $className, string $name) { $this->className = $className; $this->name = $name; } - public function getDeclaration(): string - { - if ($this->className) { - return "ZEND_METHOD($this->className, $this->name);\n"; - } + public function getDeclaration(): string { + return "ZEND_METHOD($this->className, $this->name);\n"; + } - return "ZEND_FUNCTION($this->name);\n"; + public function getArgInfoName(): string { + return "arginfo_class_{$this->className}_{$this->name}"; } - public function __toString() - { - return $this->className ? "$this->className::$this->name" : $this->name; + public function __toString(): string { + return "$this->className::$this->name"; } } @@ -382,7 +425,7 @@ class ReturnInfo { } class FuncInfo { - /** @var FunctionName */ + /** @var FunctionOrMethodName */ public $name; /** @var int */ public $flags; @@ -402,10 +445,10 @@ class FuncInfo { public $cond; public function __construct( - FunctionName $name, + FunctionOrMethodName $name, int $flags, ?string $aliasType, - ?FunctionName $alias, + ?FunctionOrMethodName $alias, bool $isDeprecated, array $args, ReturnInfo $return, @@ -440,10 +483,7 @@ class FuncInfo { } public function getArgInfoName(): string { - if ($this->name->className) { - return 'arginfo_class_' . $this->name->className . '_' . $this->name->name; - } - return 'arginfo_' . $this->name->name; + return $this->name->getArgInfoName(); } public function getDeclarationKey(): string @@ -465,18 +505,21 @@ class FuncInfo { } public function getFunctionEntry(): string { - if ($this->name->className) { + if ($this->name instanceof MethodName) { if ($this->alias) { - if ($this->alias->className) { + if ($this->alias instanceof MethodName) { return sprintf( "\tZEND_MALIAS(%s, %s, %s, %s, %s)\n", $this->alias->className, $this->name->name, $this->alias->name, $this->getArgInfoName(), $this->getFlagsAsString() ); - } else { + } else if ($this->alias instanceof FunctionName) { return sprintf( "\tZEND_ME_MAPPING(%s, %s, %s, %s)\n", - $this->name->name, $this->alias->name, $this->getArgInfoName(), $this->getFlagsAsString() + $this->name->name, $this->alias->getNonNamespacedName(), + $this->getArgInfoName(), $this->getFlagsAsString() ); + } else { + throw new Error("Cannot happen"); } } else { if ($this->flags & Class_::MODIFIER_ABSTRACT) { @@ -491,26 +534,37 @@ class FuncInfo { $this->name->className, $this->name->name, $this->getArgInfoName(), $this->getFlagsAsString() ); } - } else { + } else if ($this->name instanceof FunctionName) { + $namespace = $this->name->getNamespace(); + $shortName = $this->name->getShortName(); + if ($this->alias && $this->isDeprecated) { return sprintf( "\tZEND_DEP_FALIAS(%s, %s, %s)\n", - $this->name, $this->alias->name, $this->getArgInfoName() + $shortName, $this->alias->getNonNamespacedName(), $this->getArgInfoName() ); } if ($this->alias) { return sprintf( "\tZEND_FALIAS(%s, %s, %s)\n", - $this->name, $this->alias->name, $this->getArgInfoName() + $shortName, $this->alias->getNonNamespacedName(), $this->getArgInfoName() ); } if ($this->isDeprecated) { - return sprintf("\tZEND_DEP_FE(%s, %s)\n", $this->name, $this->getArgInfoName()); + return sprintf("\tZEND_DEP_FE(%s, %s)\n", $shortName, $this->getArgInfoName()); } - return sprintf("\tZEND_FE(%s, %s)\n", $this->name, $this->getArgInfoName()); + if ($namespace) { + return sprintf( + "\tZEND_NS_FE(\"%s\", %s, %s)\n", + $namespace, $shortName, $this->getArgInfoName()); + } else { + return sprintf("\tZEND_FE(%s, %s)\n", $shortName, $this->getArgInfoName()); + } + } else { + throw new Error("Cannot happen"); } } @@ -565,18 +619,11 @@ class ClassInfo { class FileInfo { /** @var FuncInfo[] */ - public $funcInfos; + public $funcInfos = []; /** @var ClassInfo[] */ - public $classInfos; + public $classInfos = []; /** @var bool */ - public $generateFunctionEntries; - - public function __construct( - array $funcInfos, array $classInfos, bool $generateFunctionEntries) { - $this->funcInfos = $funcInfos; - $this->classInfos = $classInfos; - $this->generateFunctionEntries = $generateFunctionEntries; - } + public $generateFunctionEntries = false; /** * @return iterable @@ -646,7 +693,7 @@ function parseDocComment(DocComment $comment): array { function parseFunctionLike( PrettyPrinterAbstract $prettyPrinter, - FunctionName $name, + FunctionOrMethodName $name, int $flags, Node\FunctionLike $func, ?string $cond @@ -672,9 +719,9 @@ function parseFunctionLike( $aliasType = $tag->name; $aliasParts = explode("::", $tag->getValue()); if (count($aliasParts) === 1) { - $alias = new FunctionName(null, $aliasParts[0]); + $alias = new FunctionName(new Name($aliasParts[0])); } else { - $alias = new FunctionName($aliasParts[0], $aliasParts[1]); + $alias = new MethodName($aliasParts[0], $aliasParts[1]); } } else if ($tag->name === 'deprecated') { $isDeprecated = true; @@ -814,46 +861,27 @@ function getFileDocComment(array $stmts): ?DocComment { return null; } -function parseStubFile(string $code): FileInfo { - $lexer = new PhpParser\Lexer(); - $parser = new PhpParser\Parser\Php7($lexer); - $nodeTraverser = new PhpParser\NodeTraverser; - $nodeTraverser->addVisitor(new PhpParser\NodeVisitor\NameResolver); - $prettyPrinter = new class extends Standard { - protected function pName_FullyQualified(Name\FullyQualified $node) { - return implode('\\', $node->parts); - } - }; - - $stmts = $parser->parse($code); - $nodeTraverser->traverse($stmts); - - $generateFunctionEntries = false; - $fileDocComment = getFileDocComment($stmts); - if ($fileDocComment) { - if (strpos($fileDocComment->getText(), '@generate-function-entries') !== false) { - $generateFunctionEntries = true; - } - } - - $funcInfos = []; - $classInfos = []; +function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstract $prettyPrinter) { $conds = []; foreach ($stmts as $stmt) { - $cond = handlePreprocessorConditions($conds, $stmt); if ($stmt instanceof Stmt\Nop) { continue; } + if ($stmt instanceof Stmt\Namespace_) { + handleStatements($fileInfo, $stmt->stmts, $prettyPrinter); + continue; + } + + $cond = handlePreprocessorConditions($conds, $stmt); if ($stmt instanceof Stmt\Function_) { - $funcInfos[] = parseFunctionLike( + $fileInfo->funcInfos[] = parseFunctionLike( $prettyPrinter, - new FunctionName(null, $stmt->name->toString()), + new FunctionName($stmt->namespacedName), 0, $stmt, $cond ); - continue; } @@ -881,21 +909,45 @@ function parseStubFile(string $code): FileInfo { $methodInfos[] = parseFunctionLike( $prettyPrinter, - new FunctionName($className, $classStmt->name->toString()), + new MethodName($className, $classStmt->name->toString()), $flags, $classStmt, $cond ); } - $classInfos[] = new ClassInfo($className, $methodInfos); + $fileInfo->classInfos[] = new ClassInfo($className, $methodInfos); continue; } throw new Exception("Unexpected node {$stmt->getType()}"); } +} + +function parseStubFile(string $code): FileInfo { + $lexer = new PhpParser\Lexer(); + $parser = new PhpParser\Parser\Php7($lexer); + $nodeTraverser = new PhpParser\NodeTraverser; + $nodeTraverser->addVisitor(new PhpParser\NodeVisitor\NameResolver); + $prettyPrinter = new class extends Standard { + protected function pName_FullyQualified(Name\FullyQualified $node) { + return implode('\\', $node->parts); + } + }; + + $stmts = $parser->parse($code); + $nodeTraverser->traverse($stmts); + + $fileInfo = new FileInfo; + $fileDocComment = getFileDocComment($stmts); + if ($fileDocComment) { + if (strpos($fileDocComment->getText(), '@generate-function-entries') !== false) { + $fileInfo->generateFunctionEntries = true; + } + } - return new FileInfo($funcInfos, $classInfos, $generateFunctionEntries); + handleStatements($fileInfo, $stmts, $prettyPrinter); + return $fileInfo; } function funcInfoToCode(FuncInfo $funcInfo): string {