From e07daadc6e8ae1e5ac43f62c245d19e296600c01 Mon Sep 17 00:00:00 2001 From: "William C. Johnson" Date: Fri, 6 Oct 2017 17:05:16 -0400 Subject: [PATCH] Disallow subscripting from crossing whiteblock boundaries Addresses https://github.com/wcjohnson/lightscript/issues/33 --- src/parser/expression.js | 4 +- src/parser/statement.js | 8 + src/plugins/lightscript.js | 4 + .../basic-promise-pattern/actual.js | 5 + .../basic-promise-pattern/expected.json | 372 ++++++++++++++++++ 5 files changed, 392 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/bang-call/subscripts/basic-promise-pattern/actual.js create mode 100644 test/fixtures/bang-call/subscripts/basic-promise-pattern/expected.json diff --git a/src/parser/expression.js b/src/parser/expression.js index 76328d47a8..d6e9420dc7 100644 --- a/src/parser/expression.js +++ b/src/parser/expression.js @@ -386,7 +386,9 @@ pp.parseSubscripts = function (base, startPos, startLoc, noCalls) { this.state.noPipeSubscripts = false; for (;;) { - if (this.hasPlugin("bangCall") && this.shouldUnwindBangSubscript()) { + if (this.hasPlugin("lightscript") && this.crossesWhiteBlockBoundary()) { + return base; + } else if (this.hasPlugin("bangCall") && this.shouldUnwindBangSubscript()) { return base; } else if (!noCalls && this.eat(tt.doubleColon)) { const node = this.startNodeAt(startPos, startLoc); diff --git a/src/parser/statement.js b/src/parser/statement.js index 9ebfe55279..d453651401 100644 --- a/src/parser/statement.js +++ b/src/parser/statement.js @@ -608,10 +608,14 @@ pp.parseBlockBody = function (node, allowDirectives, topLevel, end) { let oldStrict; let octalPosition; + const oldInWhiteBlock = this.state.inWhiteBlock; + const oldWhiteBlockIndentLevel = this.state.whiteBlockIndentLevel; this.state.nestedBlockLevel++; let isEnd; if (this.hasPlugin("lightscript") && typeof end === "number") { + this.state.inWhiteBlock = true; + this.state.whiteBlockIndentLevel = end; isEnd = () => this.state.indentLevel <= end || this.match(tt.eof); } else { isEnd = () => this.eat(end); @@ -645,6 +649,10 @@ pp.parseBlockBody = function (node, allowDirectives, topLevel, end) { } this.state.nestedBlockLevel--; + if (this.hasPlugin("lightscript")) { + this.state.inWhiteBlock = oldInWhiteBlock; + this.state.whiteBlockIndentLevel = oldWhiteBlockIndentLevel; + } if (oldStrict === false) { this.setStrict(false); diff --git a/src/plugins/lightscript.js b/src/plugins/lightscript.js index ad1ee6ca0b..f799050ba2 100644 --- a/src/plugins/lightscript.js +++ b/src/plugins/lightscript.js @@ -250,6 +250,10 @@ pp.parseWhiteBlock = function (isExpression?) { return this.parseMultilineWhiteBlock(node, indentLevel); }; +pp.crossesWhiteBlockBoundary = function() { + return (this.state.inWhiteBlock && this.state.indentLevel <= this.state.whiteBlockIndentLevel); +}; + pp.expectCommaOrLineBreak = function (loc = null) { // TODO: consider error message like "Missing comma or newline." if (!(this.eat(tt.comma) || this.isLineBreak())) this.unexpected(loc, tt.comma); diff --git a/test/fixtures/bang-call/subscripts/basic-promise-pattern/actual.js b/test/fixtures/bang-call/subscripts/basic-promise-pattern/actual.js new file mode 100644 index 0000000000..5d03d4068f --- /dev/null +++ b/test/fixtures/bang-call/subscripts/basic-promise-pattern/actual.js @@ -0,0 +1,5 @@ +a() + .then! b -> + c + .catch! d -> + e diff --git a/test/fixtures/bang-call/subscripts/basic-promise-pattern/expected.json b/test/fixtures/bang-call/subscripts/basic-promise-pattern/expected.json new file mode 100644 index 0000000000..cf15b709d0 --- /dev/null +++ b/test/fixtures/bang-call/subscripts/basic-promise-pattern/expected.json @@ -0,0 +1,372 @@ +{ + "type": "File", + "start": 0, + "end": 44, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 5, + "column": 5 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 44, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 5, + "column": 5 + } + }, + "sourceType": "script", + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 44, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 5, + "column": 5 + } + }, + "expression": { + "type": "CallExpression", + "start": 0, + "end": 44, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 5, + "column": 5 + } + }, + "callee": { + "type": "MemberExpression", + "start": 0, + "end": 32, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 4, + "column": 8 + } + }, + "object": { + "type": "CallExpression", + "start": 0, + "end": 23, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 5 + } + }, + "callee": { + "type": "MemberExpression", + "start": 0, + "end": 11, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 7 + } + }, + "object": { + "type": "CallExpression", + "start": 0, + "end": 3, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 3 + } + }, + "callee": { + "type": "Identifier", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + }, + "identifierName": "a" + }, + "name": "a" + }, + "arguments": [] + }, + "property": { + "type": "Identifier", + "start": 7, + "end": 11, + "loc": { + "start": { + "line": 2, + "column": 3 + }, + "end": { + "line": 2, + "column": 7 + }, + "identifierName": "then" + }, + "name": "then" + }, + "computed": false + }, + "arguments": [ + { + "type": "ArrowFunctionExpression", + "start": 13, + "end": 23, + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 3, + "column": 5 + } + }, + "id": null, + "generator": false, + "expression": false, + "async": false, + "params": [ + { + "type": "Identifier", + "start": 13, + "end": 14, + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 2, + "column": 10 + }, + "identifierName": "b" + }, + "name": "b" + } + ], + "skinny": true, + "body": { + "type": "BlockStatement", + "start": 15, + "end": 23, + "loc": { + "start": { + "line": 2, + "column": 11 + }, + "end": { + "line": 3, + "column": 5 + } + }, + "body": [ + { + "type": "ExpressionStatement", + "start": 22, + "end": 23, + "loc": { + "start": { + "line": 3, + "column": 4 + }, + "end": { + "line": 3, + "column": 5 + } + }, + "expression": { + "type": "Identifier", + "start": 22, + "end": 23, + "loc": { + "start": { + "line": 3, + "column": 4 + }, + "end": { + "line": 3, + "column": 5 + }, + "identifierName": "c" + }, + "name": "c" + } + } + ], + "directives": [], + "extra": { + "curly": false + } + } + } + ], + "extra": { + "bang": true + } + }, + "property": { + "type": "Identifier", + "start": 27, + "end": 32, + "loc": { + "start": { + "line": 4, + "column": 3 + }, + "end": { + "line": 4, + "column": 8 + }, + "identifierName": "catch" + }, + "name": "catch" + }, + "computed": false + }, + "arguments": [ + { + "type": "ArrowFunctionExpression", + "start": 34, + "end": 44, + "loc": { + "start": { + "line": 4, + "column": 10 + }, + "end": { + "line": 5, + "column": 5 + } + }, + "id": null, + "generator": false, + "expression": false, + "async": false, + "params": [ + { + "type": "Identifier", + "start": 34, + "end": 35, + "loc": { + "start": { + "line": 4, + "column": 10 + }, + "end": { + "line": 4, + "column": 11 + }, + "identifierName": "d" + }, + "name": "d" + } + ], + "skinny": true, + "body": { + "type": "BlockStatement", + "start": 36, + "end": 44, + "loc": { + "start": { + "line": 4, + "column": 12 + }, + "end": { + "line": 5, + "column": 5 + } + }, + "body": [ + { + "type": "ExpressionStatement", + "start": 43, + "end": 44, + "loc": { + "start": { + "line": 5, + "column": 4 + }, + "end": { + "line": 5, + "column": 5 + } + }, + "expression": { + "type": "Identifier", + "start": 43, + "end": 44, + "loc": { + "start": { + "line": 5, + "column": 4 + }, + "end": { + "line": 5, + "column": 5 + }, + "identifierName": "e" + }, + "name": "e" + } + } + ], + "directives": [], + "extra": { + "curly": false + } + } + } + ], + "extra": { + "bang": true + } + } + } + ], + "directives": [] + } +} \ No newline at end of file