@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,444 @@
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
+ * reading a list of top statements (helper for top_statement*)
11
+ * ```ebnf
12
+ * top_statements ::= top_statement*
13
+ * ```
14
+ */
15
+ read_top_statements() {
16
+ let result = [];
17
+ while (this.token !== this.EOF && this.token !== "}") {
18
+ const statement = this.read_top_statement();
19
+ if (statement) {
20
+ if (Array.isArray(statement)) {
21
+ result = result.concat(statement);
22
+ } else {
23
+ result.push(statement);
24
+ }
25
+ }
26
+ }
27
+ return result;
28
+ },
29
+ /*
30
+ * reading a top statement
31
+ * ```ebnf
32
+ * top_statement ::=
33
+ * namespace | function | class
34
+ * | interface | trait
35
+ * | use_statements | const_list
36
+ * | statement
37
+ * ```
38
+ */
39
+ read_top_statement() {
40
+ let attrs = [];
41
+ if (this.token === this.tok.T_ATTRIBUTE) {
42
+ attrs = this.read_attr_list();
43
+ }
44
+ switch (this.token) {
45
+ case this.tok.T_FUNCTION:
46
+ return this.read_function(false, false, attrs);
47
+ // optional flags
48
+ case this.tok.T_ABSTRACT:
49
+ case this.tok.T_FINAL:
50
+ case this.tok.T_READ_ONLY:
51
+ case this.tok.T_CLASS:
52
+ return this.read_class_declaration_statement(attrs);
53
+ case this.tok.T_INTERFACE:
54
+ return this.read_interface_declaration_statement(attrs);
55
+ case this.tok.T_TRAIT:
56
+ return this.read_trait_declaration_statement();
57
+ case this.tok.T_ENUM:
58
+ return this.read_enum_declaration_statement(attrs);
59
+ case this.tok.T_USE:
60
+ return this.read_use_statement();
61
+ case this.tok.T_CONST: {
62
+ const result = this.node("constantstatement");
63
+ const items = this.next().read_const_list();
64
+ this.expectEndOfStatement();
65
+ return result(null, items);
66
+ }
67
+ case this.tok.T_NAMESPACE:
68
+ return this.read_namespace();
69
+ case this.tok.T_HALT_COMPILER: {
70
+ const result = this.node("halt");
71
+ if (this.next().expect("(")) this.next();
72
+ if (this.expect(")")) this.next();
73
+ this.expect(";");
74
+ this.lexer.done = true;
75
+ return result(this.lexer._input.substring(this.lexer.offset));
76
+ }
77
+ default:
78
+ return this.read_statement();
79
+ }
80
+ },
81
+ /*
82
+ * reads a list of simple inner statements (helper for inner_statement*)
83
+ * ```ebnf
84
+ * inner_statements ::= inner_statement*
85
+ * ```
86
+ */
87
+ read_inner_statements() {
88
+ let result = [];
89
+ while (this.token != this.EOF && this.token !== "}") {
90
+ const statement = this.read_inner_statement();
91
+ if (statement) {
92
+ if (Array.isArray(statement)) {
93
+ result = result.concat(statement);
94
+ } else {
95
+ result.push(statement);
96
+ }
97
+ }
98
+ }
99
+ return result;
100
+ },
101
+ /*
102
+ * Reads a list of constants declaration
103
+ * ```ebnf
104
+ * const_list ::= T_CONST T_STRING '=' expr (',' T_STRING '=' expr)* ';'
105
+ * ```
106
+ */
107
+ read_const_list() {
108
+ return this.read_list(
109
+ function () {
110
+ this.expect(this.tok.T_STRING);
111
+ const result = this.node("constant");
112
+ let constName = this.node("identifier");
113
+ const name = this.text();
114
+ this.next();
115
+ constName = constName(name);
116
+ if (this.expect("=")) {
117
+ return result(constName, this.next().read_expr());
118
+ } else {
119
+ // fallback
120
+ return result(constName, null);
121
+ }
122
+ },
123
+ ",",
124
+ false,
125
+ );
126
+ },
127
+ /*
128
+ * Reads a list of constants declaration
129
+ * ```ebnf
130
+ * declare_list ::= IDENTIFIER '=' expr (',' IDENTIFIER '=' expr)*
131
+ * ```
132
+ * @retrurn {Array}
133
+ */
134
+ read_declare_list() {
135
+ const result = [];
136
+ while (this.token != this.EOF && this.token !== ")") {
137
+ this.expect(this.tok.T_STRING);
138
+ const directive = this.node("declaredirective");
139
+ let key = this.node("identifier");
140
+ const name = this.text();
141
+ this.next();
142
+ key = key(name);
143
+ let value = null;
144
+ if (this.expect("=")) {
145
+ value = this.next().read_expr();
146
+ }
147
+ result.push(directive(key, value));
148
+ if (this.token !== ",") break;
149
+ this.next();
150
+ }
151
+ return result;
152
+ },
153
+ /*
154
+ * reads a simple inner statement
155
+ * ```ebnf
156
+ * inner_statement ::= '{' inner_statements '}' | token
157
+ * ```
158
+ */
159
+ read_inner_statement() {
160
+ let attrs = [];
161
+ if (this.token === this.tok.T_ATTRIBUTE) {
162
+ attrs = this.read_attr_list();
163
+ }
164
+ switch (this.token) {
165
+ case this.tok.T_FUNCTION: {
166
+ const result = this.read_function(false, false);
167
+ result.attrGroups = attrs;
168
+ return result;
169
+ }
170
+ // optional flags
171
+ case this.tok.T_ABSTRACT:
172
+ case this.tok.T_FINAL:
173
+ case this.tok.T_CLASS:
174
+ return this.read_class_declaration_statement();
175
+ case this.tok.T_INTERFACE:
176
+ return this.read_interface_declaration_statement();
177
+ case this.tok.T_TRAIT:
178
+ return this.read_trait_declaration_statement();
179
+ case this.tok.T_ENUM:
180
+ return this.read_enum_declaration_statement();
181
+ case this.tok.T_HALT_COMPILER: {
182
+ this.raiseError(
183
+ "__HALT_COMPILER() can only be used from the outermost scope",
184
+ );
185
+ // fallback : returns a node but does not stop the parsing
186
+ let node = this.node("halt");
187
+ this.next().expect("(") && this.next();
188
+ this.expect(")") && this.next();
189
+ node = node(this.lexer._input.substring(this.lexer.offset));
190
+ this.expect(";") && this.next();
191
+ return node;
192
+ }
193
+ default:
194
+ return this.read_statement();
195
+ }
196
+ },
197
+ /*
198
+ * Reads statements
199
+ */
200
+ read_statement() {
201
+ switch (this.token) {
202
+ case "{":
203
+ return this.read_code_block(false);
204
+
205
+ case this.tok.T_IF:
206
+ return this.read_if();
207
+
208
+ case this.tok.T_SWITCH:
209
+ return this.read_switch();
210
+
211
+ case this.tok.T_FOR:
212
+ return this.read_for();
213
+
214
+ case this.tok.T_FOREACH:
215
+ return this.read_foreach();
216
+
217
+ case this.tok.T_WHILE:
218
+ return this.read_while();
219
+
220
+ case this.tok.T_DO:
221
+ return this.read_do();
222
+
223
+ case this.tok.T_COMMENT:
224
+ return this.read_comment();
225
+
226
+ case this.tok.T_DOC_COMMENT:
227
+ return this.read_doc_comment();
228
+
229
+ case this.tok.T_RETURN: {
230
+ const result = this.node("return");
231
+ this.next();
232
+ const expr = this.read_optional_expr(";");
233
+ this.expectEndOfStatement();
234
+ return result(expr);
235
+ }
236
+
237
+ // https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L429
238
+ case this.tok.T_BREAK:
239
+ case this.tok.T_CONTINUE: {
240
+ const result = this.node(
241
+ this.token === this.tok.T_CONTINUE ? "continue" : "break",
242
+ );
243
+ this.next();
244
+ const level = this.read_optional_expr(";");
245
+ this.expectEndOfStatement();
246
+ return result(level);
247
+ }
248
+
249
+ case this.tok.T_GLOBAL: {
250
+ const result = this.node("global");
251
+ const items = this.next().read_list(this.read_simple_variable, ",");
252
+ this.expectEndOfStatement();
253
+ return result(items);
254
+ }
255
+
256
+ case this.tok.T_STATIC: {
257
+ const current = [this.token, this.lexer.getState()];
258
+ const result = this.node();
259
+ if (this.next().token === this.tok.T_DOUBLE_COLON) {
260
+ // static keyword for a class
261
+ this.lexer.tokens.push(current);
262
+ const expr = this.next().read_expr();
263
+ this.expectEndOfStatement(expr);
264
+ return result("expressionstatement", expr);
265
+ }
266
+ if (this.token === this.tok.T_FUNCTION) {
267
+ return this.read_function(true, [0, 1, 0]);
268
+ }
269
+ const items = this.read_variable_declarations();
270
+ this.expectEndOfStatement();
271
+ return result("static", items);
272
+ }
273
+
274
+ case this.tok.T_ECHO: {
275
+ const result = this.node("echo");
276
+ const text = this.text();
277
+ const shortForm = text === "<?=" || text === "<%=";
278
+ const expressions = this.next().read_function_list(this.read_expr, ",");
279
+ this.expectEndOfStatement();
280
+ return result(expressions, shortForm);
281
+ }
282
+
283
+ case this.tok.T_INLINE_HTML: {
284
+ const value = this.text();
285
+ let prevChar =
286
+ this.lexer.yylloc.first_offset > 0
287
+ ? this.lexer._input[this.lexer.yylloc.first_offset - 1]
288
+ : null;
289
+ const fixFirstLine = prevChar === "\r" || prevChar === "\n";
290
+ // revert back the first stripped line
291
+ if (fixFirstLine) {
292
+ if (
293
+ prevChar === "\n" &&
294
+ this.lexer.yylloc.first_offset > 1 &&
295
+ this.lexer._input[this.lexer.yylloc.first_offset - 2] === "\r"
296
+ ) {
297
+ prevChar = "\r\n";
298
+ }
299
+ }
300
+ const result = this.node("inline");
301
+ this.next();
302
+ return result(value, fixFirstLine ? prevChar + value : value);
303
+ }
304
+
305
+ case this.tok.T_UNSET: {
306
+ const result = this.node("unset");
307
+ this.next().expect("(") && this.next();
308
+ const variables = this.read_function_list(this.read_variable, ",");
309
+ this.expect(")") && this.next();
310
+ this.expect(";") && this.next();
311
+ return result(variables);
312
+ }
313
+
314
+ case this.tok.T_DECLARE: {
315
+ const result = this.node("declare");
316
+ const body = [];
317
+ let mode;
318
+ this.next().expect("(") && this.next();
319
+ const directives = this.read_declare_list();
320
+ this.expect(")") && this.next();
321
+ if (this.token === ":") {
322
+ this.next();
323
+ while (
324
+ this.token != this.EOF &&
325
+ this.token !== this.tok.T_ENDDECLARE
326
+ ) {
327
+ // @todo : check declare_statement from php / not valid
328
+ body.push(this.read_top_statement());
329
+ }
330
+ if (
331
+ body.length === 0 &&
332
+ this.extractDoc &&
333
+ this._docs.length > this._docIndex
334
+ ) {
335
+ body.push(this.node("noop")());
336
+ }
337
+ this.expect(this.tok.T_ENDDECLARE) && this.next();
338
+ this.expectEndOfStatement();
339
+ mode = this.ast.declare.MODE_SHORT;
340
+ } else if (this.token === "{") {
341
+ this.next();
342
+ while (this.token != this.EOF && this.token !== "}") {
343
+ // @todo : check declare_statement from php / not valid
344
+ body.push(this.read_top_statement());
345
+ }
346
+ if (
347
+ body.length === 0 &&
348
+ this.extractDoc &&
349
+ this._docs.length > this._docIndex
350
+ ) {
351
+ body.push(this.node("noop")());
352
+ }
353
+ this.expect("}") && this.next();
354
+ mode = this.ast.declare.MODE_BLOCK;
355
+ } else {
356
+ this.expect(";") && this.next();
357
+ mode = this.ast.declare.MODE_NONE;
358
+ }
359
+ return result(directives, body, mode);
360
+ }
361
+
362
+ case this.tok.T_TRY:
363
+ return this.read_try();
364
+
365
+ case this.tok.T_THROW: {
366
+ const result = this.node("throw");
367
+ const expr = this.next().read_expr();
368
+ this.expectEndOfStatement();
369
+ return result(expr);
370
+ }
371
+
372
+ // ignore this (extra ponctuation)
373
+ case ";": {
374
+ this.next();
375
+ return null;
376
+ }
377
+
378
+ case this.tok.T_STRING: {
379
+ const result = this.node();
380
+ const current = [this.token, this.lexer.getState()];
381
+ const labelNameText = this.text();
382
+ let labelName = this.node("identifier");
383
+ // AST : https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L457
384
+ if (this.next().token === ":") {
385
+ labelName = labelName(labelNameText);
386
+ this.next();
387
+ return result("label", labelName);
388
+ } else {
389
+ labelName.destroy();
390
+ }
391
+
392
+ // default fallback expr / T_STRING '::' (etc...)
393
+ result.destroy();
394
+ this.lexer.tokens.push(current);
395
+ const statement = this.node("expressionstatement");
396
+ const expr = this.next().read_expr();
397
+ this.expectEndOfStatement(expr);
398
+ return statement(expr);
399
+ }
400
+
401
+ case this.tok.T_GOTO: {
402
+ const result = this.node("goto");
403
+ let labelName = null;
404
+ if (this.next().expect(this.tok.T_STRING)) {
405
+ labelName = this.node("identifier");
406
+ const name = this.text();
407
+ this.next();
408
+ labelName = labelName(name);
409
+ this.expectEndOfStatement();
410
+ }
411
+ return result(labelName);
412
+ }
413
+
414
+ default: {
415
+ // default fallback expr
416
+ const statement = this.node("expressionstatement");
417
+ const expr = this.read_expr();
418
+ this.expectEndOfStatement(expr);
419
+ return statement(expr);
420
+ }
421
+ }
422
+ },
423
+ /*
424
+ * ```ebnf
425
+ * code_block ::= '{' (inner_statements | top_statements) '}'
426
+ * ```
427
+ */
428
+ read_code_block(top) {
429
+ const result = this.node("block");
430
+ this.expect("{") && this.next();
431
+ const body = top
432
+ ? this.read_top_statements()
433
+ : this.read_inner_statements();
434
+ if (
435
+ body.length === 0 &&
436
+ this.extractDoc &&
437
+ this._docs.length > this._docIndex
438
+ ) {
439
+ body.push(this.node("noop")());
440
+ }
441
+ this.expect("}") && this.next();
442
+ return result(null, body);
443
+ },
444
+ };
@@ -0,0 +1,99 @@
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
+ * Reads a switch statement
11
+ * ```ebnf
12
+ * switch ::= T_SWITCH '(' expr ')' switch_case_list
13
+ * ```
14
+ * @return {Switch}
15
+ * @see http://php.net/manual/en/control-structures.switch.php
16
+ */
17
+ read_switch() {
18
+ const result = this.node("switch");
19
+ this.expect(this.tok.T_SWITCH) && this.next();
20
+ this.expect("(") && this.next();
21
+ const test = this.read_expr();
22
+ this.expect(")") && this.next();
23
+ const shortForm = this.token === ":";
24
+ const body = this.read_switch_case_list();
25
+ return result(test, body, shortForm);
26
+ },
27
+ /*
28
+ * ```ebnf
29
+ * switch_case_list ::= '{' ';'? case_list* '}' | ':' ';'? case_list* T_ENDSWITCH ';'
30
+ * ```
31
+ * @see https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L566
32
+ */
33
+ read_switch_case_list() {
34
+ // DETECT SWITCH MODE
35
+ let expect = null;
36
+ const result = this.node("block");
37
+ const items = [];
38
+ if (this.token === "{") {
39
+ expect = "}";
40
+ } else if (this.token === ":") {
41
+ expect = this.tok.T_ENDSWITCH;
42
+ } else {
43
+ this.expect(["{", ":"]);
44
+ }
45
+ this.next();
46
+ // OPTIONNAL ';'
47
+ // https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L570
48
+ if (this.token === ";") {
49
+ this.next();
50
+ }
51
+ // EXTRACTING CASES
52
+ while (this.token !== this.EOF && this.token !== expect) {
53
+ items.push(this.read_case_list(expect));
54
+ }
55
+ if (
56
+ items.length === 0 &&
57
+ this.extractDoc &&
58
+ this._docs.length > this._docIndex
59
+ ) {
60
+ items.push(this.node("noop")());
61
+ }
62
+ // CHECK END TOKEN
63
+ this.expect(expect) && this.next();
64
+ if (expect === this.tok.T_ENDSWITCH) {
65
+ this.expectEndOfStatement();
66
+ }
67
+ return result(null, items);
68
+ },
69
+ /*
70
+ * ```ebnf
71
+ * case_list ::= ((T_CASE expr) | T_DEFAULT) (':' | ';') inner_statement*
72
+ * ```
73
+ */
74
+ read_case_list(stopToken) {
75
+ const result = this.node("case");
76
+ let test = null;
77
+ if (this.token === this.tok.T_CASE) {
78
+ test = this.next().read_expr();
79
+ } else if (this.token === this.tok.T_DEFAULT) {
80
+ // the default entry - no condition
81
+ this.next();
82
+ } else {
83
+ this.expect([this.tok.T_CASE, this.tok.T_DEFAULT]);
84
+ }
85
+ // case_separator
86
+ this.expect([":", ";"]) && this.next();
87
+ const body = this.node("block");
88
+ const items = [];
89
+ while (
90
+ this.token !== this.EOF &&
91
+ this.token !== stopToken &&
92
+ this.token !== this.tok.T_CASE &&
93
+ this.token !== this.tok.T_DEFAULT
94
+ ) {
95
+ items.push(this.read_inner_statement());
96
+ }
97
+ return result(test, body(null, items));
98
+ },
99
+ };
@@ -0,0 +1,43 @@
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
+ * ```ebnf
11
+ * try ::= T_TRY '{' inner_statement* '}'
12
+ * (
13
+ * T_CATCH '(' namespace_name (variable)? ')' '{' inner_statement* '}'
14
+ * )*
15
+ * (T_FINALLY '{' inner_statement* '}')?
16
+ * ```
17
+ * @see https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L448
18
+ * @return {Try}
19
+ */
20
+ read_try() {
21
+ this.expect(this.tok.T_TRY);
22
+ const result = this.node("try");
23
+ let always = null;
24
+ const catches = [];
25
+ const body = this.next().read_statement();
26
+ // https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L455
27
+ while (this.token === this.tok.T_CATCH) {
28
+ const item = this.node("catch");
29
+ this.next().expect("(") && this.next();
30
+ const what = this.read_list(this.read_namespace_name, "|", false);
31
+ let variable = null;
32
+ if (this.version < 800 || this.token === this.tok.T_VARIABLE) {
33
+ variable = this.read_variable(true, false);
34
+ }
35
+ this.expect(")");
36
+ catches.push(item(this.next().read_statement(), what, variable));
37
+ }
38
+ if (this.token === this.tok.T_FINALLY) {
39
+ always = this.next().read_statement();
40
+ }
41
+ return result(body, catches, always);
42
+ },
43
+ };