@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.
- package/LICENSE +27 -0
- package/README.md +108 -0
- package/dist/@jorgsowa/php-parser.js +11239 -0
- package/dist/@jorgsowa/php-parser.min.js +2 -0
- package/dist/@jorgsowa/php-parser.min.js.LICENSE.txt +10 -0
- package/package.json +86 -0
- package/src/ast/array.js +44 -0
- package/src/ast/arrowfunc.js +43 -0
- package/src/ast/assign.js +28 -0
- package/src/ast/assignref.js +27 -0
- package/src/ast/attrgroup.js +21 -0
- package/src/ast/attribute.js +26 -0
- package/src/ast/bin.js +27 -0
- package/src/ast/block.js +24 -0
- package/src/ast/boolean.js +23 -0
- package/src/ast/break.js +21 -0
- package/src/ast/byref.js +21 -0
- package/src/ast/call.js +26 -0
- package/src/ast/case.js +26 -0
- package/src/ast/cast.js +28 -0
- package/src/ast/catch.js +29 -0
- package/src/ast/class.js +36 -0
- package/src/ast/classconstant.js +71 -0
- package/src/ast/clone.js +21 -0
- package/src/ast/closure.js +47 -0
- package/src/ast/comment.js +23 -0
- package/src/ast/commentblock.js +22 -0
- package/src/ast/commentline.js +22 -0
- package/src/ast/constant.js +26 -0
- package/src/ast/constantstatement.js +24 -0
- package/src/ast/continue.js +24 -0
- package/src/ast/declaration.js +60 -0
- package/src/ast/declare.js +71 -0
- package/src/ast/declaredirective.js +26 -0
- package/src/ast/do.js +26 -0
- package/src/ast/echo.js +26 -0
- package/src/ast/empty.js +23 -0
- package/src/ast/encapsed.js +75 -0
- package/src/ast/encapsedpart.js +28 -0
- package/src/ast/entry.js +30 -0
- package/src/ast/enum.js +30 -0
- package/src/ast/enumcase.js +26 -0
- package/src/ast/error.js +30 -0
- package/src/ast/eval.js +24 -0
- package/src/ast/exit.js +26 -0
- package/src/ast/expression.js +20 -0
- package/src/ast/expressionstatement.js +24 -0
- package/src/ast/for.js +33 -0
- package/src/ast/foreach.js +33 -0
- package/src/ast/function.js +34 -0
- package/src/ast/global.js +24 -0
- package/src/ast/goto.js +22 -0
- package/src/ast/halt.js +22 -0
- package/src/ast/identifier.js +26 -0
- package/src/ast/if.js +30 -0
- package/src/ast/include.js +28 -0
- package/src/ast/inline.js +23 -0
- package/src/ast/interface.js +28 -0
- package/src/ast/intersectiontype.js +24 -0
- package/src/ast/isset.js +23 -0
- package/src/ast/label.js +21 -0
- package/src/ast/list.js +26 -0
- package/src/ast/literal.js +28 -0
- package/src/ast/location.js +22 -0
- package/src/ast/lookup.js +26 -0
- package/src/ast/magic.js +22 -0
- package/src/ast/match.js +26 -0
- package/src/ast/matcharm.js +26 -0
- package/src/ast/method.js +24 -0
- package/src/ast/name.js +55 -0
- package/src/ast/namedargument.js +27 -0
- package/src/ast/namespace.js +26 -0
- package/src/ast/new.js +26 -0
- package/src/ast/node.js +111 -0
- package/src/ast/noop.js +20 -0
- package/src/ast/nowdoc.js +26 -0
- package/src/ast/nullkeyword.js +20 -0
- package/src/ast/nullsafepropertylookup.js +22 -0
- package/src/ast/number.js +23 -0
- package/src/ast/offsetlookup.js +22 -0
- package/src/ast/operation.js +19 -0
- package/src/ast/parameter.js +61 -0
- package/src/ast/parentreference.js +24 -0
- package/src/ast/position.js +22 -0
- package/src/ast/post.js +26 -0
- package/src/ast/pre.js +26 -0
- package/src/ast/print.js +23 -0
- package/src/ast/program.js +32 -0
- package/src/ast/property.js +46 -0
- package/src/ast/propertyhook.js +33 -0
- package/src/ast/propertylookup.js +22 -0
- package/src/ast/propertystatement.js +59 -0
- package/src/ast/reference.js +21 -0
- package/src/ast/retif.js +28 -0
- package/src/ast/return.js +21 -0
- package/src/ast/selfreference.js +24 -0
- package/src/ast/silent.js +24 -0
- package/src/ast/statement.js +19 -0
- package/src/ast/static.js +24 -0
- package/src/ast/staticlookup.js +22 -0
- package/src/ast/staticreference.js +24 -0
- package/src/ast/staticvariable.js +26 -0
- package/src/ast/string.js +28 -0
- package/src/ast/switch.js +28 -0
- package/src/ast/throw.js +21 -0
- package/src/ast/trait.js +24 -0
- package/src/ast/traitalias.js +44 -0
- package/src/ast/traitprecedence.js +28 -0
- package/src/ast/traituse.js +26 -0
- package/src/ast/try.js +28 -0
- package/src/ast/typereference.js +40 -0
- package/src/ast/unary.js +26 -0
- package/src/ast/uniontype.js +24 -0
- package/src/ast/unset.js +23 -0
- package/src/ast/usegroup.js +30 -0
- package/src/ast/useitem.js +45 -0
- package/src/ast/variable.js +36 -0
- package/src/ast/variadic.js +25 -0
- package/src/ast/variadicplaceholder.js +24 -0
- package/src/ast/while.js +28 -0
- package/src/ast/yield.js +27 -0
- package/src/ast/yieldfrom.js +25 -0
- package/src/ast.js +593 -0
- package/src/index.js +239 -0
- package/src/lexer/attribute.js +85 -0
- package/src/lexer/comments.js +63 -0
- package/src/lexer/initial.js +64 -0
- package/src/lexer/numbers.js +171 -0
- package/src/lexer/property.js +96 -0
- package/src/lexer/scripting.js +114 -0
- package/src/lexer/strings.js +524 -0
- package/src/lexer/tokens.js +356 -0
- package/src/lexer/utils.js +112 -0
- package/src/lexer.js +561 -0
- package/src/parser/array.js +113 -0
- package/src/parser/class.js +718 -0
- package/src/parser/comment.js +52 -0
- package/src/parser/enum.js +56 -0
- package/src/parser/expr.js +848 -0
- package/src/parser/function.js +507 -0
- package/src/parser/if.js +94 -0
- package/src/parser/loops.js +168 -0
- package/src/parser/main.js +21 -0
- package/src/parser/namespace.js +231 -0
- package/src/parser/scalar.js +492 -0
- package/src/parser/statement.js +444 -0
- package/src/parser/switch.js +99 -0
- package/src/parser/try.js +43 -0
- package/src/parser/utils.js +203 -0
- package/src/parser/variable.js +363 -0
- package/src/parser.js +748 -0
- package/src/tokens.js +177 -0
- 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
|
+
};
|