1313use PHPCfg \Op ;
1414use RuntimeException ;
1515
16- class Parser
16+ class Helper
1717{
1818 public const KIND_VAR = 1 ;
1919 public const KIND_PARAM = 2 ;
@@ -54,22 +54,35 @@ public static function null(): Type
5454 return self ::makeCachedType (Type::TYPE_NULL );
5555 }
5656
57- public static function object (): Type
57+ public static function object (? string $ userType = null ): Type
5858 {
59+ if ($ userType !== null ) {
60+ return new Type (Type::TYPE_OBJECT , [], $ userType );
61+ }
5962 return self ::makeCachedType (Type::TYPE_OBJECT );
6063 }
6164
65+ public static function array (?Type $ subType = null ): Type
66+ {
67+ if ($ subType !== null ) {
68+ return new Type (Type::TYPE_ARRAY , [$ subType ]);
69+ }
70+ return self ::makeCachedType (Type::TYPE_ARRAY );
71+ }
72+
6273 public static function void (): Type
6374 {
6475 return self ::makeCachedType (Type::TYPE_VOID );
6576 }
6677
78+ public static function callable (): Type
79+ {
80+ return self ::makeCachedType (Type::TYPE_CALLABLE );
81+ }
82+
6783 public static function nullable (Type $ type ): Type
6884 {
69- return (new Type (Type::TYPE_UNION , [
70- $ type ,
71- new Type (Type::TYPE_NULL ),
72- ]))->simplify ();
85+ return static ::union ($ type , static ::null ())->simplify ();
7386 }
7487
7588 private static function makeCachedType (int $ key ): Type
@@ -83,7 +96,7 @@ private static function makeCachedType(int $key): Type
8396 public static function numeric (): Type
8497 {
8598 if (!isset (self ::$ typeCache ["numeric " ])) {
86- self ::$ typeCache ["numeric " ] = new Type (Type:: TYPE_UNION , [ self ::int (), self ::float ()] );
99+ self ::$ typeCache ["numeric " ] = static :: union ( static ::int (), static ::float ());
87100 }
88101 return self ::$ typeCache ["numeric " ];
89102 }
@@ -96,14 +109,19 @@ public static function mixed(): Type
96109 foreach (Type::getPrimitives () as $ key => $ name ) {
97110 $ subs [] = self ::makeCachedType ($ key );
98111 }
99- self ::$ typeCache ["mixed " ] = new Type (Type:: TYPE_UNION , $ subs );
112+ self ::$ typeCache ["mixed " ] = static :: union (... $ subs );
100113 }
101114 return self ::$ typeCache ["mixed " ];
102115 }
103116
104117 public static function union (Type ...$ subTypes ): Type
105118 {
106- return new Type (Type::TYPE_UNION , $ subTypes );
119+ return (new Type (Type::TYPE_UNION , $ subTypes ))->simplify ();
120+ }
121+
122+ public static function intersection (Type ...$ subTypes ): Type
123+ {
124+ return (new Type (Type::TYPE_INTERSECTION , $ subTypes ))->simplify ();
107125 }
108126
109127 /**
@@ -153,38 +171,41 @@ public static function parseDecl(string $decl): Type
153171 case 'bool ' :
154172 case 'false ' :
155173 case 'true ' :
156- return new Type (Type:: TYPE_BOOLEAN );
174+ return static :: bool ( );
157175 case 'integer ' :
158176 case 'int ' :
159- return new Type (Type:: TYPE_LONG );
177+ return static :: int ( );
160178 case 'double ' :
161179 case 'real ' :
162180 case 'float ' :
163- return new Type (Type:: TYPE_DOUBLE );
181+ return static :: float ( );
164182 case 'string ' :
165- return new Type (Type:: TYPE_STRING );
183+ return static :: string ( );
166184 case 'array ' :
167- return new Type (Type:: TYPE_ARRAY );
185+ return static :: array ( );
168186 case 'callable ' :
169- return new Type (Type:: TYPE_CALLABLE );
187+ return static :: callable ( );
170188 case 'null ' :
189+ return static ::null ();
171190 case 'void ' :
172- return new Type (Type:: TYPE_NULL );
191+ return static :: void ( );
173192 case 'numeric ' :
174193 return static ::parseDecl ('int|float ' );
194+ case 'mixed ' :
195+ return static ::mixed ();
175196 }
176197 if (strpos ($ decl , '| ' ) !== false || strpos ($ decl , '& ' ) !== false || strpos ($ decl , '( ' ) !== false ) {
177198 return self ::parseCompexDecl ($ decl )->simplify ();
178199 }
179200 if (substr ($ decl , -2 ) === '[] ' ) {
180201 $ type = static ::parseDecl (substr ($ decl , 0 , -2 ));
181- return new Type (Type:: TYPE_ARRAY , [ $ type] );
202+ return static :: array ( $ type );
182203 }
183204 $ regex = '(^([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]* \\\\)*[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$) ' ;
184- if (!preg_match ($ regex , $ decl )) {
185- throw new RuntimeException ( " Unknown type declaration found: $ decl " );
205+ if ($ decl === ' unknown ' || !preg_match ($ regex , $ decl )) {
206+ return static :: unknown ( );
186207 }
187- return new Type (Type:: TYPE_OBJECT , [], $ decl );
208+ return static :: object ( $ decl );
188209 }
189210
190211 private static function parseCompexDecl (string $ decl ): Type
@@ -231,9 +252,9 @@ private static function parseCompexDecl(string $decl): Type
231252 $ combinator = substr ($ decl , $ pos , 1 );
232253 }
233254 if ($ combinator === '| ' ) {
234- return new Type (Type:: TYPE_UNION , [ $ left , $ right] );
255+ return static :: union ( $ left , $ right );
235256 } elseif ($ combinator === '& ' ) {
236- return new Type (Type:: TYPE_INTERSECTION , [ $ left , $ right] );
257+ return static :: intersection ( $ left , $ right );
237258 }
238259 throw new RuntimeException ("Unknown combinator $ combinator " );
239260 }
@@ -258,16 +279,11 @@ public static function fromOpType(Op\Type $type): Type
258279 return self ::nullable (static ::fromOpType ($ type ->subtype ));
259280 }
260281 if ($ type instanceof Op \Type \Union) {
261- return (new Type (
262- Type::TYPE_UNION ,
263- array_map (fn ($ sub ) => static ::fromOpType ($ sub ), $ type ->subtypes )
264- ))->simplify ();
282+ return static ::union (...array_map (fn ($ sub ) => static ::fromOpType ($ sub ), $ type ->subtypes ))->simplify ();
265283 }
266284 if ($ type instanceof Op \Type \Intersection) {
267- return (new Type (
268- Type::TYPE_INTERSECTION ,
269- array_map (fn ($ sub ) => static ::fromOpType ($ sub ), $ type ->subtypes )
270- ))->simplify ();
285+ return static ::intersection (...array_map (fn ($ sub ) => static ::fromOpType ($ sub ), $ type ->subtypes )
286+ )->simplify ();
271287 }
272288 throw new LogicException ("Unknown type " . $ type ->getType ());
273289 }
0 commit comments