@jorgsowa/php-parser 3.2.5-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/LICENSE +27 -0
  2. package/README.md +108 -0
  3. package/dist/@jorgsowa/php-parser.js +11239 -0
  4. package/dist/@jorgsowa/php-parser.min.js +2 -0
  5. package/dist/@jorgsowa/php-parser.min.js.LICENSE.txt +10 -0
  6. package/package.json +86 -0
  7. package/src/ast/array.js +44 -0
  8. package/src/ast/arrowfunc.js +43 -0
  9. package/src/ast/assign.js +28 -0
  10. package/src/ast/assignref.js +27 -0
  11. package/src/ast/attrgroup.js +21 -0
  12. package/src/ast/attribute.js +26 -0
  13. package/src/ast/bin.js +27 -0
  14. package/src/ast/block.js +24 -0
  15. package/src/ast/boolean.js +23 -0
  16. package/src/ast/break.js +21 -0
  17. package/src/ast/byref.js +21 -0
  18. package/src/ast/call.js +26 -0
  19. package/src/ast/case.js +26 -0
  20. package/src/ast/cast.js +28 -0
  21. package/src/ast/catch.js +29 -0
  22. package/src/ast/class.js +36 -0
  23. package/src/ast/classconstant.js +71 -0
  24. package/src/ast/clone.js +21 -0
  25. package/src/ast/closure.js +47 -0
  26. package/src/ast/comment.js +23 -0
  27. package/src/ast/commentblock.js +22 -0
  28. package/src/ast/commentline.js +22 -0
  29. package/src/ast/constant.js +26 -0
  30. package/src/ast/constantstatement.js +24 -0
  31. package/src/ast/continue.js +24 -0
  32. package/src/ast/declaration.js +60 -0
  33. package/src/ast/declare.js +71 -0
  34. package/src/ast/declaredirective.js +26 -0
  35. package/src/ast/do.js +26 -0
  36. package/src/ast/echo.js +26 -0
  37. package/src/ast/empty.js +23 -0
  38. package/src/ast/encapsed.js +75 -0
  39. package/src/ast/encapsedpart.js +28 -0
  40. package/src/ast/entry.js +30 -0
  41. package/src/ast/enum.js +30 -0
  42. package/src/ast/enumcase.js +26 -0
  43. package/src/ast/error.js +30 -0
  44. package/src/ast/eval.js +24 -0
  45. package/src/ast/exit.js +26 -0
  46. package/src/ast/expression.js +20 -0
  47. package/src/ast/expressionstatement.js +24 -0
  48. package/src/ast/for.js +33 -0
  49. package/src/ast/foreach.js +33 -0
  50. package/src/ast/function.js +34 -0
  51. package/src/ast/global.js +24 -0
  52. package/src/ast/goto.js +22 -0
  53. package/src/ast/halt.js +22 -0
  54. package/src/ast/identifier.js +26 -0
  55. package/src/ast/if.js +30 -0
  56. package/src/ast/include.js +28 -0
  57. package/src/ast/inline.js +23 -0
  58. package/src/ast/interface.js +28 -0
  59. package/src/ast/intersectiontype.js +24 -0
  60. package/src/ast/isset.js +23 -0
  61. package/src/ast/label.js +21 -0
  62. package/src/ast/list.js +26 -0
  63. package/src/ast/literal.js +28 -0
  64. package/src/ast/location.js +22 -0
  65. package/src/ast/lookup.js +26 -0
  66. package/src/ast/magic.js +22 -0
  67. package/src/ast/match.js +26 -0
  68. package/src/ast/matcharm.js +26 -0
  69. package/src/ast/method.js +24 -0
  70. package/src/ast/name.js +55 -0
  71. package/src/ast/namedargument.js +27 -0
  72. package/src/ast/namespace.js +26 -0
  73. package/src/ast/new.js +26 -0
  74. package/src/ast/node.js +111 -0
  75. package/src/ast/noop.js +20 -0
  76. package/src/ast/nowdoc.js +26 -0
  77. package/src/ast/nullkeyword.js +20 -0
  78. package/src/ast/nullsafepropertylookup.js +22 -0
  79. package/src/ast/number.js +23 -0
  80. package/src/ast/offsetlookup.js +22 -0
  81. package/src/ast/operation.js +19 -0
  82. package/src/ast/parameter.js +61 -0
  83. package/src/ast/parentreference.js +24 -0
  84. package/src/ast/position.js +22 -0
  85. package/src/ast/post.js +26 -0
  86. package/src/ast/pre.js +26 -0
  87. package/src/ast/print.js +23 -0
  88. package/src/ast/program.js +32 -0
  89. package/src/ast/property.js +46 -0
  90. package/src/ast/propertyhook.js +33 -0
  91. package/src/ast/propertylookup.js +22 -0
  92. package/src/ast/propertystatement.js +59 -0
  93. package/src/ast/reference.js +21 -0
  94. package/src/ast/retif.js +28 -0
  95. package/src/ast/return.js +21 -0
  96. package/src/ast/selfreference.js +24 -0
  97. package/src/ast/silent.js +24 -0
  98. package/src/ast/statement.js +19 -0
  99. package/src/ast/static.js +24 -0
  100. package/src/ast/staticlookup.js +22 -0
  101. package/src/ast/staticreference.js +24 -0
  102. package/src/ast/staticvariable.js +26 -0
  103. package/src/ast/string.js +28 -0
  104. package/src/ast/switch.js +28 -0
  105. package/src/ast/throw.js +21 -0
  106. package/src/ast/trait.js +24 -0
  107. package/src/ast/traitalias.js +44 -0
  108. package/src/ast/traitprecedence.js +28 -0
  109. package/src/ast/traituse.js +26 -0
  110. package/src/ast/try.js +28 -0
  111. package/src/ast/typereference.js +40 -0
  112. package/src/ast/unary.js +26 -0
  113. package/src/ast/uniontype.js +24 -0
  114. package/src/ast/unset.js +23 -0
  115. package/src/ast/usegroup.js +30 -0
  116. package/src/ast/useitem.js +45 -0
  117. package/src/ast/variable.js +36 -0
  118. package/src/ast/variadic.js +25 -0
  119. package/src/ast/variadicplaceholder.js +24 -0
  120. package/src/ast/while.js +28 -0
  121. package/src/ast/yield.js +27 -0
  122. package/src/ast/yieldfrom.js +25 -0
  123. package/src/ast.js +593 -0
  124. package/src/index.js +239 -0
  125. package/src/lexer/attribute.js +85 -0
  126. package/src/lexer/comments.js +63 -0
  127. package/src/lexer/initial.js +64 -0
  128. package/src/lexer/numbers.js +171 -0
  129. package/src/lexer/property.js +96 -0
  130. package/src/lexer/scripting.js +114 -0
  131. package/src/lexer/strings.js +524 -0
  132. package/src/lexer/tokens.js +356 -0
  133. package/src/lexer/utils.js +112 -0
  134. package/src/lexer.js +561 -0
  135. package/src/parser/array.js +113 -0
  136. package/src/parser/class.js +718 -0
  137. package/src/parser/comment.js +52 -0
  138. package/src/parser/enum.js +56 -0
  139. package/src/parser/expr.js +848 -0
  140. package/src/parser/function.js +507 -0
  141. package/src/parser/if.js +94 -0
  142. package/src/parser/loops.js +168 -0
  143. package/src/parser/main.js +21 -0
  144. package/src/parser/namespace.js +231 -0
  145. package/src/parser/scalar.js +492 -0
  146. package/src/parser/statement.js +444 -0
  147. package/src/parser/switch.js +99 -0
  148. package/src/parser/try.js +43 -0
  149. package/src/parser/utils.js +203 -0
  150. package/src/parser/variable.js +363 -0
  151. package/src/parser.js +748 -0
  152. package/src/tokens.js +177 -0
  153. package/types.d.ts +1457 -0
@@ -0,0 +1,524 @@
1
+ /**
2
+ * Copyright (C) 2018 Glayzzle (BSD3 License)
3
+ * @authors https://github.com/glayzzle/php-parser/graphs/contributors
4
+ * @url http://glayzzle.com
5
+ */
6
+ "use strict";
7
+
8
+ const newline = ["\n", "\r"];
9
+ const valid_after_heredoc = ["\n", "\r", ";"];
10
+ const valid_after_heredoc_73 = valid_after_heredoc.concat([
11
+ "\t",
12
+ " ",
13
+ ",",
14
+ "]",
15
+ ")",
16
+ "/",
17
+ "=",
18
+ "!",
19
+ ".",
20
+ ]);
21
+
22
+ module.exports = {
23
+ T_CONSTANT_ENCAPSED_STRING() {
24
+ let ch;
25
+ while (this.offset < this.size) {
26
+ ch = this.input();
27
+ if (ch == "\\") {
28
+ this.input();
29
+ } else if (ch == "'") {
30
+ break;
31
+ }
32
+ }
33
+ return this.tok.T_CONSTANT_ENCAPSED_STRING;
34
+ },
35
+ // check if matching a HEREDOC state
36
+ is_HEREDOC() {
37
+ const revert = this.offset;
38
+ if (
39
+ this._input[this.offset - 1] === "<" &&
40
+ this._input[this.offset] === "<" &&
41
+ this._input[this.offset + 1] === "<"
42
+ ) {
43
+ this.offset += 3;
44
+
45
+ // optional tabs / spaces
46
+ if (this.is_TABSPACE()) {
47
+ while (this.offset < this.size) {
48
+ this.offset++;
49
+ if (!this.is_TABSPACE()) {
50
+ break;
51
+ }
52
+ }
53
+ }
54
+
55
+ // optional quotes
56
+ let tChar = this._input[this.offset - 1];
57
+ if (tChar === "'" || tChar === '"') {
58
+ this.offset++;
59
+ } else {
60
+ tChar = null;
61
+ }
62
+
63
+ // required label
64
+ if (this.is_LABEL_START()) {
65
+ let yyoffset = this.offset - 1;
66
+ while (this.offset < this.size) {
67
+ this.offset++;
68
+ if (!this.is_LABEL()) {
69
+ break;
70
+ }
71
+ }
72
+ const yylabel = this._input.substring(yyoffset, this.offset - 1);
73
+ if (!tChar || tChar === this._input[this.offset - 1]) {
74
+ // required ending quote
75
+ if (tChar) this.offset++;
76
+ // require newline
77
+ if (newline.includes(this._input[this.offset - 1])) {
78
+ // go go go
79
+ this.heredoc_label.label = yylabel;
80
+ this.heredoc_label.length = yylabel.length;
81
+ this.heredoc_label.finished = false;
82
+ yyoffset = this.offset - revert;
83
+ this.offset = revert;
84
+ this.consume(yyoffset);
85
+ if (tChar === "'") {
86
+ this.begin("ST_NOWDOC");
87
+ } else {
88
+ this.begin("ST_HEREDOC");
89
+ }
90
+ // prematch to get the indentation information from end of doc
91
+ this.prematch_ENDOFDOC();
92
+ return this.tok.T_START_HEREDOC;
93
+ }
94
+ }
95
+ }
96
+ }
97
+ this.offset = revert;
98
+ return false;
99
+ },
100
+ ST_DOUBLE_QUOTES() {
101
+ let ch;
102
+ while (this.offset < this.size) {
103
+ ch = this.input();
104
+ if (ch == "\\") {
105
+ this.input();
106
+ } else if (ch == '"') {
107
+ break;
108
+ } else if (ch == "$") {
109
+ ch = this.input();
110
+ if (ch == "{" || this.is_LABEL_START()) {
111
+ this.unput(2);
112
+ break;
113
+ }
114
+ if (ch) this.unput(1);
115
+ } else if (ch == "{") {
116
+ ch = this.input();
117
+ if (ch == "$") {
118
+ this.unput(2);
119
+ break;
120
+ }
121
+ if (ch) this.unput(1);
122
+ }
123
+ }
124
+ if (ch == '"') {
125
+ return this.tok.T_CONSTANT_ENCAPSED_STRING;
126
+ } else {
127
+ let prefix = 1;
128
+ if (this.yytext[0] === "b" || this.yytext[0] === "B") {
129
+ prefix = 2;
130
+ }
131
+ if (this.yytext.length > 2) {
132
+ this.appendToken(
133
+ this.tok.T_ENCAPSED_AND_WHITESPACE,
134
+ this.yytext.length - prefix,
135
+ );
136
+ }
137
+ this.unput(this.yytext.length - prefix);
138
+ this.begin("ST_DOUBLE_QUOTES");
139
+ return this.yytext;
140
+ }
141
+ },
142
+
143
+ // check if its a DOC end sequence
144
+ isDOC_MATCH(offset, consumeLeadingSpaces) {
145
+ // @fixme : check if out of text limits
146
+
147
+ // consumeLeadingSpaces is false happen DOC prematch END HEREDOC stage.
148
+
149
+ // Ensure current state is really after a new line break, not after a such as ${variables}
150
+ const prev_ch = this._input[offset - 2];
151
+ if (!newline.includes(prev_ch)) {
152
+ return false;
153
+ }
154
+
155
+ // skip leading spaces or tabs
156
+ let indentation_uses_spaces = false;
157
+ let indentation_uses_tabs = false;
158
+ // reset heredoc_label structure
159
+ let indentation = 0;
160
+ let leading_ch = this._input[offset - 1];
161
+
162
+ if (this.version >= 703) {
163
+ while (leading_ch === "\t" || leading_ch === " ") {
164
+ if (leading_ch === " ") {
165
+ indentation_uses_spaces = true;
166
+ } else if (leading_ch === "\t") {
167
+ indentation_uses_tabs = true;
168
+ }
169
+
170
+ leading_ch = this._input[offset + indentation];
171
+ indentation++;
172
+ }
173
+
174
+ // Move offset to skip leading whitespace
175
+ offset = offset + indentation;
176
+
177
+ // return out if there was only whitespace on this line
178
+ if (newline.includes(this._input[offset - 1])) {
179
+ return false;
180
+ }
181
+ }
182
+
183
+ if (
184
+ this._input.substring(
185
+ offset - 1,
186
+ offset - 1 + this.heredoc_label.length,
187
+ ) === this.heredoc_label.label
188
+ ) {
189
+ const ch = this._input[offset - 1 + this.heredoc_label.length];
190
+ if (
191
+ (this.version >= 703
192
+ ? valid_after_heredoc_73
193
+ : valid_after_heredoc
194
+ ).includes(ch)
195
+ ) {
196
+ if (consumeLeadingSpaces) {
197
+ this.consume(indentation);
198
+ // https://wiki.php.net/rfc/flexible_heredoc_nowdoc_syntaxes
199
+ if (indentation_uses_spaces && indentation_uses_tabs) {
200
+ throw new Error(
201
+ "Parse error: mixing spaces and tabs in ending marker at line " +
202
+ this.yylineno +
203
+ " (offset " +
204
+ this.offset +
205
+ ")",
206
+ );
207
+ }
208
+ } else {
209
+ // Called in prematch_ENDOFDOC
210
+ this.heredoc_label.indentation = indentation;
211
+ this.heredoc_label.indentation_uses_spaces = indentation_uses_spaces;
212
+ this.heredoc_label.first_encaps_node = true;
213
+ }
214
+ return true;
215
+ }
216
+ }
217
+
218
+ return false;
219
+ },
220
+
221
+ /*
222
+ * Prematch the end of HEREDOC/NOWDOC end tag to preset the
223
+ * context of this.heredoc_label
224
+ */
225
+ prematch_ENDOFDOC() {
226
+ // reset heredoc
227
+ this.heredoc_label.indentation_uses_spaces = false;
228
+ this.heredoc_label.indentation = 0;
229
+ this.heredoc_label.first_encaps_node = true;
230
+ let offset = this.offset + 1;
231
+
232
+ while (offset < this._input.length) {
233
+ // if match heredoc_label structrue will be set
234
+ if (this.isDOC_MATCH(offset, false)) {
235
+ return;
236
+ }
237
+
238
+ if (!newline.includes(this._input[offset - 1])) {
239
+ // skip one line
240
+ while (
241
+ !newline.includes(this._input[offset++]) &&
242
+ offset < this._input.length
243
+ ) {
244
+ // skip
245
+ }
246
+ }
247
+
248
+ offset++;
249
+ }
250
+ },
251
+
252
+ matchST_NOWDOC() {
253
+ // edge case : empty now doc
254
+ if (this.isDOC_MATCH(this.offset, true)) {
255
+ // @fixme : never reached (may be caused by quotes)
256
+ this.consume(this.heredoc_label.length);
257
+ this.popState();
258
+ return this.tok.T_END_HEREDOC;
259
+ }
260
+ // SCANNING CONTENTS
261
+ let ch = this._input[this.offset - 1];
262
+ while (this.offset < this.size) {
263
+ if (newline.includes(ch)) {
264
+ ch = this.input();
265
+ if (this.isDOC_MATCH(this.offset, true)) {
266
+ this.unput(1).popState();
267
+ this.appendToken(this.tok.T_END_HEREDOC, this.heredoc_label.length);
268
+ return this.tok.T_ENCAPSED_AND_WHITESPACE;
269
+ }
270
+ } else {
271
+ ch = this.input();
272
+ }
273
+ }
274
+ // too bad ! reached end of document (will get a parse error)
275
+ return this.tok.T_ENCAPSED_AND_WHITESPACE;
276
+ },
277
+
278
+ matchST_HEREDOC() {
279
+ // edge case : empty here doc
280
+ let ch = this.input();
281
+ if (this.isDOC_MATCH(this.offset, true)) {
282
+ this.consume(this.heredoc_label.length - 1);
283
+ this.popState();
284
+ return this.tok.T_END_HEREDOC;
285
+ }
286
+ // SCANNING CONTENTS
287
+ while (this.offset < this.size) {
288
+ if (ch === "\\") {
289
+ ch = this.input(); // ignore next
290
+ if (!newline.includes(ch)) {
291
+ ch = this.input();
292
+ }
293
+ }
294
+
295
+ if (newline.includes(ch)) {
296
+ ch = this.input();
297
+ if (this.isDOC_MATCH(this.offset, true)) {
298
+ this.unput(1).popState();
299
+ this.appendToken(this.tok.T_END_HEREDOC, this.heredoc_label.length);
300
+ return this.tok.T_ENCAPSED_AND_WHITESPACE;
301
+ }
302
+ } else if (ch === "$") {
303
+ ch = this.input();
304
+ if (ch === "{") {
305
+ // start of ${
306
+ this.begin("ST_LOOKING_FOR_VARNAME");
307
+ if (this.yytext.length > 2) {
308
+ this.appendToken(this.tok.T_DOLLAR_OPEN_CURLY_BRACES, 2);
309
+ this.unput(2);
310
+ return this.tok.T_ENCAPSED_AND_WHITESPACE;
311
+ } else {
312
+ return this.tok.T_DOLLAR_OPEN_CURLY_BRACES;
313
+ }
314
+ } else if (this.is_LABEL_START()) {
315
+ // start of $var...
316
+ const yyoffset = this.offset;
317
+ const next = this.consume_VARIABLE();
318
+ if (this.yytext.length > this.offset - yyoffset + 2) {
319
+ this.appendToken(next, this.offset - yyoffset + 2);
320
+ this.unput(this.offset - yyoffset + 2);
321
+ return this.tok.T_ENCAPSED_AND_WHITESPACE;
322
+ } else {
323
+ return next;
324
+ }
325
+ //console.log(this.yytext);
326
+ }
327
+ } else if (ch === "{") {
328
+ ch = this.input();
329
+ if (ch === "$") {
330
+ // start of {$...
331
+ this.begin("ST_IN_SCRIPTING");
332
+ if (this.yytext.length > 2) {
333
+ this.appendToken(this.tok.T_CURLY_OPEN, 1);
334
+ this.unput(2);
335
+ return this.tok.T_ENCAPSED_AND_WHITESPACE;
336
+ } else {
337
+ this.unput(1);
338
+ return this.tok.T_CURLY_OPEN;
339
+ }
340
+ }
341
+ } else {
342
+ ch = this.input();
343
+ }
344
+ }
345
+
346
+ // too bad ! reached end of document (will get a parse error)
347
+ return this.tok.T_ENCAPSED_AND_WHITESPACE;
348
+ },
349
+
350
+ consume_VARIABLE() {
351
+ this.consume_LABEL();
352
+ const ch = this.input();
353
+ if (ch == "[") {
354
+ this.unput(1);
355
+ this.begin("ST_VAR_OFFSET");
356
+ return this.tok.T_VARIABLE;
357
+ } else if (ch === "-") {
358
+ if (this.input() === ">") {
359
+ this.input();
360
+ if (this.is_LABEL_START()) {
361
+ this.begin("ST_LOOKING_FOR_PROPERTY");
362
+ }
363
+ this.unput(3);
364
+ return this.tok.T_VARIABLE;
365
+ } else {
366
+ this.unput(2);
367
+ }
368
+ } else {
369
+ if (ch) this.unput(1);
370
+ }
371
+ return this.tok.T_VARIABLE;
372
+ },
373
+ // HANDLES BACKQUOTES
374
+ matchST_BACKQUOTE() {
375
+ let ch = this.input();
376
+ if (ch === "$") {
377
+ ch = this.input();
378
+ if (ch === "{") {
379
+ this.begin("ST_LOOKING_FOR_VARNAME");
380
+ return this.tok.T_DOLLAR_OPEN_CURLY_BRACES;
381
+ } else if (this.is_LABEL_START()) {
382
+ const tok = this.consume_VARIABLE();
383
+ return tok;
384
+ }
385
+ } else if (ch === "{") {
386
+ if (this._input[this.offset] === "$") {
387
+ this.begin("ST_IN_SCRIPTING");
388
+ return this.tok.T_CURLY_OPEN;
389
+ }
390
+ } else if (ch === "`") {
391
+ this.popState();
392
+ return "`";
393
+ }
394
+
395
+ // any char
396
+ while (this.offset < this.size) {
397
+ if (ch === "\\") {
398
+ this.input();
399
+ } else if (ch === "`") {
400
+ this.unput(1);
401
+ this.popState();
402
+ this.appendToken("`", 1);
403
+ break;
404
+ } else if (ch === "$") {
405
+ ch = this.input();
406
+ if (ch === "{") {
407
+ this.begin("ST_LOOKING_FOR_VARNAME");
408
+ if (this.yytext.length > 2) {
409
+ this.appendToken(this.tok.T_DOLLAR_OPEN_CURLY_BRACES, 2);
410
+ this.unput(2);
411
+ return this.tok.T_ENCAPSED_AND_WHITESPACE;
412
+ } else {
413
+ return this.tok.T_DOLLAR_OPEN_CURLY_BRACES;
414
+ }
415
+ } else if (this.is_LABEL_START()) {
416
+ // start of $var...
417
+ const yyoffset = this.offset;
418
+ const next = this.consume_VARIABLE();
419
+ if (this.yytext.length > this.offset - yyoffset + 2) {
420
+ this.appendToken(next, this.offset - yyoffset + 2);
421
+ this.unput(this.offset - yyoffset + 2);
422
+ return this.tok.T_ENCAPSED_AND_WHITESPACE;
423
+ } else {
424
+ return next;
425
+ }
426
+ }
427
+ continue;
428
+ } else if (ch === "{") {
429
+ ch = this.input();
430
+ if (ch === "$") {
431
+ // start of {$...
432
+ this.begin("ST_IN_SCRIPTING");
433
+ if (this.yytext.length > 2) {
434
+ this.appendToken(this.tok.T_CURLY_OPEN, 1);
435
+ this.unput(2);
436
+ return this.tok.T_ENCAPSED_AND_WHITESPACE;
437
+ } else {
438
+ this.unput(1);
439
+ return this.tok.T_CURLY_OPEN;
440
+ }
441
+ }
442
+ continue;
443
+ }
444
+ ch = this.input();
445
+ }
446
+ return this.tok.T_ENCAPSED_AND_WHITESPACE;
447
+ },
448
+
449
+ matchST_DOUBLE_QUOTES() {
450
+ let ch = this.input();
451
+ if (ch === "$") {
452
+ ch = this.input();
453
+ if (ch === "{") {
454
+ this.begin("ST_LOOKING_FOR_VARNAME");
455
+ return this.tok.T_DOLLAR_OPEN_CURLY_BRACES;
456
+ } else if (this.is_LABEL_START()) {
457
+ const tok = this.consume_VARIABLE();
458
+ return tok;
459
+ }
460
+ } else if (ch === "{") {
461
+ if (this._input[this.offset] === "$") {
462
+ this.begin("ST_IN_SCRIPTING");
463
+ return this.tok.T_CURLY_OPEN;
464
+ }
465
+ } else if (ch === '"') {
466
+ this.popState();
467
+ return '"';
468
+ }
469
+
470
+ // any char
471
+ while (this.offset < this.size) {
472
+ if (ch === "\\") {
473
+ this.input();
474
+ } else if (ch === '"') {
475
+ this.unput(1);
476
+ this.popState();
477
+ this.appendToken('"', 1);
478
+ break;
479
+ } else if (ch === "$") {
480
+ ch = this.input();
481
+ if (ch === "{") {
482
+ this.begin("ST_LOOKING_FOR_VARNAME");
483
+ if (this.yytext.length > 2) {
484
+ this.appendToken(this.tok.T_DOLLAR_OPEN_CURLY_BRACES, 2);
485
+ this.unput(2);
486
+ return this.tok.T_ENCAPSED_AND_WHITESPACE;
487
+ } else {
488
+ return this.tok.T_DOLLAR_OPEN_CURLY_BRACES;
489
+ }
490
+ } else if (this.is_LABEL_START()) {
491
+ // start of $var...
492
+ const yyoffset = this.offset;
493
+ const next = this.consume_VARIABLE();
494
+ if (this.yytext.length > this.offset - yyoffset + 2) {
495
+ this.appendToken(next, this.offset - yyoffset + 2);
496
+ this.unput(this.offset - yyoffset + 2);
497
+ return this.tok.T_ENCAPSED_AND_WHITESPACE;
498
+ } else {
499
+ return next;
500
+ }
501
+ }
502
+ if (ch) this.unput(1);
503
+ } else if (ch === "{") {
504
+ ch = this.input();
505
+ if (ch === "$") {
506
+ // start of {$...
507
+ this.begin("ST_IN_SCRIPTING");
508
+ if (this.yytext.length > 2) {
509
+ this.appendToken(this.tok.T_CURLY_OPEN, 1);
510
+ this.unput(2);
511
+ return this.tok.T_ENCAPSED_AND_WHITESPACE;
512
+ } else {
513
+ // @fixme : yytext = '"{$' (this.yytext.length > 3)
514
+ this.unput(1);
515
+ return this.tok.T_CURLY_OPEN;
516
+ }
517
+ }
518
+ if (ch) this.unput(1);
519
+ }
520
+ ch = this.input();
521
+ }
522
+ return this.tok.T_ENCAPSED_AND_WHITESPACE;
523
+ },
524
+ };