Skip to content

Commit 66a3c38

Browse files
authored
Merge pull request glayzzle#506 from jodysimpson/FIX-flexible-heredoc
Added fixes for new flexible heredoc from php7.3
2 parents 7938988 + 0ee6acc commit 66a3c38

File tree

5 files changed

+1604
-83
lines changed

5 files changed

+1604
-83
lines changed

src/lexer.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ lexer.prototype.setInput = function(input) {
164164
length: 0,
165165
indentation: 0,
166166
indentation_uses_spaces: false,
167+
finished: false,
167168
/**
168169
* this used for parser to detemine the if current node segment is first encaps node.
169170
* if ture, the indentation will remove from the begining. and if false, the prev node

src/lexer/strings.js

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,19 @@
55
*/
66
"use strict";
77

8+
const newline = ["\n", "\r"];
9+
const valid_after_heredoc = ["\n", "\r", ";"];
10+
const valid_after_heredoc_73 = valid_after_heredoc.concat([
11+
"\t",
12+
" ",
13+
",",
14+
"]",
15+
")",
16+
"/",
17+
"=",
18+
"!"
19+
]);
20+
821
module.exports = {
922
T_CONSTANT_ENCAPSED_STRING: function() {
1023
let ch;
@@ -60,13 +73,11 @@ module.exports = {
6073
// required ending quote
6174
if (tChar) this.offset++;
6275
// require newline
63-
if (
64-
this._input[this.offset - 1] === "\r" ||
65-
this._input[this.offset - 1] === "\n"
66-
) {
76+
if (newline.includes(this._input[this.offset - 1])) {
6777
// go go go
6878
this.heredoc_label.label = yylabel;
6979
this.heredoc_label.length = yylabel.length;
80+
this.heredoc_label.finished = false;
7081
yyoffset = this.offset - revert;
7182
this.offset = revert;
7283
this.consume(yyoffset);
@@ -135,8 +146,8 @@ module.exports = {
135146
// consumeLeadingSpaces is false happen DOC prematch END HEREDOC stage.
136147

137148
// Ensure current state is really after a new line break, not after a such as ${variables}
138-
const prev_ch = this._input.substring(offset - 2, offset - 1);
139-
if (prev_ch !== "\n" && prev_ch !== "\r") {
149+
const prev_ch = this._input[offset - 2];
150+
if (!newline.includes(prev_ch)) {
140151
return false;
141152
}
142153

@@ -145,21 +156,28 @@ module.exports = {
145156
let indentation_uses_tabs = false;
146157
// reset heredoc_label structure
147158
let indentation = 0;
148-
let leading_ch = this._input.substring(offset - 1, offset);
159+
let leading_ch = this._input[offset - 1];
160+
161+
if (this.version >= 703) {
162+
while (leading_ch === "\t" || leading_ch === " ") {
163+
if (leading_ch === " ") {
164+
indentation_uses_spaces = true;
165+
} else if (leading_ch === "\t") {
166+
indentation_uses_tabs = true;
167+
}
149168

150-
while (leading_ch === "\t" || leading_ch === " ") {
151-
if (leading_ch === " ") {
152-
indentation_uses_spaces = true;
153-
} else if (leading_ch === "\t") {
154-
indentation_uses_tabs = true;
169+
leading_ch = this._input[offset + indentation];
170+
indentation++;
155171
}
156172

157-
leading_ch = this._input[offset + indentation];
158-
indentation++;
159-
}
173+
// Move offset to skip leading whitespace
174+
offset = offset + indentation;
160175

161-
// Move offset to skip leading whitespace
162-
offset = offset + indentation;
176+
// return out if there was only whitespace on this line
177+
if (newline.includes(this._input[offset - 1])) {
178+
return false;
179+
}
180+
}
163181

164182
if (
165183
this._input.substring(
@@ -168,7 +186,12 @@ module.exports = {
168186
) === this.heredoc_label.label
169187
) {
170188
const ch = this._input[offset - 1 + this.heredoc_label.length];
171-
if (ch === "\n" || ch === "\r" || ch === ";") {
189+
if (
190+
(this.version >= 703
191+
? valid_after_heredoc_73
192+
: valid_after_heredoc
193+
).includes(ch)
194+
) {
172195
if (consumeLeadingSpaces) {
173196
this.consume(indentation);
174197
// https://wiki.php.net/rfc/flexible_heredoc_nowdoc_syntaxes
@@ -211,9 +234,14 @@ module.exports = {
211234
return;
212235
}
213236

214-
// skip one line
215-
while (this._input[offset++] !== "\n" && offset < this._input.length) {
216-
// skip
237+
if (!newline.includes(this._input[offset - 1])) {
238+
// skip one line
239+
while (
240+
!newline.includes(this._input[offset++]) &&
241+
offset < this._input.length
242+
) {
243+
// skip
244+
}
217245
}
218246

219247
offset++;
@@ -231,7 +259,7 @@ module.exports = {
231259
/** SCANNING CONTENTS **/
232260
let ch = this._input[this.offset - 1];
233261
while (this.offset < this.size) {
234-
if (ch === "\n" || ch === "\r") {
262+
if (newline.includes(ch)) {
235263
ch = this.input();
236264
if (this.isDOC_MATCH(this.offset, true)) {
237265
this.unput(1).popState();
@@ -258,12 +286,12 @@ module.exports = {
258286
while (this.offset < this.size) {
259287
if (ch === "\\") {
260288
ch = this.input(); // ignore next
261-
if (ch !== "\n" && ch !== "\r") {
289+
if (!newline.includes(ch)) {
262290
ch = this.input();
263291
}
264292
}
265293

266-
if (ch === "\n" || ch === "\r") {
294+
if (newline.includes(ch)) {
267295
ch = this.input();
268296
if (this.isDOC_MATCH(this.offset, true)) {
269297
this.unput(1).popState();

src/parser/scalar.js

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,11 @@ module.exports = {
128128
inCoutingState = false;
129129
}
130130

131-
if (inCheckState && leadingWhitespaceCharCount < indentation) {
131+
if (
132+
text[offset] !== "\n" &&
133+
inCheckState &&
134+
leadingWhitespaceCharCount < indentation
135+
) {
132136
this.raiseError(
133137
`Invalid body indentation level (expecting an indentation at least ${indentation})`
134138
);
@@ -335,12 +339,14 @@ module.exports = {
335339
result = result(
336340
"string",
337341
false,
338-
this.remove_heredoc_leading_whitespace_chars(
339-
this.resolve_special_chars(text, isDoubleQuote),
340-
this.lexer.heredoc_label.indentation,
341-
this.lexer.heredoc_label.indentation_uses_spaces,
342-
this.lexer.heredoc_label.first_encaps_node
343-
),
342+
this.version >= 703 && !this.lexer.heredoc_label.finished
343+
? this.remove_heredoc_leading_whitespace_chars(
344+
this.resolve_special_chars(text, isDoubleQuote),
345+
this.lexer.heredoc_label.indentation,
346+
this.lexer.heredoc_label.indentation_uses_spaces,
347+
this.lexer.heredoc_label.first_encaps_node
348+
)
349+
: text,
344350
false,
345351
text
346352
);
@@ -467,6 +473,7 @@ module.exports = {
467473

468474
if (expect === this.tok.T_END_HEREDOC) {
469475
node.label = this.lexer.heredoc_label.label;
476+
this.lexer.heredoc_label.finished = true;
470477
}
471478
return node;
472479
},

0 commit comments

Comments
 (0)