@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
package/src/lexer.js ADDED
@@ -0,0 +1,561 @@
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
+ /**
9
+ * This is the php lexer. It will tokenize the string for helping the
10
+ * parser to build the AST from its grammar.
11
+ *
12
+ * @constructor Lexer
13
+ * @memberOf module:php-parser
14
+ * @property {number} EOF
15
+ * @property {boolean} all_tokens defines if all tokens must be retrieved (used by token_get_all only)
16
+ * @property {boolean} comment_tokens extracts comments tokens
17
+ * @property {boolean} mode_eval enables the evald mode (ignore opening tags)
18
+ * @property {boolean} asp_tags disables by default asp tags mode
19
+ * @property {boolean} short_tags enables by default short tags mode
20
+ * @property {object} keywords List of php keyword
21
+ * @property {object} castKeywords List of php keywords for type casting
22
+ */
23
+ const Lexer = function (engine) {
24
+ this.engine = engine;
25
+ this.tok = this.engine.tokens.names;
26
+ this.EOF = 1;
27
+ this.debug = false;
28
+ this.all_tokens = true;
29
+ this.comment_tokens = false;
30
+ this.mode_eval = false;
31
+ this.asp_tags = false;
32
+ this.short_tags = false;
33
+ this.version = 803;
34
+ this.yyprevcol = 0;
35
+ this.keywords = {
36
+ __class__: this.tok.T_CLASS_C,
37
+ __trait__: this.tok.T_TRAIT_C,
38
+ __function__: this.tok.T_FUNC_C,
39
+ __method__: this.tok.T_METHOD_C,
40
+ __line__: this.tok.T_LINE,
41
+ __file__: this.tok.T_FILE,
42
+ __dir__: this.tok.T_DIR,
43
+ __namespace__: this.tok.T_NS_C,
44
+ exit: this.tok.T_EXIT,
45
+ die: this.tok.T_EXIT,
46
+ function: this.tok.T_FUNCTION,
47
+ const: this.tok.T_CONST,
48
+ return: this.tok.T_RETURN,
49
+ try: this.tok.T_TRY,
50
+ catch: this.tok.T_CATCH,
51
+ finally: this.tok.T_FINALLY,
52
+ throw: this.tok.T_THROW,
53
+ if: this.tok.T_IF,
54
+ elseif: this.tok.T_ELSEIF,
55
+ endif: this.tok.T_ENDIF,
56
+ else: this.tok.T_ELSE,
57
+ while: this.tok.T_WHILE,
58
+ endwhile: this.tok.T_ENDWHILE,
59
+ do: this.tok.T_DO,
60
+ for: this.tok.T_FOR,
61
+ endfor: this.tok.T_ENDFOR,
62
+ foreach: this.tok.T_FOREACH,
63
+ endforeach: this.tok.T_ENDFOREACH,
64
+ declare: this.tok.T_DECLARE,
65
+ enddeclare: this.tok.T_ENDDECLARE,
66
+ instanceof: this.tok.T_INSTANCEOF,
67
+ as: this.tok.T_AS,
68
+ switch: this.tok.T_SWITCH,
69
+ endswitch: this.tok.T_ENDSWITCH,
70
+ case: this.tok.T_CASE,
71
+ default: this.tok.T_DEFAULT,
72
+ break: this.tok.T_BREAK,
73
+ continue: this.tok.T_CONTINUE,
74
+ goto: this.tok.T_GOTO,
75
+ echo: this.tok.T_ECHO,
76
+ print: this.tok.T_PRINT,
77
+ class: this.tok.T_CLASS,
78
+ interface: this.tok.T_INTERFACE,
79
+ trait: this.tok.T_TRAIT,
80
+ enum: this.tok.T_ENUM,
81
+ extends: this.tok.T_EXTENDS,
82
+ implements: this.tok.T_IMPLEMENTS,
83
+ new: this.tok.T_NEW,
84
+ clone: this.tok.T_CLONE,
85
+ var: this.tok.T_VAR,
86
+ eval: this.tok.T_EVAL,
87
+ include: this.tok.T_INCLUDE,
88
+ include_once: this.tok.T_INCLUDE_ONCE,
89
+ require: this.tok.T_REQUIRE,
90
+ require_once: this.tok.T_REQUIRE_ONCE,
91
+ namespace: this.tok.T_NAMESPACE,
92
+ use: this.tok.T_USE,
93
+ insteadof: this.tok.T_INSTEADOF,
94
+ global: this.tok.T_GLOBAL,
95
+ isset: this.tok.T_ISSET,
96
+ empty: this.tok.T_EMPTY,
97
+ __halt_compiler: this.tok.T_HALT_COMPILER,
98
+ static: this.tok.T_STATIC,
99
+ abstract: this.tok.T_ABSTRACT,
100
+ final: this.tok.T_FINAL,
101
+ private: this.tok.T_PRIVATE,
102
+ protected: this.tok.T_PROTECTED,
103
+ public: this.tok.T_PUBLIC,
104
+ unset: this.tok.T_UNSET,
105
+ list: this.tok.T_LIST,
106
+ array: this.tok.T_ARRAY,
107
+ callable: this.tok.T_CALLABLE,
108
+ or: this.tok.T_LOGICAL_OR,
109
+ and: this.tok.T_LOGICAL_AND,
110
+ xor: this.tok.T_LOGICAL_XOR,
111
+ match: this.tok.T_MATCH,
112
+ readonly: this.tok.T_READ_ONLY,
113
+ };
114
+ this.castKeywords = {
115
+ int: this.tok.T_INT_CAST,
116
+ integer: this.tok.T_INT_CAST,
117
+ real: this.tok.T_DOUBLE_CAST,
118
+ double: this.tok.T_DOUBLE_CAST,
119
+ float: this.tok.T_DOUBLE_CAST,
120
+ string: this.tok.T_STRING_CAST,
121
+ binary: this.tok.T_STRING_CAST,
122
+ array: this.tok.T_ARRAY_CAST,
123
+ object: this.tok.T_OBJECT_CAST,
124
+ bool: this.tok.T_BOOL_CAST,
125
+ boolean: this.tok.T_BOOL_CAST,
126
+ unset: this.tok.T_UNSET_CAST,
127
+ };
128
+ };
129
+
130
+ /**
131
+ * Initialize the lexer with the specified input
132
+ * @function Lexer#setInput
133
+ * @memberOf module:php-parser
134
+ */
135
+ Lexer.prototype.setInput = function (input) {
136
+ this._input = input;
137
+ this.size = input.length;
138
+ this.yylineno = 1;
139
+ this.offset = 0;
140
+ this.yyprevcol = 0;
141
+ this.yytext = "";
142
+ this.yylloc = {
143
+ first_offset: 0,
144
+ first_line: 1,
145
+ first_column: 0,
146
+ prev_offset: 0,
147
+ prev_line: 1,
148
+ prev_column: 0,
149
+ last_line: 1,
150
+ last_column: 0,
151
+ };
152
+ this.tokens = [];
153
+ if (this.version > 703) {
154
+ this.keywords.fn = this.tok.T_FN;
155
+ } else {
156
+ delete this.keywords.fn;
157
+ }
158
+ this.done = this.offset >= this.size;
159
+ if (!this.all_tokens && this.mode_eval) {
160
+ this.conditionStack = ["INITIAL"];
161
+ this.begin("ST_IN_SCRIPTING");
162
+ } else {
163
+ this.conditionStack = [];
164
+ this.begin("INITIAL");
165
+ }
166
+ // https://github.com/php/php-src/blob/999e32b65a8a4bb59e27e538fa68ffae4b99d863/Zend/zend_language_scanner.h#L59
167
+ // Used for heredoc and nowdoc
168
+ this.heredoc_label = {
169
+ label: "",
170
+ length: 0,
171
+ indentation: 0,
172
+ indentation_uses_spaces: false,
173
+ finished: false,
174
+ /*
175
+ * this used for parser to detemine the if current node segment is first encaps node.
176
+ * if ture, the indentation will remove from the begining. and if false, the prev node
177
+ * might be a variable '}' ,and the leading spaces should not be removed util meet the
178
+ * first \n
179
+ */
180
+ first_encaps_node: false,
181
+ // for backward compatible
182
+ /* istanbul ignore next */
183
+ toString() {
184
+ this.label;
185
+ },
186
+ };
187
+ return this;
188
+ };
189
+
190
+ /**
191
+ * consumes and returns one char from the input
192
+ * @function Lexer#input
193
+ * @memberOf module:php-parser
194
+ */
195
+ Lexer.prototype.input = function () {
196
+ const ch = this._input[this.offset];
197
+ if (!ch) return "";
198
+ this.yytext += ch;
199
+ this.offset++;
200
+ if (ch === "\r" && this._input[this.offset] === "\n") {
201
+ this.yytext += "\n";
202
+ this.offset++;
203
+ }
204
+ if (ch === "\n" || ch === "\r") {
205
+ this.yylloc.last_line = ++this.yylineno;
206
+ this.yyprevcol = this.yylloc.last_column;
207
+ this.yylloc.last_column = 0;
208
+ } else {
209
+ this.yylloc.last_column++;
210
+ }
211
+ return ch;
212
+ };
213
+
214
+ /**
215
+ * revert eating specified size
216
+ * @function Lexer#unput
217
+ * @memberOf module:php-parser
218
+ */
219
+ Lexer.prototype.unput = function (size) {
220
+ if (size === 1) {
221
+ // 1 char unput (most cases)
222
+ this.offset--;
223
+ if (
224
+ this._input[this.offset] === "\n" &&
225
+ this._input[this.offset - 1] === "\r"
226
+ ) {
227
+ this.offset--;
228
+ size++;
229
+ }
230
+ if (
231
+ this._input[this.offset] === "\r" ||
232
+ this._input[this.offset] === "\n"
233
+ ) {
234
+ this.yylloc.last_line--;
235
+ this.yylineno--;
236
+ this.yylloc.last_column = this.yyprevcol;
237
+ } else {
238
+ this.yylloc.last_column--;
239
+ }
240
+ this.yytext = this.yytext.substring(0, this.yytext.length - size);
241
+ } else if (size > 0) {
242
+ this.offset -= size;
243
+ if (size < this.yytext.length) {
244
+ this.yytext = this.yytext.substring(0, this.yytext.length - size);
245
+ // re-calculate position
246
+ this.yylloc.last_line = this.yylloc.first_line;
247
+ this.yylloc.last_column = this.yyprevcol = this.yylloc.first_column;
248
+ for (let i = 0; i < this.yytext.length; i++) {
249
+ let c = this.yytext[i];
250
+ if (c === "\r") {
251
+ c = this.yytext[++i];
252
+ this.yyprevcol = this.yylloc.last_column;
253
+ this.yylloc.last_line++;
254
+ this.yylloc.last_column = 0;
255
+ if (c !== "\n") {
256
+ if (c === "\r") {
257
+ this.yylloc.last_line++;
258
+ } else {
259
+ this.yylloc.last_column++;
260
+ }
261
+ }
262
+ } else if (c === "\n") {
263
+ this.yyprevcol = this.yylloc.last_column;
264
+ this.yylloc.last_line++;
265
+ this.yylloc.last_column = 0;
266
+ } else {
267
+ this.yylloc.last_column++;
268
+ }
269
+ }
270
+ this.yylineno = this.yylloc.last_line;
271
+ } else {
272
+ // reset full text
273
+ this.yytext = "";
274
+ this.yylloc.last_line = this.yylineno = this.yylloc.first_line;
275
+ this.yylloc.last_column = this.yylloc.first_column;
276
+ }
277
+ }
278
+
279
+ return this;
280
+ };
281
+
282
+ /**
283
+ * check if the text matches
284
+ * @function Lexer#tryMatch
285
+ * @memberOf module:php-parser
286
+ * @param {string} text
287
+ * @returns {boolean}
288
+ */
289
+ Lexer.prototype.tryMatch = function (text) {
290
+ return text === this.ahead(text.length);
291
+ };
292
+
293
+ /**
294
+ * check if the text matches
295
+ * @function Lexer#tryMatchCaseless
296
+ * @memberOf module:php-parser
297
+ * @param {string} text
298
+ * @returns {boolean}
299
+ */
300
+ Lexer.prototype.tryMatchCaseless = function (text) {
301
+ return text === this.ahead(text.length).toLowerCase();
302
+ };
303
+
304
+ /**
305
+ * look ahead
306
+ * @function Lexer#ahead
307
+ * @memberOf module:php-parser
308
+ * @param {number} size
309
+ * @returns {string}
310
+ */
311
+ Lexer.prototype.ahead = function (size) {
312
+ let text = this._input.substring(this.offset, this.offset + size);
313
+ if (
314
+ text[text.length - 1] === "\r" &&
315
+ this._input[this.offset + size + 1] === "\n"
316
+ ) {
317
+ text += "\n";
318
+ }
319
+ return text;
320
+ };
321
+
322
+ /**
323
+ * consume the specified size
324
+ * @function Lexer#consume
325
+ * @memberOf module:php-parser
326
+ * @param {number} size
327
+ * @returns {Lexer}
328
+ */
329
+ Lexer.prototype.consume = function (size) {
330
+ for (let i = 0; i < size; i++) {
331
+ const ch = this._input[this.offset];
332
+ if (!ch) break;
333
+ this.yytext += ch;
334
+ this.offset++;
335
+ if (ch === "\r" && this._input[this.offset] === "\n") {
336
+ this.yytext += "\n";
337
+ this.offset++;
338
+ i++;
339
+ }
340
+ if (ch === "\n" || ch === "\r") {
341
+ this.yylloc.last_line = ++this.yylineno;
342
+ this.yyprevcol = this.yylloc.last_column;
343
+ this.yylloc.last_column = 0;
344
+ } else {
345
+ this.yylloc.last_column++;
346
+ }
347
+ }
348
+ return this;
349
+ };
350
+
351
+ /**
352
+ * Gets the current state
353
+ * @function Lexer#getState
354
+ * @memberOf module:php-parser
355
+ */
356
+ Lexer.prototype.getState = function () {
357
+ return {
358
+ yytext: this.yytext,
359
+ offset: this.offset,
360
+ yylineno: this.yylineno,
361
+ yyprevcol: this.yyprevcol,
362
+ yylloc: {
363
+ first_offset: this.yylloc.first_offset,
364
+ first_line: this.yylloc.first_line,
365
+ first_column: this.yylloc.first_column,
366
+ last_line: this.yylloc.last_line,
367
+ last_column: this.yylloc.last_column,
368
+ },
369
+ heredoc_label: this.heredoc_label,
370
+ };
371
+ };
372
+
373
+ /**
374
+ * Sets the current lexer state
375
+ * @function Lexer#setState
376
+ * @memberOf module:php-parser
377
+ */
378
+ Lexer.prototype.setState = function (state) {
379
+ this.yytext = state.yytext;
380
+ this.offset = state.offset;
381
+ this.yylineno = state.yylineno;
382
+ this.yyprevcol = state.yyprevcol;
383
+ this.yylloc = state.yylloc;
384
+ if (state.heredoc_label) {
385
+ this.heredoc_label = state.heredoc_label;
386
+ }
387
+ return this;
388
+ };
389
+
390
+ /**
391
+ * prepend next token
392
+ * @function Lexer#appendToken
393
+ * @memberOf module:php-parser
394
+ * @param {*} value
395
+ * @param {*} ahead
396
+ * @returns {Lexer}
397
+ */
398
+ Lexer.prototype.appendToken = function (value, ahead) {
399
+ this.tokens.push([value, ahead]);
400
+ return this;
401
+ };
402
+
403
+ /**
404
+ * return next match that has a token
405
+ * @function Lexer#lex
406
+ * @memberOf module:php-parser
407
+ * @returns {number|string}
408
+ */
409
+ Lexer.prototype.lex = function () {
410
+ this.yylloc.prev_offset = this.offset;
411
+ this.yylloc.prev_line = this.yylloc.last_line;
412
+ this.yylloc.prev_column = this.yylloc.last_column;
413
+ let token = this.next() || this.lex();
414
+ if (!this.all_tokens) {
415
+ while (
416
+ token === this.tok.T_WHITESPACE || // ignore white space
417
+ (!this.comment_tokens &&
418
+ (token === this.tok.T_COMMENT || // ignore single lines comments
419
+ token === this.tok.T_DOC_COMMENT)) || // ignore doc comments
420
+ // ignore open tags
421
+ token === this.tok.T_OPEN_TAG
422
+ ) {
423
+ token = this.next() || this.lex();
424
+ }
425
+ if (token == this.tok.T_OPEN_TAG_WITH_ECHO) {
426
+ // https://github.com/php/php-src/blob/7ff186434e82ee7be7c59d0db9a976641cf7b09c/Zend/zend_compile.c#L1683
427
+ // open tag with echo statement
428
+ return this.tok.T_ECHO;
429
+ } else if (token === this.tok.T_CLOSE_TAG) {
430
+ // https://github.com/php/php-src/blob/7ff186434e82ee7be7c59d0db9a976641cf7b09c/Zend/zend_compile.c#L1680
431
+ return ";"; /* implicit ; */
432
+ }
433
+ }
434
+ if (!this.yylloc.prev_offset) {
435
+ this.yylloc.prev_offset = this.yylloc.first_offset;
436
+ this.yylloc.prev_line = this.yylloc.first_line;
437
+ this.yylloc.prev_column = this.yylloc.first_column;
438
+ }
439
+ /*else if (this.yylloc.prev_offset === this.offset && this.offset !== this.size) {
440
+ throw new Error('Infinite loop @ ' + this.offset + ' / ' + this.size);
441
+ }*/
442
+ return token;
443
+ };
444
+
445
+ /**
446
+ * activates a new lexer condition state (pushes the new lexer condition state onto the condition stack)
447
+ * @function Lexer#begin
448
+ * @memberOf module:php-parser
449
+ * @param {*} condition
450
+ * @returns {Lexer}
451
+ */
452
+ Lexer.prototype.begin = function (condition) {
453
+ this.conditionStack.push(condition);
454
+ this.curCondition = condition;
455
+ this.stateCb = this["match" + condition];
456
+ /* istanbul ignore next */
457
+ if (typeof this.stateCb !== "function") {
458
+ throw new Error('Undefined condition state "' + condition + '"');
459
+ }
460
+ return this;
461
+ };
462
+
463
+ /**
464
+ * pop the previously active lexer condition state off the condition stack
465
+ * @function Lexer#popState
466
+ * @memberOf module:php-parser
467
+ * @returns {string|*}
468
+ */
469
+ Lexer.prototype.popState = function () {
470
+ const n = this.conditionStack.length - 1;
471
+ const condition = n > 0 ? this.conditionStack.pop() : this.conditionStack[0];
472
+ this.curCondition = this.conditionStack[this.conditionStack.length - 1];
473
+ this.stateCb = this["match" + this.curCondition];
474
+ /* istanbul ignore next */
475
+ if (typeof this.stateCb !== "function") {
476
+ throw new Error('Undefined condition state "' + this.curCondition + '"');
477
+ }
478
+ return condition;
479
+ };
480
+
481
+ /**
482
+ * return next match in input
483
+ * @function Lexer#next
484
+ * @memberOf module:php-parser
485
+ * @returns {number|*}
486
+ */
487
+ Lexer.prototype.next = function () {
488
+ let token;
489
+ if (!this._input) {
490
+ this.done = true;
491
+ }
492
+ this.yylloc.first_offset = this.offset;
493
+ this.yylloc.first_line = this.yylloc.last_line;
494
+ this.yylloc.first_column = this.yylloc.last_column;
495
+ this.yytext = "";
496
+ if (this.done) {
497
+ this.yylloc.prev_offset = this.yylloc.first_offset;
498
+ this.yylloc.prev_line = this.yylloc.first_line;
499
+ this.yylloc.prev_column = this.yylloc.first_column;
500
+ return this.EOF;
501
+ }
502
+ if (this.tokens.length > 0) {
503
+ token = this.tokens.shift();
504
+ if (typeof token[1] === "object") {
505
+ this.setState(token[1]);
506
+ } else {
507
+ this.consume(token[1]);
508
+ }
509
+ token = token[0];
510
+ } else {
511
+ token = this.stateCb.apply(this, []);
512
+ }
513
+ if (this.offset >= this.size && this.tokens.length === 0) {
514
+ this.done = true;
515
+ }
516
+ /* istanbul ignore next */
517
+ if (this.debug) {
518
+ let tName = token;
519
+ if (typeof tName === "number") {
520
+ tName = this.engine.tokens.values[tName];
521
+ } else {
522
+ tName = '"' + tName + '"';
523
+ }
524
+ const e = new Error(
525
+ tName +
526
+ "\tfrom " +
527
+ this.yylloc.first_line +
528
+ "," +
529
+ this.yylloc.first_column +
530
+ "\t - to " +
531
+ this.yylloc.last_line +
532
+ "," +
533
+ this.yylloc.last_column +
534
+ '\t"' +
535
+ this.yytext +
536
+ '"',
537
+ );
538
+ // eslint-disable-next-line no-console
539
+ console.error(e.stack);
540
+ }
541
+ return token;
542
+ };
543
+
544
+ // extends the lexer with states
545
+ [
546
+ require("./lexer/attribute.js"),
547
+ require("./lexer/comments.js"),
548
+ require("./lexer/initial.js"),
549
+ require("./lexer/numbers.js"),
550
+ require("./lexer/property.js"),
551
+ require("./lexer/scripting.js"),
552
+ require("./lexer/strings.js"),
553
+ require("./lexer/tokens.js"),
554
+ require("./lexer/utils.js"),
555
+ ].forEach(function (ext) {
556
+ for (const k in ext) {
557
+ Lexer.prototype[k] = ext[k];
558
+ }
559
+ });
560
+
561
+ module.exports = Lexer;
@@ -0,0 +1,113 @@
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
+ module.exports = {
9
+ /*
10
+ * Parse an array
11
+ * ```ebnf
12
+ * array ::= T_ARRAY '(' array_pair_list ')' |
13
+ * '[' array_pair_list ']'
14
+ * ```
15
+ */
16
+ read_array() {
17
+ let expect = null;
18
+ let shortForm = false;
19
+ const result = this.node("array");
20
+
21
+ if (this.token === this.tok.T_ARRAY) {
22
+ this.next().expect("(");
23
+ expect = ")";
24
+ } else {
25
+ shortForm = true;
26
+ expect = "]";
27
+ }
28
+ let items = [];
29
+ if (this.next().token !== expect) {
30
+ items = this.read_array_pair_list(shortForm);
31
+ }
32
+ this.expect(expect);
33
+ this.next();
34
+ return result(shortForm, items);
35
+ },
36
+ /*
37
+ * Reads an array of items
38
+ * ```ebnf
39
+ * array_pair_list ::= array_pair (',' array_pair?)*
40
+ * ```
41
+ */
42
+ read_array_pair_list(shortForm) {
43
+ const self = this;
44
+ return this.read_list(
45
+ function () {
46
+ return self.read_array_pair(shortForm);
47
+ },
48
+ ",",
49
+ true,
50
+ );
51
+ },
52
+ /*
53
+ * Reads an entry
54
+ * array_pair:
55
+ * expr T_DOUBLE_ARROW expr
56
+ * | expr
57
+ * | expr T_DOUBLE_ARROW '&' variable
58
+ * | '&' variable
59
+ * | expr T_DOUBLE_ARROW T_LIST '(' array_pair_list ')'
60
+ * | T_LIST '(' array_pair_list ')'
61
+ */
62
+ read_array_pair(shortForm) {
63
+ if (
64
+ (!shortForm && this.token === ")") ||
65
+ (shortForm && this.token === "]")
66
+ ) {
67
+ return;
68
+ }
69
+
70
+ if (this.token === ",") {
71
+ return this.node("noop")();
72
+ }
73
+
74
+ const entry = this.node("entry");
75
+
76
+ let key = null;
77
+ let value = null;
78
+ let byRef = false;
79
+ let unpack = false;
80
+
81
+ if (this.token === "&") {
82
+ this.next();
83
+ byRef = true;
84
+ value = this.read_variable(true, false);
85
+ } else if (this.token === this.tok.T_ELLIPSIS && this.version >= 704) {
86
+ this.next();
87
+ if (this.token === "&") {
88
+ this.error();
89
+ }
90
+ unpack = true;
91
+ value = this.read_expr();
92
+ } else {
93
+ const expr = this.read_expr();
94
+
95
+ if (this.token === this.tok.T_DOUBLE_ARROW) {
96
+ this.next();
97
+ key = expr;
98
+
99
+ if (this.token === "&") {
100
+ this.next();
101
+ byRef = true;
102
+ value = this.read_variable(true, false);
103
+ } else {
104
+ value = this.read_expr();
105
+ }
106
+ } else {
107
+ value = expr;
108
+ }
109
+ }
110
+
111
+ return entry(key, value, byRef, unpack);
112
+ },
113
+ };