@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,492 @@
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 specialChar = {
9
+ "\\": "\\",
10
+ $: "$",
11
+ n: "\n",
12
+ r: "\r",
13
+ t: "\t",
14
+ f: String.fromCharCode(12),
15
+ v: String.fromCharCode(11),
16
+ e: String.fromCharCode(27),
17
+ };
18
+
19
+ module.exports = {
20
+ /*
21
+ * Unescape special chars
22
+ */
23
+ resolve_special_chars(text, doubleQuote) {
24
+ if (!doubleQuote) {
25
+ // single quote fix
26
+ return text.replace(/\\\\/g, "\\").replace(/\\'/g, "'");
27
+ }
28
+ return text
29
+ .replace(/\\"/, '"')
30
+ .replace(
31
+ /\\([\\$nrtfve]|[xX][0-9a-fA-F]{1,2}|[0-7]{1,3}|u{([0-9a-fA-F]+)})/g,
32
+ ($match, p1, p2) => {
33
+ if (specialChar[p1]) {
34
+ return specialChar[p1];
35
+ } else if ("x" === p1[0] || "X" === p1[0]) {
36
+ return String.fromCodePoint(parseInt(p1.substr(1), 16));
37
+ } else if ("u" === p1[0]) {
38
+ return String.fromCodePoint(parseInt(p2, 16));
39
+ } else {
40
+ return String.fromCodePoint(parseInt(p1, 8));
41
+ }
42
+ },
43
+ );
44
+ },
45
+
46
+ /*
47
+ * Remove all leading spaces each line for heredoc text if there is a indentation
48
+ * @param {string} text
49
+ * @param {number} indentation
50
+ * @param {boolean} indentation_uses_spaces
51
+ * @param {boolean} first_encaps_node if it is behind a variable, the first N spaces should not be removed
52
+ */
53
+ remove_heredoc_leading_whitespace_chars(
54
+ text,
55
+ indentation,
56
+ indentation_uses_spaces,
57
+ first_encaps_node,
58
+ ) {
59
+ if (indentation === 0) {
60
+ return text;
61
+ }
62
+
63
+ this.check_heredoc_indentation_level(
64
+ text,
65
+ indentation,
66
+ indentation_uses_spaces,
67
+ first_encaps_node,
68
+ );
69
+
70
+ const matchedChar = indentation_uses_spaces ? " " : "\t";
71
+ const removementRegExp = new RegExp(
72
+ `\\n${matchedChar}{${indentation}}`,
73
+ "g",
74
+ );
75
+ const removementFirstEncapsNodeRegExp = new RegExp(
76
+ `^${matchedChar}{${indentation}}`,
77
+ );
78
+
79
+ // Rough replace, need more check
80
+ if (first_encaps_node) {
81
+ // Remove text leading whitespace
82
+ text = text.replace(removementFirstEncapsNodeRegExp, "");
83
+ }
84
+
85
+ // Remove leading whitespace after \n
86
+ return text.replace(removementRegExp, "\n");
87
+ },
88
+
89
+ /*
90
+ * Check indentation level of heredoc in text, if mismatch, raiseError
91
+ * @param {string} text
92
+ * @param {number} indentation
93
+ * @param {boolean} indentation_uses_spaces
94
+ * @param {boolean} first_encaps_node if it is behind a variable, the first N spaces should not be removed
95
+ */
96
+ check_heredoc_indentation_level(
97
+ text,
98
+ indentation,
99
+ indentation_uses_spaces,
100
+ first_encaps_node,
101
+ ) {
102
+ const textSize = text.length;
103
+ let offset = 0;
104
+ let leadingWhitespaceCharCount = 0;
105
+ /*
106
+ * @var inCoutingState {boolean} reset to true after a new line
107
+ * @private
108
+ */
109
+ let inCoutingState = true;
110
+ const chToCheck = indentation_uses_spaces ? " " : "\t";
111
+ let inCheckState = false;
112
+ if (!first_encaps_node) {
113
+ // start from first \n
114
+ offset = text.indexOf("\n");
115
+ // if no \n, just return
116
+ if (offset === -1) {
117
+ return;
118
+ }
119
+ offset++;
120
+ }
121
+ while (offset < textSize) {
122
+ if (inCoutingState) {
123
+ if (text[offset] === chToCheck) {
124
+ leadingWhitespaceCharCount++;
125
+ } else {
126
+ inCheckState = true;
127
+ }
128
+ } else {
129
+ inCoutingState = false;
130
+ }
131
+
132
+ if (
133
+ text[offset] !== "\n" &&
134
+ inCheckState &&
135
+ leadingWhitespaceCharCount < indentation
136
+ ) {
137
+ this.raiseError(
138
+ `Invalid body indentation level (expecting an indentation at least ${indentation})`,
139
+ );
140
+ } else {
141
+ inCheckState = false;
142
+ }
143
+
144
+ if (text[offset] === "\n") {
145
+ // Reset counting state
146
+ inCoutingState = true;
147
+ leadingWhitespaceCharCount = 0;
148
+ }
149
+ offset++;
150
+ }
151
+ },
152
+
153
+ /*
154
+ * Reads dereferencable scalar
155
+ */
156
+ read_dereferencable_scalar() {
157
+ let result = null;
158
+
159
+ switch (this.token) {
160
+ case this.tok.T_CONSTANT_ENCAPSED_STRING:
161
+ {
162
+ let value = this.node("string");
163
+ const text = this.text();
164
+ let offset = 0;
165
+ if (text[0] === "b" || text[0] === "B") {
166
+ offset = 1;
167
+ }
168
+ const isDoubleQuote = text[offset] === '"';
169
+ this.next();
170
+ const textValue = this.resolve_special_chars(
171
+ text.substring(offset + 1, text.length - 1),
172
+ isDoubleQuote,
173
+ );
174
+ value = value(
175
+ isDoubleQuote,
176
+ textValue,
177
+ offset === 1, // unicode flag
178
+ text,
179
+ );
180
+ if (this.token === this.tok.T_DOUBLE_COLON) {
181
+ // https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L1151
182
+ result = this.read_static_getter(value);
183
+ } else {
184
+ // dirrect string
185
+ result = value;
186
+ }
187
+ }
188
+ break;
189
+ case this.tok.T_ARRAY: // array parser
190
+ result = this.read_array();
191
+ break;
192
+ case "[": // short array format
193
+ result = this.read_array();
194
+ break;
195
+ }
196
+
197
+ return result;
198
+ },
199
+
200
+ /*
201
+ * ```ebnf
202
+ * scalar ::= T_MAGIC_CONST
203
+ * | T_LNUMBER | T_DNUMBER
204
+ * | T_START_HEREDOC T_ENCAPSED_AND_WHITESPACE? T_END_HEREDOC
205
+ * | '"' encaps_list '"'
206
+ * | T_START_HEREDOC encaps_list T_END_HEREDOC
207
+ * | namespace_name (T_DOUBLE_COLON T_STRING)?
208
+ * ```
209
+ */
210
+ read_scalar() {
211
+ if (this.is("T_MAGIC_CONST")) {
212
+ return this.get_magic_constant();
213
+ } else {
214
+ let value, node;
215
+ switch (this.token) {
216
+ // NUMERIC
217
+ case this.tok.T_LNUMBER: // long
218
+ case this.tok.T_DNUMBER: {
219
+ // double
220
+ const result = this.node("number");
221
+ value = this.text();
222
+ this.next();
223
+ return result(value, null);
224
+ }
225
+ case this.tok.T_START_HEREDOC:
226
+ if (this.lexer.curCondition === "ST_NOWDOC") {
227
+ const start = this.lexer.yylloc.first_offset;
228
+ node = this.node("nowdoc");
229
+ value = this.next().text();
230
+ // strip the last line return char
231
+ if (this.lexer.heredoc_label.indentation > 0) {
232
+ value = value.substring(
233
+ 0,
234
+ value.length - this.lexer.heredoc_label.indentation,
235
+ );
236
+ }
237
+ const lastCh = value[value.length - 1];
238
+ if (lastCh === "\n") {
239
+ if (value[value.length - 2] === "\r") {
240
+ // windows style
241
+ value = value.substring(0, value.length - 2);
242
+ } else {
243
+ // linux style
244
+ value = value.substring(0, value.length - 1);
245
+ }
246
+ } else if (lastCh === "\r") {
247
+ // mac style
248
+ value = value.substring(0, value.length - 1);
249
+ }
250
+ this.expect(this.tok.T_ENCAPSED_AND_WHITESPACE) && this.next();
251
+ this.expect(this.tok.T_END_HEREDOC) && this.next();
252
+ const raw = this.lexer._input.substring(
253
+ start,
254
+ this.lexer.yylloc.first_offset,
255
+ );
256
+ node = node(
257
+ this.remove_heredoc_leading_whitespace_chars(
258
+ value,
259
+ this.lexer.heredoc_label.indentation,
260
+ this.lexer.heredoc_label.indentation_uses_spaces,
261
+ this.lexer.heredoc_label.first_encaps_node,
262
+ ),
263
+ raw,
264
+ this.lexer.heredoc_label.label,
265
+ );
266
+ this.lexer.heredoc_label.finished = true;
267
+ return node;
268
+ } else {
269
+ return this.read_encapsed_string(this.tok.T_END_HEREDOC);
270
+ }
271
+
272
+ case '"':
273
+ return this.read_encapsed_string('"');
274
+
275
+ case 'b"':
276
+ case 'B"': {
277
+ return this.read_encapsed_string('"', true);
278
+ }
279
+
280
+ // TEXTS
281
+ case this.tok.T_CONSTANT_ENCAPSED_STRING:
282
+ case this.tok.T_ARRAY: // array parser
283
+ case "[": // short array format
284
+ return this.read_dereferencable_scalar();
285
+ default: {
286
+ const err = this.error("SCALAR");
287
+ // graceful mode : ignore token & return error node
288
+ this.next();
289
+ return err;
290
+ }
291
+ }
292
+ }
293
+ },
294
+ /*
295
+ * Handles the dereferencing
296
+ */
297
+ read_dereferencable(expr) {
298
+ let result, offset;
299
+ const node = this.node("offsetlookup");
300
+ if (this.token === "[") {
301
+ offset = this.next().read_expr();
302
+ if (this.expect("]")) this.next();
303
+ result = node(expr, offset);
304
+ } else if (this.token === this.tok.T_DOLLAR_OPEN_CURLY_BRACES) {
305
+ offset = this.read_encapsed_string_item(false);
306
+ result = node(expr, offset);
307
+ }
308
+ return result;
309
+ },
310
+ /*
311
+ * Reads and extracts an encapsed item
312
+ * ```ebnf
313
+ * encapsed_string_item ::= T_ENCAPSED_AND_WHITESPACE
314
+ * | T_DOLLAR_OPEN_CURLY_BRACES expr '}'
315
+ * | T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '}'
316
+ * | T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '[' expr ']' '}'
317
+ * | T_CURLY_OPEN variable '}'
318
+ * | variable
319
+ * | variable '[' expr ']'
320
+ * | variable T_OBJECT_OPERATOR T_STRING
321
+ * ```
322
+ * @return {String|Variable|Expr|Lookup}
323
+ * @see https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L1219
324
+ */
325
+ read_encapsed_string_item(isDoubleQuote) {
326
+ const encapsedPart = this.node("encapsedpart");
327
+ let syntax = null;
328
+ let curly = false;
329
+ let result = this.node(),
330
+ offset,
331
+ node,
332
+ name;
333
+
334
+ // plain text
335
+ // https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L1222
336
+ if (this.token === this.tok.T_ENCAPSED_AND_WHITESPACE) {
337
+ const text = this.text();
338
+ this.next();
339
+
340
+ // if this.lexer.heredoc_label.first_encaps_node -> remove first indents
341
+ result = result(
342
+ "string",
343
+ false,
344
+ this.version >= 703 && !this.lexer.heredoc_label.finished
345
+ ? this.remove_heredoc_leading_whitespace_chars(
346
+ this.resolve_special_chars(text, isDoubleQuote),
347
+ this.lexer.heredoc_label.indentation,
348
+ this.lexer.heredoc_label.indentation_uses_spaces,
349
+ this.lexer.heredoc_label.first_encaps_node,
350
+ )
351
+ : text,
352
+ false,
353
+ text,
354
+ );
355
+ } else if (this.token === this.tok.T_DOLLAR_OPEN_CURLY_BRACES) {
356
+ syntax = "simple";
357
+ curly = true;
358
+ // dynamic variable name
359
+ // https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L1239
360
+ name = null;
361
+ if (this.next().token === this.tok.T_STRING_VARNAME) {
362
+ name = this.node("variable");
363
+ const varName = this.text();
364
+ this.next();
365
+ // check if lookup an offset
366
+ // https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L1243
367
+ result.destroy();
368
+ if (this.token === "[") {
369
+ name = name(varName, false);
370
+ node = this.node("offsetlookup");
371
+ offset = this.next().read_expr();
372
+ this.expect("]") && this.next();
373
+ result = node(name, offset);
374
+ } else {
375
+ result = name(varName, false);
376
+ }
377
+ } else {
378
+ result = result("variable", this.read_expr(), false);
379
+ }
380
+ this.expect("}") && this.next();
381
+ } else if (this.token === this.tok.T_CURLY_OPEN) {
382
+ // expression
383
+ // https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L1246
384
+ syntax = "complex";
385
+ result.destroy();
386
+ result = this.next().read_variable(false, false);
387
+ this.expect("}") && this.next();
388
+ } else if (this.token === this.tok.T_VARIABLE) {
389
+ syntax = "simple";
390
+ // plain variable
391
+ // https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L1231
392
+ result.destroy();
393
+ result = this.read_simple_variable();
394
+
395
+ // https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L1233
396
+ if (this.token === "[") {
397
+ node = this.node("offsetlookup");
398
+ offset = this.next().read_encaps_var_offset();
399
+ this.expect("]") && this.next();
400
+ result = node(result, offset);
401
+ }
402
+
403
+ // https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L1236
404
+ if (this.token === this.tok.T_OBJECT_OPERATOR) {
405
+ node = this.node("propertylookup");
406
+ this.next().expect(this.tok.T_STRING);
407
+ const what = this.node("identifier");
408
+ name = this.text();
409
+ this.next();
410
+ result = node(result, what(name));
411
+ }
412
+
413
+ // error / fallback
414
+ } else {
415
+ this.expect(this.tok.T_ENCAPSED_AND_WHITESPACE);
416
+ const value = this.text();
417
+ this.next();
418
+ // consider it as string
419
+ result.destroy();
420
+ result = result("string", false, value, false, value);
421
+ }
422
+
423
+ // reset first_encaps_node to false after access any node
424
+ this.lexer.heredoc_label.first_encaps_node = false;
425
+ return encapsedPart(result, syntax, curly);
426
+ },
427
+ /*
428
+ * Reads an encapsed string
429
+ */
430
+ read_encapsed_string(expect, isBinary = false) {
431
+ const labelStart = this.lexer.yylloc.first_offset;
432
+ let node = this.node("encapsed");
433
+ this.next();
434
+ const start = this.lexer.yylloc.prev_offset - (isBinary ? 1 : 0);
435
+ const value = [];
436
+ let type = null;
437
+
438
+ if (expect === "`") {
439
+ type = this.ast.encapsed.TYPE_SHELL;
440
+ } else if (expect === '"') {
441
+ type = this.ast.encapsed.TYPE_STRING;
442
+ } else {
443
+ type = this.ast.encapsed.TYPE_HEREDOC;
444
+ }
445
+
446
+ // reading encapsed parts
447
+ while (this.token !== expect && this.token !== this.EOF) {
448
+ value.push(this.read_encapsed_string_item(true));
449
+ }
450
+ if (
451
+ value.length > 0 &&
452
+ value[value.length - 1].kind === "encapsedpart" &&
453
+ value[value.length - 1].expression.kind === "string"
454
+ ) {
455
+ const node = value[value.length - 1].expression;
456
+ const lastCh = node.value[node.value.length - 1];
457
+ if (lastCh === "\n") {
458
+ if (node.value[node.value.length - 2] === "\r") {
459
+ // windows style
460
+ node.value = node.value.substring(0, node.value.length - 2);
461
+ } else {
462
+ // linux style
463
+ node.value = node.value.substring(0, node.value.length - 1);
464
+ }
465
+ } else if (lastCh === "\r") {
466
+ // mac style
467
+ node.value = node.value.substring(0, node.value.length - 1);
468
+ }
469
+ }
470
+ this.expect(expect) && this.next();
471
+ const raw = this.lexer._input.substring(
472
+ type === "heredoc" ? labelStart : start - 1,
473
+ this.lexer.yylloc.first_offset,
474
+ );
475
+ node = node(value, raw, type);
476
+
477
+ if (expect === this.tok.T_END_HEREDOC) {
478
+ node.label = this.lexer.heredoc_label.label;
479
+ this.lexer.heredoc_label.finished = true;
480
+ }
481
+ return node;
482
+ },
483
+ /*
484
+ * Constant token
485
+ */
486
+ get_magic_constant() {
487
+ const result = this.node("magic");
488
+ const name = this.text();
489
+ this.next();
490
+ return result(name.toUpperCase(), name);
491
+ },
492
+ };