11<?php namespace lang \meta ;
22
3- use lang \IllegalArgumentException ;
43use lang \ast \nodes \{ArrayLiteral , FunctionDeclaration };
54use lang \ast \{Language , Token , Tokens , Visitor , Code };
5+ use lang \{IllegalArgumentException , IllegalStateException };
66
77/**
88 * Parses annotations from AST, using PHP language syntax.
@@ -20,6 +20,14 @@ static function __static() {
2020 self ::$ lang = Language::named ('PHP ' );
2121 }
2222
23+ /** Locates a declared partial of a given class */
24+ private function partial ($ tree , $ class ) {
25+ foreach ($ class ->getTraitNames () as $ declared ) {
26+ if ($ type = $ tree ->type ($ declared )) return $ type ;
27+ }
28+ throw new IllegalStateException ('No part of ' .$ class ->name .' declared in tree ' );
29+ }
30+
2331 /** Locates an anonymous class creation expression */
2432 private function anonymous ($ tree , $ start , $ end ) {
2533 foreach ($ tree ->children () as $ child ) {
@@ -29,31 +37,16 @@ private function anonymous($tree, $start, $end) {
2937 }
3038
3139 /** Returns the syntax tree for a given type using a cache */
32- private function tree ($ reflect ) {
33-
34- // Handle generic class names correctly
35- if ($ class = \xp::$ cn [$ reflect ->name ] ?? null ) {
36- $ class = substr ($ class , 0 , strcspn ($ class , '< ' ));
37- } else {
38- $ class = strtr ($ reflect ->name , '\\' , '. ' );
39- }
40-
41- if (!isset ($ this ->cache [$ class ])) {
42- if ($ reflect ->isAnonymous ()) {
43- $ tree = self ::$ lang ->parse (new Tokens (file_get_contents ($ reflect ->getFileName ()), '<anonymous> ' ))->tree ();
44- $ type = $ this ->anonymous ($ tree , $ reflect ->getStartLine (), $ reflect ->getEndLine ())->current ()->definition ;
45- } else {
46- sscanf (\xp::$ cl [$ class ], '%[^:]://%[^$] ' , $ cl , $ argument );
47- $ instanceFor = [literal ($ cl ), 'instanceFor ' ];
48- $ tree = self ::$ lang ->parse (new Tokens ($ instanceFor ($ argument )->loadClassBytes ($ class ), $ class ))->tree ();
49- $ type = $ tree ->type (strtr ($ class , '. ' , '\\' ));
50- }
51-
52- // Limit cache
53- $ this ->cache [$ class ]= new SyntaxTree ($ tree , $ type );
40+ private function tree ($ class , $ file ) {
41+ if (null === ($ tree = $ this ->cache [$ file ] ?? null )) {
42+ $ this ->cache [$ file ]= $ tree = self ::$ lang ->parse (new Tokens (file_get_contents ($ file ), $ file ))->tree ();
5443 if (sizeof ($ this ->cache ) > self ::CACHE_SIZE ) unset($ this ->cache [key ($ this ->cache )]);
5544 }
56- return $ this ->cache [$ class ];
45+
46+ return new SyntaxTree ($ tree , $ class ->isAnonymous ()
47+ ? $ this ->anonymous ($ tree , $ class ->getStartLine (), $ class ->getEndLine ())->current ()->definition
48+ : $ tree ->type ($ class ->name ) ?? $ this ->partial ($ tree , $ class )
49+ );
5750 }
5851
5952 private function parse ($ code , $ resolver ) {
@@ -154,7 +147,7 @@ private function parse($code, $resolver) {
154147 }
155148
156149 public function evaluate ($ arg , $ code ) {
157- $ tree = $ arg instanceof SyntaxTree ? $ arg : $ this ->tree ($ arg );
150+ $ tree = $ arg instanceof SyntaxTree ? $ arg : $ this ->tree ($ arg, $ arg -> getFileName () );
158151 $ parsed = self ::parse ($ code , $ tree ->resolver ())->tree ()->children ();
159152 if (1 === sizeof ($ parsed )) {
160153 return $ parsed [0 ]->visit ($ tree );
@@ -197,7 +190,7 @@ private function annotations($tree, $annotated) {
197190 }
198191
199192 public function imports ($ reflect ) {
200- $ resolver = $ this ->tree ($ reflect )->resolver ();
193+ $ resolver = $ this ->tree ($ reflect, $ reflect -> getFileName () )->resolver ();
201194 $ imports = [];
202195 foreach ($ resolver ->imports as $ alias => $ type ) {
203196 $ imports [$ alias ]= ltrim ($ type , '\\' );
@@ -207,31 +200,34 @@ public function imports($reflect) {
207200
208201 /** @return iterable */
209202 public function ofType ($ reflect ) {
210- $ tree = $ this ->tree ($ reflect );
203+ $ tree = $ this ->tree ($ reflect, $ reflect -> getFileName () );
211204 return $ this ->annotations ($ tree , $ tree ->type ());
212205 }
213206
214207 /** @return iterable */
215208 public function ofConstant ($ reflect ) {
216- $ tree = $ this ->tree ($ reflect ->getDeclaringClass ());
209+ $ class = $ reflect ->getDeclaringClass ();
210+ $ tree = $ this ->tree ($ class , $ class ->getFileName ());
217211 return $ this ->annotations ($ tree , $ tree ->type ()->constant ($ reflect ->name ));
218212 }
219213
220214 /** @return iterable */
221215 public function ofProperty ($ reflect ) {
222- $ tree = $ this ->tree ($ reflect ->getDeclaringClass ());
216+ $ class = $ reflect ->getDeclaringClass ();
217+ $ tree = $ this ->tree ($ class , $ class ->getFileName ());
223218 return $ this ->annotations ($ tree , $ tree ->type ()->property ($ reflect ->name ));
224219 }
225220
226221 /** @return iterable */
227222 public function ofMethod ($ reflect ) {
228- $ tree = $ this ->tree ($ reflect ->getDeclaringClass ());
223+ $ tree = $ this ->tree ($ reflect ->getDeclaringClass (), $ reflect -> getFileName () );
229224 return $ this ->annotations ($ tree , $ tree ->type ()->method ($ reflect ->name ));
230225 }
231226
232227 /** @return iterable */
233228 public function ofParameter ($ method , $ reflect ) {
234- $ tree = $ this ->tree ($ method ->getDeclaringClass ());
229+ $ class = $ reflect ->getDeclaringClass ();
230+ $ tree = $ this ->tree ($ class , $ class ->getMethod ($ method ->name )->getFileName ());
235231 return $ this ->annotations ($ tree , $ tree ->type ()
236232 ->method ($ method ->name )
237233 ->signature
0 commit comments