From 0cec268d15e5aded8692ee8076e93d2839725918 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 15 Nov 2019 12:50:44 +0100 Subject: Support single class unions in gen stubs --- scripts/dev/gen_stub.php | 76 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 23 deletions(-) (limited to 'scripts') diff --git a/scripts/dev/gen_stub.php b/scripts/dev/gen_stub.php index a02e23b256..c6f9557fb4 100755 --- a/scripts/dev/gen_stub.php +++ b/scripts/dev/gen_stub.php @@ -131,6 +131,10 @@ class SimpleType { } } + public function toEscapedName(): string { + return str_replace('\\', '\\\\', $this->name); + } + public function equals(SimpleType $other) { return $this->name === $other->name && $this->isBuiltin === $other->isBuiltin; @@ -167,15 +171,6 @@ class Type { return false; } - public function isBuiltinOnly(): bool { - foreach ($this->types as $type) { - if (!$type->isBuiltin) { - return false; - } - } - return true; - } - public function getWithoutNull(): Type { return new Type(array_filter($this->types, function(SimpleType $type) { return !$type->isNull(); @@ -190,10 +185,20 @@ class Type { return null; } - public function toTypeMask(): string { - return implode('|', array_map(function(SimpleType $type) { - return $type->toTypeMask(); - }, $this->types)); + public function tryToRepresentableType(): ?RepresentableType { + $classType = null; + $builtinTypes = []; + foreach ($this->types as $type) { + if ($type->isBuiltin) { + $builtinTypes[] = $type; + } else if ($classType === null) { + $classType = $type; + } else { + // We can only represent a single class type. + return false; + } + } + return new RepresentableType($classType, $builtinTypes); } public static function equals(?Type $a, ?Type $b): bool { @@ -215,6 +220,24 @@ class Type { } } +class RepresentableType { + /** @var ?SimpleType $classType */ + public $classType; + /** @var SimpleType[] $builtinTypes */ + public $builtinTypes; + + public function __construct(?SimpleType $classType, array $builtinTypes) { + $this->classType = $classType; + $this->builtinTypes = $builtinTypes; + } + + public function toTypeMask(): string { + return implode('|', array_map(function(SimpleType $type) { + return $type->toTypeMask(); + }, $this->builtinTypes)); + } +} + class ArgInfo { const SEND_BY_VAL = 0; const SEND_BY_REF = 1; @@ -467,8 +490,7 @@ function funcInfoToCode(FuncInfo $funcInfo): string { $code = ''; $returnType = $funcInfo->return->type; if ($returnType !== null) { - $simpleReturnType = $returnType->tryToSimpleType(); - if ($simpleReturnType !== null) { + if (null !== $simpleReturnType = $returnType->tryToSimpleType()) { if ($simpleReturnType->isBuiltin) { $code .= sprintf( "ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_%s, %d, %d, %s, %d)\n", @@ -479,15 +501,23 @@ function funcInfoToCode(FuncInfo $funcInfo): string { $code .= sprintf( "ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_%s, %d, %d, %s, %d)\n", $funcInfo->name, $funcInfo->return->byRef, $funcInfo->numRequiredArgs, - str_replace('\\', '\\\\', $simpleReturnType->name), $returnType->isNullable() + $simpleReturnType->toEscapedName(), $returnType->isNullable() + ); + } + } else if (null !== $representableType = $returnType->tryToRepresentableType()) { + if ($representableType->classType !== null) { + $code .= sprintf( + "ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_%s, %d, %d, %s, %s)\n", + $funcInfo->name, $funcInfo->return->byRef, $funcInfo->numRequiredArgs, + $representableType->classType->toEscapedName(), $representableType->toTypeMask() + ); + } else { + $code .= sprintf( + "ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_%s, %d, %d, %s)\n", + $funcInfo->name, $funcInfo->return->byRef, $funcInfo->numRequiredArgs, + $representableType->toTypeMask() ); } - } else if ($returnType->isBuiltinOnly()) { - $code .= sprintf( - "ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_%s, %d, %d, %s)\n", - $funcInfo->name, $funcInfo->return->byRef, $funcInfo->numRequiredArgs, - $returnType->toTypeMask() - ); } else { throw new Exception('Unimplemented'); } @@ -514,7 +544,7 @@ function funcInfoToCode(FuncInfo $funcInfo): string { $code .= sprintf( "\tZEND_%s_OBJ_INFO(%s, %s, %s, %d)\n", $argKind, $argInfo->getSendByString(), $argInfo->name, - str_replace('\\', '\\\\', $simpleArgType->name), $argType->isNullable() + $simpleArgType->toEscapedName(), $argType->isNullable() ); } } else { -- cgit v1.2.1