@@ -16,24 +16,53 @@ class ConstExprParser
16
16
/** @var bool */
17
17
private $ quoteAwareConstExprString ;
18
18
19
- public function __construct (bool $ unescapeStrings = false , bool $ quoteAwareConstExprString = false )
19
+ /** @var bool */
20
+ private $ useLinesAttributes ;
21
+
22
+ /** @var bool */
23
+ private $ useIndexAttributes ;
24
+
25
+ /**
26
+ * @param array{lines?: bool, indexes?: bool} $usedAttributes
27
+ */
28
+ public function __construct (
29
+ bool $ unescapeStrings = false ,
30
+ bool $ quoteAwareConstExprString = false ,
31
+ array $ usedAttributes = []
32
+ )
20
33
{
21
34
$ this ->unescapeStrings = $ unescapeStrings ;
22
35
$ this ->quoteAwareConstExprString = $ quoteAwareConstExprString ;
36
+ $ this ->useLinesAttributes = $ usedAttributes ['lines ' ] ?? false ;
37
+ $ this ->useIndexAttributes = $ usedAttributes ['indexes ' ] ?? false ;
23
38
}
24
39
25
40
public function parse (TokenIterator $ tokens , bool $ trimStrings = false ): Ast \ConstExpr \ConstExprNode
26
41
{
42
+ $ startLine = $ tokens ->currentTokenLine ();
43
+ $ startIndex = $ tokens ->currentTokenIndex ();
27
44
if ($ tokens ->isCurrentTokenType (Lexer::TOKEN_FLOAT )) {
28
45
$ value = $ tokens ->currentTokenValue ();
29
46
$ tokens ->next ();
30
- return new Ast \ConstExpr \ConstExprFloatNode ($ value );
47
+
48
+ return $ this ->enrichWithAttributes (
49
+ $ tokens ,
50
+ new Ast \ConstExpr \ConstExprFloatNode ($ value ),
51
+ $ startLine ,
52
+ $ startIndex
53
+ );
31
54
}
32
55
33
56
if ($ tokens ->isCurrentTokenType (Lexer::TOKEN_INTEGER )) {
34
57
$ value = $ tokens ->currentTokenValue ();
35
58
$ tokens ->next ();
36
- return new Ast \ConstExpr \ConstExprIntegerNode ($ value );
59
+
60
+ return $ this ->enrichWithAttributes (
61
+ $ tokens ,
62
+ new Ast \ConstExpr \ConstExprIntegerNode ($ value ),
63
+ $ startLine ,
64
+ $ startIndex
65
+ );
37
66
}
38
67
39
68
if ($ tokens ->isCurrentTokenType (Lexer::TOKEN_SINGLE_QUOTED_STRING , Lexer::TOKEN_DOUBLE_QUOTED_STRING )) {
@@ -49,27 +78,52 @@ public function parse(TokenIterator $tokens, bool $trimStrings = false): Ast\Con
49
78
$ tokens ->next ();
50
79
51
80
if ($ this ->quoteAwareConstExprString ) {
52
- return new Ast \ConstExpr \QuoteAwareConstExprStringNode (
53
- $ value ,
54
- $ type === Lexer::TOKEN_SINGLE_QUOTED_STRING
55
- ? Ast \ConstExpr \QuoteAwareConstExprStringNode::SINGLE_QUOTED
56
- : Ast \ConstExpr \QuoteAwareConstExprStringNode::DOUBLE_QUOTED
81
+ return $ this ->enrichWithAttributes (
82
+ $ tokens ,
83
+ new Ast \ConstExpr \QuoteAwareConstExprStringNode (
84
+ $ value ,
85
+ $ type === Lexer::TOKEN_SINGLE_QUOTED_STRING
86
+ ? Ast \ConstExpr \QuoteAwareConstExprStringNode::SINGLE_QUOTED
87
+ : Ast \ConstExpr \QuoteAwareConstExprStringNode::DOUBLE_QUOTED
88
+ ),
89
+ $ startLine ,
90
+ $ startIndex
57
91
);
58
92
}
59
93
60
- return new Ast \ConstExpr \ConstExprStringNode ($ value );
94
+ return $ this ->enrichWithAttributes (
95
+ $ tokens ,
96
+ new Ast \ConstExpr \ConstExprStringNode ($ value ),
97
+ $ startLine ,
98
+ $ startIndex
99
+ );
61
100
62
101
} elseif ($ tokens ->isCurrentTokenType (Lexer::TOKEN_IDENTIFIER )) {
63
102
$ identifier = $ tokens ->currentTokenValue ();
64
103
$ tokens ->next ();
65
104
66
105
switch (strtolower ($ identifier )) {
67
106
case 'true ' :
68
- return new Ast \ConstExpr \ConstExprTrueNode ();
107
+ return $ this ->enrichWithAttributes (
108
+ $ tokens ,
109
+ new Ast \ConstExpr \ConstExprTrueNode (),
110
+ $ startLine ,
111
+ $ startIndex
112
+ );
69
113
case 'false ' :
70
- return new Ast \ConstExpr \ConstExprFalseNode ();
114
+ return $ this ->enrichWithAttributes (
115
+ $ tokens ,
116
+ new Ast \ConstExpr \ConstExprFalseNode (),
117
+ $ startLine ,
118
+ $ startIndex
119
+ );
71
120
case 'null ' :
72
- return new Ast \ConstExpr \ConstExprNullNode ();
121
+ return $ this ->enrichWithAttributes (
122
+ $ tokens ,
123
+ new Ast \ConstExpr \ConstExprNullNode (),
124
+ $ startLine ,
125
+ $ startIndex
126
+ );
73
127
case 'array ' :
74
128
$ tokens ->consumeTokenType (Lexer::TOKEN_OPEN_PARENTHESES );
75
129
return $ this ->parseArray ($ tokens , Lexer::TOKEN_CLOSE_PARENTHESES );
@@ -106,11 +160,21 @@ public function parse(TokenIterator $tokens, bool $trimStrings = false): Ast\Con
106
160
break ;
107
161
}
108
162
109
- return new Ast \ConstExpr \ConstFetchNode ($ identifier , $ classConstantName );
163
+ return $ this ->enrichWithAttributes (
164
+ $ tokens ,
165
+ new Ast \ConstExpr \ConstFetchNode ($ identifier , $ classConstantName ),
166
+ $ startLine ,
167
+ $ startIndex
168
+ );
110
169
111
170
}
112
171
113
- return new Ast \ConstExpr \ConstFetchNode ('' , $ identifier );
172
+ return $ this ->enrichWithAttributes (
173
+ $ tokens ,
174
+ new Ast \ConstExpr \ConstFetchNode ('' , $ identifier ),
175
+ $ startLine ,
176
+ $ startIndex
177
+ );
114
178
115
179
} elseif ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_OPEN_SQUARE_BRACKET )) {
116
180
return $ this ->parseArray ($ tokens , Lexer::TOKEN_CLOSE_SQUARE_BRACKET );
@@ -131,19 +195,30 @@ private function parseArray(TokenIterator $tokens, int $endToken): Ast\ConstExpr
131
195
{
132
196
$ items = [];
133
197
198
+ $ startLine = $ tokens ->currentTokenLine ();
199
+ $ startIndex = $ tokens ->currentTokenIndex ();
200
+
134
201
if (!$ tokens ->tryConsumeTokenType ($ endToken )) {
135
202
do {
136
203
$ items [] = $ this ->parseArrayItem ($ tokens );
137
204
} while ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_COMMA ) && !$ tokens ->isCurrentTokenType ($ endToken ));
138
205
$ tokens ->consumeTokenType ($ endToken );
139
206
}
140
207
141
- return new Ast \ConstExpr \ConstExprArrayNode ($ items );
208
+ return $ this ->enrichWithAttributes (
209
+ $ tokens ,
210
+ new Ast \ConstExpr \ConstExprArrayNode ($ items ),
211
+ $ startLine ,
212
+ $ startIndex
213
+ );
142
214
}
143
215
144
216
145
217
private function parseArrayItem (TokenIterator $ tokens ): Ast \ConstExpr \ConstExprArrayItemNode
146
218
{
219
+ $ startLine = $ tokens ->currentTokenLine ();
220
+ $ startIndex = $ tokens ->currentTokenIndex ();
221
+
147
222
$ expr = $ this ->parse ($ tokens );
148
223
149
224
if ($ tokens ->tryConsumeTokenType (Lexer::TOKEN_DOUBLE_ARROW )) {
@@ -155,7 +230,40 @@ private function parseArrayItem(TokenIterator $tokens): Ast\ConstExpr\ConstExprA
155
230
$ value = $ expr ;
156
231
}
157
232
158
- return new Ast \ConstExpr \ConstExprArrayItemNode ($ key , $ value );
233
+ return $ this ->enrichWithAttributes (
234
+ $ tokens ,
235
+ new Ast \ConstExpr \ConstExprArrayItemNode ($ key , $ value ),
236
+ $ startLine ,
237
+ $ startIndex
238
+ );
239
+ }
240
+
241
+ /**
242
+ * @template T of Ast\ConstExpr\ConstExprNode
243
+ * @param T $node
244
+ * @return T
245
+ */
246
+ private function enrichWithAttributes (TokenIterator $ tokens , Ast \ConstExpr \ConstExprNode $ node , int $ startLine , int $ startIndex ): Ast \ConstExpr \ConstExprNode
247
+ {
248
+ $ endLine = $ tokens ->currentTokenLine ();
249
+ $ endIndex = $ tokens ->currentTokenIndex ();
250
+ if ($ this ->useLinesAttributes ) {
251
+ $ node ->setAttribute (Ast \Attribute::START_LINE , $ startLine );
252
+ $ node ->setAttribute (Ast \Attribute::END_LINE , $ endLine );
253
+ }
254
+
255
+ if ($ this ->useIndexAttributes ) {
256
+ $ tokensArray = $ tokens ->getTokens ();
257
+ $ endIndex --;
258
+ if ($ tokensArray [$ endIndex ][Lexer::TYPE_OFFSET ] === Lexer::TOKEN_HORIZONTAL_WS ) {
259
+ $ endIndex --;
260
+ }
261
+
262
+ $ node ->setAttribute (Ast \Attribute::START_INDEX , $ startIndex );
263
+ $ node ->setAttribute (Ast \Attribute::END_INDEX , $ endIndex );
264
+ }
265
+
266
+ return $ node ;
159
267
}
160
268
161
269
}
0 commit comments