Skip to content

Commit

Permalink
Early whiteblock body termination
Browse files Browse the repository at this point in the history
  • Loading branch information
wcjohnson committed Oct 8, 2017
1 parent 3099b20 commit 5e5a50e
Show file tree
Hide file tree
Showing 18 changed files with 866 additions and 47 deletions.
31 changes: 2 additions & 29 deletions src/parser/statement.js
Expand Up @@ -630,19 +630,7 @@ pp.parseLabeledStatement = function (node, maybeName, expr) {

pp.parseExpressionStatement = function (node, expr) {
node.expression = expr;
if (this.hasPlugin("lightscript")) {
// for array comprehensions.
// TODO: cleanup / think of a better way of doing this.
this.match(tt.bracketR) ||
this.match(tt.braceR) ||
this.match(tt.parenR) ||
this.match(tt._else) ||
this.match(tt._elif) ||
this.match(tt.colon) ||
this.semicolon();
} else {
this.semicolon();
}
this.semicolon();
return this.finishNode(node, "ExpressionStatement");
};

Expand Down Expand Up @@ -674,17 +662,7 @@ pp.parseBlockBody = function (node, allowDirectives, topLevel, end) {
let oldStrict;
let octalPosition;

const oldInWhiteBlock = this.state.inWhiteBlock;
const oldWhiteBlockIndentLevel = this.state.whiteBlockIndentLevel;

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);
}
const isEnd = () => this.eat(end);

while (!isEnd()) {
if (!parsedNonDirective && this.state.containsOctal && !octalPosition) {
Expand Down Expand Up @@ -713,11 +691,6 @@ pp.parseBlockBody = function (node, allowDirectives, topLevel, end) {
node.body.push(stmt);
}

if (this.hasPlugin("lightscript")) {
this.state.inWhiteBlock = oldInWhiteBlock;
this.state.whiteBlockIndentLevel = oldWhiteBlockIndentLevel;
}

if (oldStrict === false) {
this.setStrict(false);
}
Expand Down
23 changes: 6 additions & 17 deletions src/parser/util.js
Expand Up @@ -63,23 +63,12 @@ pp.isLineBreak = function () {
// Test whether a semicolon can be inserted at the current position.

pp.canInsertSemicolon = function () {
return this.match(tt.eof) ||
this.match(tt.braceR) ||
this.isLineBreak() ||
(this.hasPlugin("lightscript") && (
// LSC oneline statement ASI cases
// Allow if x: throw y else: throw z
this.match(tt._else) ||
this.match(tt._elif) ||
// Allow (-> throw new Error)()
this.match(tt.parenR) ||
// Allow [-> throw new Error]
this.match(tt.bracketR) ||
// Technically it is legal to insert a ; after a ;.
// Allows -> throw new Error; f()
this.state.tokens[this.state.tokens.length - 1].type === tt.semi
)) ||
(this.hasPlugin("seqExprRequiresParen") && this.match(tt.comma));
return this.match(tt.eof)
|| this.match(tt.braceR)
|| this.isLineBreak()
|| this.state.tokens[this.state.tokens.length - 1].type === tt.semi
|| (this.match(tt.comma) && this.hasPlugin("seqExprRequiresParen"))
|| (this.hasPlugin("lightscript") && this.matchesWhiteBlockASIToken());
};

// TODO
Expand Down
66 changes: 65 additions & 1 deletion src/plugins/lightscript.js
Expand Up @@ -120,6 +120,70 @@ pp.expectParenFreeBlockStart = function (node) {
}
};

pp.matchesWhiteBlockASIToken = function() {
return (
(this.match(tt.comma) && this.hasPlugin("seqExprRequiresParen")) ||
this.match(tt.parenR) ||
this.match(tt.bracketR) ||
this.match(tt.braceR) ||
this.match(tt._else) ||
this.match(tt._elif) ||
this.match(tt.colon) ||
this.match(tt.eof)
);
};

// c/p statement.js parseBlockBody
pp.parseWhiteBlockBody = function (node, allowDirectives, topLevel, whiteBlockIndentLevel) {
node.body = [];
node.directives = [];

let parsedNonDirective = false;
let oldStrict;
let octalPosition;

const oldInWhiteBlock = this.state.inWhiteBlock;
const oldWhiteBlockIndentLevel = this.state.whiteBlockIndentLevel;
this.state.inWhiteBlock = true;
this.state.whiteBlockIndentLevel = whiteBlockIndentLevel;

const isEnd = () => this.state.indentLevel <= whiteBlockIndentLevel || this.matchesWhiteBlockASIToken();

while (!isEnd()) {
if (!parsedNonDirective && this.state.containsOctal && !octalPosition) {
octalPosition = this.state.octalPosition;
}

const stmt = this.parseStatement(true, topLevel);

if (allowDirectives && !parsedNonDirective && this.isValidDirective(stmt)) {
const directive = this.stmtToDirective(stmt);
node.directives.push(directive);

if (oldStrict === undefined && directive.value.value === "use strict") {
oldStrict = this.state.strict;
this.setStrict(true);

if (octalPosition) {
this.raise(octalPosition, "Octal literal in strict mode");
}
}

continue;
}

parsedNonDirective = true;
node.body.push(stmt);
}

this.state.inWhiteBlock = oldInWhiteBlock;
this.state.whiteBlockIndentLevel = oldWhiteBlockIndentLevel;

if (oldStrict === false) {
this.setStrict(false);
}
};

pp.parseInlineWhiteBlock = function(node) {
if (this.state.type.startsExpr) return this.parseMaybeAssign();
// oneline statement case
Expand All @@ -130,7 +194,7 @@ pp.parseInlineWhiteBlock = function(node) {
};

pp.parseMultilineWhiteBlock = function(node, indentLevel) {
this.parseBlockBody(node, false, false, indentLevel);
this.parseWhiteBlockBody(node, false, false, indentLevel);
if (!node.body.length) {
this.unexpected(node.start, "Expected an Indent or Statement");
}
Expand Down
@@ -0,0 +1,3 @@
{
"throws": "Unexpected token (1:10)"
}
3 changes: 3 additions & 0 deletions test/fixtures/flow/predicates/4/options.lightscript.json
@@ -0,0 +1,3 @@
{
"throws": "Unexpected token (1:20)"
}
@@ -0,0 +1,2 @@
[->
a, b]
@@ -0,0 +1,157 @@
{
"type": "File",
"start": 0,
"end": 11,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 2,
"column": 7
}
},
"program": {
"type": "Program",
"start": 0,
"end": 11,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 2,
"column": 7
}
},
"sourceType": "script",
"body": [
{
"type": "ExpressionStatement",
"start": 0,
"end": 11,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 2,
"column": 7
}
},
"expression": {
"type": "ArrayExpression",
"start": 0,
"end": 11,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 2,
"column": 7
}
},
"elements": [
{
"type": "ArrowFunctionExpression",
"start": 1,
"end": 7,
"loc": {
"start": {
"line": 1,
"column": 1
},
"end": {
"line": 2,
"column": 3
}
},
"id": null,
"generator": false,
"expression": false,
"async": false,
"params": [],
"skinny": true,
"body": {
"type": "BlockStatement",
"start": 1,
"end": 7,
"loc": {
"start": {
"line": 1,
"column": 1
},
"end": {
"line": 2,
"column": 3
}
},
"body": [
{
"type": "ExpressionStatement",
"start": 6,
"end": 7,
"loc": {
"start": {
"line": 2,
"column": 2
},
"end": {
"line": 2,
"column": 3
}
},
"expression": {
"type": "Identifier",
"start": 6,
"end": 7,
"loc": {
"start": {
"line": 2,
"column": 2
},
"end": {
"line": 2,
"column": 3
},
"identifierName": "a"
},
"name": "a"
}
}
],
"directives": [],
"extra": {
"curly": false
}
}
},
{
"type": "Identifier",
"start": 9,
"end": 10,
"loc": {
"start": {
"line": 2,
"column": 5
},
"end": {
"line": 2,
"column": 6
},
"identifierName": "b"
},
"name": "b"
}
]
}
}
],
"directives": []
}
}
@@ -0,0 +1,2 @@
a! b() ->
c, d

0 comments on commit 5e5a50e

Please sign in to comment.