44
55namespace TypeLang \PhpDocParser \DocBlock \Extractor ;
66
7+ use TypeLang \Parser \Node \FullQualifiedName ;
8+ use TypeLang \Parser \Node \Identifier ;
9+ use TypeLang \Parser \Node \Literal \VariableLiteralNode ;
10+ use TypeLang \Parser \Node \Name ;
11+ use TypeLang \PhpDocParser \DocBlock \Reference \ClassConstReference ;
12+ use TypeLang \PhpDocParser \DocBlock \Reference \ClassPropertyReference ;
13+ use TypeLang \PhpDocParser \DocBlock \Reference \FunctionReference ;
14+ use TypeLang \PhpDocParser \DocBlock \Reference \GenericReference ;
15+ use TypeLang \PhpDocParser \DocBlock \Reference \MethodReference ;
16+ use TypeLang \PhpDocParser \DocBlock \Reference \NameReference ;
717use TypeLang \PhpDocParser \DocBlock \Reference \ReferenceInterface ;
818use TypeLang \PhpDocParser \DocBlock \Reference \UriReference ;
919
@@ -27,6 +37,166 @@ public function extract(string $body): array
2737
2838 private function parseReference (string $ body ): ReferenceInterface
2939 {
30- return new UriReference ($ body );
40+ if ($ result = $ this ->tryParseUriReference ($ body )) {
41+ return $ result ;
42+ }
43+
44+ if (\str_ends_with ($ body , '() ' )) {
45+ return $ this ->tryParseCallableReference ($ body )
46+ ?? new GenericReference ($ body );
47+ }
48+
49+ if (\str_contains ($ body , ':: ' )) {
50+ return \str_contains ($ body , '$ ' )
51+ ? $ this ->tryParseClassProperty ($ body )
52+ : $ this ->tryParseClassConst ($ body );
53+ }
54+
55+ if ($ result = $ this ->tryParseNameReference ($ body )) {
56+ return $ result ;
57+ }
58+
59+ return new GenericReference ($ body );
60+ }
61+
62+ private function tryParseClassProperty (string $ body ): ?ClassPropertyReference
63+ {
64+ $ parts = \explode (':: ' , $ body );
65+
66+ if (\count ($ parts ) !== 2 ) {
67+ return null ;
68+ }
69+
70+ if (($ variable = $ this ->tryParseVariable ($ parts [1 ])) === null ) {
71+ return null ;
72+ }
73+
74+ if (($ name = $ this ->tryParseName ($ parts [0 ])) === null ) {
75+ return null ;
76+ }
77+
78+ return new ClassPropertyReference ($ name , $ variable );
79+ }
80+
81+ private function tryParseClassConst (string $ body ): ?ClassConstReference
82+ {
83+ $ parts = \explode (':: ' , $ body );
84+
85+ if (\count ($ parts ) !== 2 ) {
86+ return null ;
87+ }
88+
89+ if (($ callable = $ this ->tryParseIdentifier ($ parts [1 ])) === null ) {
90+ return null ;
91+ }
92+
93+ if (($ name = $ this ->tryParseName ($ parts [0 ])) === null ) {
94+ return null ;
95+ }
96+
97+ return new ClassConstReference ($ name , $ callable );
98+ }
99+
100+ private function tryParseNameReference (string $ body ): ?NameReference
101+ {
102+ return null ;
103+ }
104+
105+ private function tryParseCallableReference (string $ body ): FunctionReference |MethodReference |null
106+ {
107+ if (\str_contains ($ body , ':: ' )) {
108+ return $ this ->tryParseMethod ($ body );
109+ }
110+
111+ return $ this ->tryParseFunction ($ body );
112+ }
113+
114+ private function tryParseFunction (string $ body ): ?FunctionReference
115+ {
116+ $ callable = $ this ->tryParseName (\substr ($ body , 0 , -2 ));
117+
118+ if ($ callable !== null ) {
119+ return new FunctionReference ($ callable );
120+ }
121+
122+ return null ;
123+ }
124+
125+ private function tryParseMethod (string $ body ): ?MethodReference
126+ {
127+ $ parts = \explode (':: ' , \substr ($ body , 0 , -2 ));
128+
129+ if (\count ($ parts ) !== 2 ) {
130+ return null ;
131+ }
132+
133+ if (($ callable = $ this ->tryParseIdentifier ($ parts [1 ])) === null ) {
134+ return null ;
135+ }
136+
137+ if (($ name = $ this ->tryParseName ($ parts [0 ])) === null ) {
138+ return null ;
139+ }
140+
141+ return new MethodReference ($ name , $ callable );
142+ }
143+
144+ private function tryParseName (string $ name ): ?Name
145+ {
146+ if ($ fqn = \str_starts_with ($ name , '\\' )) {
147+ $ name = \substr ($ name , 1 );
148+ }
149+
150+ $ parts = [];
151+
152+ foreach (\explode ('\\' , $ name ) as $ chunk ) {
153+ $ identifier = $ this ->tryParseIdentifier ($ chunk );
154+
155+ if ($ identifier === null ) {
156+ return null ;
157+ }
158+
159+ $ parts [] = $ identifier ;
160+ }
161+
162+ return $ fqn ? new FullQualifiedName ($ parts ) : new Name ($ parts );
163+ }
164+
165+ private function tryParseVariable (string $ name ): ?VariableLiteralNode
166+ {
167+ if (\preg_match ('/^\$[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$/ ' , $ name ) === 0 ) {
168+ return null ;
169+ }
170+
171+ return new VariableLiteralNode ($ name );
172+ }
173+
174+ private function tryParseIdentifier (string $ name ): ?Identifier
175+ {
176+ if (\preg_match ('/^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$/ ' , $ name ) === 0 ) {
177+ return null ;
178+ }
179+
180+ return new Identifier ($ name );
181+ }
182+
183+ private function tryParseUriReference (string $ body ): ?UriReference
184+ {
185+ $ result = \parse_url ($ body );
186+
187+ if (!\is_array ($ result ) || !isset ($ result ['host ' ])) {
188+ return null ;
189+ }
190+
191+ return new UriReference (
192+ scheme: $ result ['scheme ' ] ?? '' ,
193+ host: $ result ['host ' ],
194+ port: $ result ['port ' ] ?? null ,
195+ path: $ result ['path ' ] ?? '/ ' ,
196+ query: $ result ['query ' ] ?? '' ,
197+ fragment: $ result ['fragment ' ] ?? '' ,
198+ user: $ result ['user ' ] ?? '' ,
199+ password: $ result ['pass ' ] ?? '' ,
200+ );
31201 }
32202}
0 commit comments