Skip to content

Commit

Permalink
Block parsing algorithm simplification
Browse files Browse the repository at this point in the history
  • Loading branch information
wcjohnson committed Oct 4, 2017
1 parent 65d3524 commit c9c226a
Show file tree
Hide file tree
Showing 62 changed files with 1,302 additions and 2,973 deletions.
14 changes: 11 additions & 3 deletions src/parser/statement.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ pp.parseStatement = function (declaration, topLevel) {

const isBlock = this.state.nextBraceIsBlock;
if (this.state.nextBraceIsBlock !== undefined) delete this.state.nextBraceIsBlock;
const allowDirectives = this.state.nextBraceAllowDirectives;
if (this.state.nextBraceAllowDirectives !== undefined) delete this.state.nextBraceAllowDirectives;

// Most types of statements are recognized by the keyword they
// start with. Many are trivial to parse, some require a bit of
Expand Down Expand Up @@ -114,7 +116,7 @@ pp.parseStatement = function (declaration, topLevel) {
}

try {
return this.parseBlock();
return this.parseBlock(allowDirectives);
} catch (err) {
if (objParseError) {
if (objParseError.pos > err.pos) {
Expand All @@ -134,7 +136,7 @@ pp.parseStatement = function (declaration, topLevel) {
// allow line-starting `{` to be parsed as obj or obj pattern
break;
} else {
return this.parseBlock();
return this.parseBlock(allowDirectives);
}
case tt.semi: return this.parseEmptyStatement(node);
case tt._export:
Expand Down Expand Up @@ -618,7 +620,13 @@ pp.parseExpressionStatement = function (node, 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.semicolon();
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();
}
Expand Down
139 changes: 14 additions & 125 deletions src/plugins/lightscript.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,80 +120,23 @@ pp.expectParenFreeBlockStart = function (node) {
}
};

// XXX: legacy
// [for ...: stmnt]

pp.parseArrayComprehension = function (node) {
const loop = this.startNode();
node.loop = this.parseForStatement(loop);
this.expect(tt.bracketR);
return this.finishNode(node, "ArrayComprehension");
};

// XXX: legacy
pp.parseObjectComprehension = function(node) {
const loop = this.startNode();
node.loop = this.parseForStatement(loop);
this.expect(tt.braceR);
return this.finishNode(node, "ObjectComprehension");
};

// Parse a whiteblock body consisting of a single object expr.
pp.parseObjectWhiteBlock = function(node, blockIndentLevel) {
const errorPos = this.state.start;
const exprStmt = this.startNode();
const obj = this.parseMaybeAssign();

if (
obj.type !== "ObjectExpression" &&
obj.type !== "ObjectComprehension" &&
// A tilde call can begin with { if an ObjectExpression is the thisArg.
(obj.type !== "CallExpression" || !obj.tilde)
) {
this.unexpected(errorPos, "Expected an object.");
}

if (this.state.indentLevel > blockIndentLevel) {
this.unexpected(errorPos, "Expected an object.");
}

exprStmt.expression = obj;
this.finishNode(exprStmt, "ExpressionStatement");

node.body = [exprStmt];
node.directives = [];
this.addExtra(node, "curly", false);
return this.finishNode(node, "BlockStatement");
};

pp.tryParseObjectWhiteBlock = function(node, blockIndentLevel) {
const state = this.state.clone();
try {
return [this.parseObjectWhiteBlock(node, blockIndentLevel)];
} catch (err) {
this.state = state;
return [null, err];
}
};

pp.rethrowObjParseError = function(objParseResult, blockParseError) {
const objParseError = objParseResult ? objParseResult[1] : null;
if (objParseError) {
if (objParseError.message === "WRONG_SPECULATIVE_BRANCH") {
throw blockParseError;
} else {
throw objParseError;
}
} else {
throw blockParseError;
}
};

pp.parseNonemptyWhiteBlock = function(node, indentLevel) {
this.parseBlockBody(node, false, false, indentLevel);
if (!node.body.length) {
this.unexpected(node.start, "Expected an Indent or Statement");
}
};

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

pp.parseMultilineWhiteBlock = function(node, indentLevel) {
if (this.match(tt.braceL) && this.hasPlugin("whiteblockOnly")) {
return this.parseObjectWhiteBlock(node, indentLevel);
}

if (this.match(tt.braceL) && this.hasPlugin("whiteblockPreferred")) {
const objParseResult = this.tryParseObjectWhiteBlock(node, indentLevel);
if (objParseResult[0]) return objParseResult[0];

try {
this.parseNonemptyWhiteBlock(node, indentLevel);
} catch (err) {
this.rethrowObjParseError(objParseResult, err);
}
} else {
this.parseNonemptyWhiteBlock(node, indentLevel);
this.parseBlockBody(node, false, false, indentLevel);
if (!node.body.length) {
this.unexpected(node.start, "Expected an Indent or Statement");
}

this.addExtra(node, "curly", false);
return this.finishNode(node, "BlockStatement");
};
Expand All @@ -237,27 +167,6 @@ pp.parseWhiteBlock = function (isExpression?) {
return this.parseInlineWhiteBlock(node);
}

if (this.match(tt.braceL)) {
if (this.hasPlugin("whiteblockOnly")) {
return this.parseObjectWhiteBlock(node, indentLevel);
}

let objParseResult = null;
if (this.hasPlugin("whiteblockPreferred")) {
objParseResult = this.tryParseObjectWhiteBlock(node, indentLevel);
if (objParseResult[0]) return objParseResult[0];

try {
this.state.nestedBlockLevel++;
const stmt = this.parseStatement(false);
this.state.nestedBlockLevel--;
return stmt;
} catch (err) {
this.rethrowObjParseError(objParseResult, err);
}
}
}

this.state.nestedBlockLevel++;
const stmt = this.parseStatement(false);
this.state.nestedBlockLevel--;
Expand Down Expand Up @@ -323,35 +232,14 @@ pp.parseArrowType = function (node) {
}
};

// largely c/p from parseFunctionBody

pp.parseBraceArrowFunctionBody = function(node, indentLevel) {
// In whiteblock-only mode, `{` must be introducing an object
if (this.hasPlugin("whiteblockOnly")) {
return this.parseObjectWhiteBlock(node, indentLevel);
}

// In whiteblock-preferred mode, try to parse an object, otherwise fall back on
// a braceblock.
if (this.hasPlugin("whiteblockPreferred")) {
const objParseResult = this.tryParseObjectWhiteBlock(node, indentLevel);
if (objParseResult[0]) return objParseResult[0];
this.next();

try {
this.parseBlockBody(node, true, false, tt.braceR);
} catch (err) {
this.rethrowObjParseError(objParseResult, err);
}

this.addExtra(node, "curly", true);
return this.finishNode(node, "BlockStatement");
pp.parseBraceArrowFunctionBody = function() {
this.state.nextBraceAllowDirectives = true;
const node = this.parseStatement(true);
if (node.type === "ExpressionStatement") {
return node.expression;
} else {
return node;
}

this.next();
this.parseBlockBody(node, true, false, tt.braceR);
this.addExtra(node, "curly", true);
return this.finishNode(node, "BlockStatement");
};

pp.parseArrowFunctionBody = function (node) {
Expand Down Expand Up @@ -542,10 +430,11 @@ pp.isAwaitArrowAssign = function (expr) {
pp.parseAwaitArrow = function (left) {
const node = this.startNode();
const arrowType = this.state.value;
const arrowPos = this.state.pos;
this.next();
if (arrowType === "<!-") {
if (left.type === "ObjectPattern" || left.type === "ArrayPattern") {
this.unexpected(left.start, "Destructuring is not allowed with '<!-'.");
this.unexpected(arrowPos - 3, "Destructuring is not allowed with '<!-'.");
}
return this.parseSafeAwait(node);
} else {
Expand Down
Loading

0 comments on commit c9c226a

Please sign in to comment.