Skip to content

Commit fea57ba

Browse files
evilebottnawialexander-akait
authored andcommitted
refactor: read_optional_expr (#405)
1 parent f5f023b commit fea57ba

File tree

8 files changed

+146
-50
lines changed

8 files changed

+146
-50
lines changed

src/parser/expr.js

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,32 @@ module.exports = {
192192
return result;
193193
},
194194

195+
/**
196+
* Reads optional expression
197+
*/
198+
read_optional_expr: function(stopToken) {
199+
if (this.token !== stopToken) {
200+
return this.read_expr();
201+
}
202+
203+
return null;
204+
},
205+
206+
/**
207+
* Reads exit expression
208+
*/
209+
read_exit_expr: function() {
210+
let expression = null;
211+
212+
if (this.token === "(") {
213+
this.next();
214+
expression = this.read_optional_expr(')');
215+
this.expect(')') && this.next();
216+
}
217+
218+
return expression;
219+
},
220+
195221
/**
196222
* ```ebnf
197223
* Reads an expression
@@ -320,17 +346,8 @@ module.exports = {
320346
case this.tok.T_EXIT: {
321347
const useDie = this.lexer.yytext.toLowerCase() === "die";
322348
result = this.node("exit");
323-
let expression = null;
324-
if (this.next().token === "(") {
325-
if (this.next().token !== ")") {
326-
expression = this.read_expr();
327-
if (this.expect(")")) {
328-
this.next();
329-
}
330-
} else {
331-
this.next();
332-
}
333-
}
349+
this.next();
350+
const expression = this.read_exit_expr();
334351
return result(expression, useDie);
335352
}
336353

src/parser/statement.js

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -212,10 +212,8 @@ module.exports = {
212212

213213
case this.tok.T_RETURN: {
214214
const result = this.node("return");
215-
let expr = null;
216-
if (!this.next().is("EOS")) {
217-
expr = this.read_expr();
218-
}
215+
this.next();
216+
const expr = this.read_optional_expr(';');
219217
this.expectEndOfStatement();
220218
return result(expr);
221219
}
@@ -226,11 +224,8 @@ module.exports = {
226224
const result = this.node(
227225
this.token === this.tok.T_CONTINUE ? "continue" : "break"
228226
);
229-
let level = null;
230-
this.next(); // look ahead
231-
if (this.token !== ";") {
232-
level = this.read_expr();
233-
}
227+
this.next();
228+
const level = this.read_optional_expr(';');
234229
this.expectEndOfStatement();
235230
return result(level);
236231
}

test/snapshot/__snapshots__/break.test.js.snap

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,27 @@ Program {
4848
}
4949
`;
5050

51+
exports[`break should fail when no ';' at end 1`] = `
52+
Program {
53+
"children": Array [
54+
Break {
55+
"kind": "break",
56+
"level": undefined,
57+
},
58+
],
59+
"errors": Array [
60+
Error {
61+
"expected": "EXPR",
62+
"kind": "error",
63+
"line": 1,
64+
"message": "Parse Error : syntax error on line 1",
65+
"token": "the end of file (EOF)",
66+
},
67+
],
68+
"kind": "program",
69+
}
70+
`;
71+
5172
exports[`break simple 1`] = `
5273
Program {
5374
"children": Array [

test/snapshot/__snapshots__/continue.test.js.snap

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,27 @@ Program {
4848
}
4949
`;
5050

51+
exports[`continue should fail when no ';' at end 1`] = `
52+
Program {
53+
"children": Array [
54+
Continue {
55+
"kind": "continue",
56+
"level": undefined,
57+
},
58+
],
59+
"errors": Array [
60+
Error {
61+
"expected": "EXPR",
62+
"kind": "error",
63+
"line": 1,
64+
"message": "Parse Error : syntax error on line 1",
65+
"token": "the end of file (EOF)",
66+
},
67+
],
68+
"kind": "program",
69+
}
70+
`;
71+
5172
exports[`continue simple 1`] = `
5273
Program {
5374
"children": Array [

test/snapshot/__snapshots__/return.test.js.snap

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,27 @@ Program {
1313
}
1414
`;
1515

16+
exports[`return should fail when no ';' at end 1`] = `
17+
Program {
18+
"children": Array [
19+
Return {
20+
"expr": undefined,
21+
"kind": "return",
22+
},
23+
],
24+
"errors": Array [
25+
Error {
26+
"expected": "EXPR",
27+
"kind": "error",
28+
"line": 1,
29+
"message": "Parse Error : syntax error on line 1",
30+
"token": "the end of file (EOF)",
31+
},
32+
],
33+
"kind": "program",
34+
}
35+
`;
36+
1637
exports[`return simple 1`] = `
1738
Program {
1839
"children": Array [

test/snapshot/break.test.js

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,30 @@
1-
const parser = require('../main');
1+
const parser = require("../main");
22

3-
describe('break', () => {
4-
it('simple', () => {
5-
expect(parser.parseEval('break;')).toMatchSnapshot();
3+
describe("break", () => {
4+
it("simple", () => {
5+
expect(parser.parseEval("break;")).toMatchSnapshot();
66
});
7-
it('argument 0', () => {
8-
expect(parser.parseEval('break 0;')).toMatchSnapshot();
7+
it("argument 0", () => {
8+
expect(parser.parseEval("break 0;")).toMatchSnapshot();
99
});
10-
it('argument 1', () => {
11-
expect(parser.parseEval('break 1;')).toMatchSnapshot();
10+
it("argument 1", () => {
11+
expect(parser.parseEval("break 1;")).toMatchSnapshot();
1212
});
13-
it('argument 2', () => {
14-
expect(parser.parseEval('break 2;')).toMatchSnapshot();
13+
it("argument 2", () => {
14+
expect(parser.parseEval("break 2;")).toMatchSnapshot();
1515
});
16-
it('with parens', () => {
17-
expect(parser.parseEval('break (1);')).toMatchSnapshot();
16+
it("with parens", () => {
17+
expect(parser.parseEval("break (1);")).toMatchSnapshot();
1818
});
1919
// Deprecated since 5.4.0
20-
it('with expression', () => {
21-
expect(parser.parseEval('break $var;')).toMatchSnapshot();
20+
it("with expression", () => {
21+
expect(parser.parseEval("break $var;")).toMatchSnapshot();
22+
});
23+
it("should fail when no ';' at end", function() {
24+
expect(
25+
parser.parseEval("break", {
26+
parser: { suppressErrors: true }
27+
})
28+
).toMatchSnapshot();
2229
});
2330
});

test/snapshot/continue.test.js

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,30 @@
1-
const parser = require('../main');
1+
const parser = require("../main");
22

3-
describe('continue', () => {
4-
it('simple', () => {
5-
expect(parser.parseEval('continue;')).toMatchSnapshot();
3+
describe("continue", () => {
4+
it("simple", () => {
5+
expect(parser.parseEval("continue;")).toMatchSnapshot();
66
});
7-
it('argument 0', () => {
8-
expect(parser.parseEval('continue 0;')).toMatchSnapshot();
7+
it("argument 0", () => {
8+
expect(parser.parseEval("continue 0;")).toMatchSnapshot();
99
});
10-
it('argument 1', () => {
11-
expect(parser.parseEval('continue 1;')).toMatchSnapshot();
10+
it("argument 1", () => {
11+
expect(parser.parseEval("continue 1;")).toMatchSnapshot();
1212
});
13-
it('argument 2', () => {
14-
expect(parser.parseEval('continue 2;')).toMatchSnapshot();
13+
it("argument 2", () => {
14+
expect(parser.parseEval("continue 2;")).toMatchSnapshot();
1515
});
16-
it('with parens', () => {
17-
expect(parser.parseEval('continue (1);')).toMatchSnapshot();
16+
it("with parens", () => {
17+
expect(parser.parseEval("continue (1);")).toMatchSnapshot();
1818
});
1919
// Deprecated since 5.4.0
20-
it('with expression', () => {
21-
expect(parser.parseEval('continue $var;')).toMatchSnapshot();
20+
it("with expression", () => {
21+
expect(parser.parseEval("continue $var;")).toMatchSnapshot();
22+
});
23+
it("should fail when no ';' at end", function() {
24+
expect(
25+
parser.parseEval("continue", {
26+
parser: { suppressErrors: true }
27+
})
28+
).toMatchSnapshot();
2229
});
2330
});

test/snapshot/return.test.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
1-
const parser = require('../main');
1+
const parser = require("../main");
22

33
describe("return", function() {
44
it("simple", function() {
55
expect(parser.parseEval('return "string";')).toMatchSnapshot();
66
});
77
it("no expression", function() {
8-
expect(parser.parseEval('return;')).toMatchSnapshot();
8+
expect(parser.parseEval("return;")).toMatchSnapshot();
9+
});
10+
it("should fail when no ';' at end", function() {
11+
expect(
12+
parser.parseEval("return", {
13+
parser: { suppressErrors: true }
14+
})
15+
).toMatchSnapshot();
916
});
1017
});

0 commit comments

Comments
 (0)