Skip to content

Commit

Permalink
CatchExpr parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
wcjohnson committed Oct 25, 2017
1 parent 6a9bc59 commit 933d76a
Show file tree
Hide file tree
Showing 24 changed files with 2,216 additions and 3 deletions.
20 changes: 17 additions & 3 deletions src/parser/expression.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,11 @@ pp.parseMaybeAssign = function (noIn, refShorthandDefaultPos, afterLeftParse, re
node.isNowAssign = isNowAssign;
}

return this.finishNode(node, "AssignmentExpression");
if (this.hasPlugin("catchExpression")) {
return this.parseMaybeCatchAssignment(this.finishNode(node, "AssignmentExpression"));
} else {
return this.finishNode(node, "AssignmentExpression");
}
} else if (failOnShorthandAssign && refShorthandDefaultPos.start) {
this.unexpected(refShorthandDefaultPos.start);
}
Expand All @@ -191,7 +195,11 @@ pp.parseMaybeAssign = function (noIn, refShorthandDefaultPos, afterLeftParse, re
}
}

return left;
if (this.hasPlugin("catchExpression")) {
return this.parseMaybeCatchExpression(left);
} else {
return left;
}
};

// Parse a ternary conditional (`?:`) operator.
Expand Down Expand Up @@ -343,7 +351,7 @@ pp.parseMaybeUnary = function (refShorthandDefaultPos) {
let expr = this.parseExprSubscripts(refShorthandDefaultPos);
if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr;

if (this.state.inMatchAtom && this.state.type.postfix) {
if (this.state.inMatchAtom && (this.state.type.postfix || this.match(tt._catch))) {
this.unexpected(null, "Illegal operator in match atom.");
}

Expand All @@ -356,6 +364,12 @@ pp.parseMaybeUnary = function (refShorthandDefaultPos) {
this.next();
expr = this.finishNode(node, "UpdateExpression");
}

// Same-line catch expr
if (this.match(tt._catch) && !this.isLineBreak() && this.hasPlugin("catchExpression")) {
return this.parseCatchExpression(expr);
}

return expr;
};

Expand Down
88 changes: 88 additions & 0 deletions src/plugins/catchExpression.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import Parser from "../parser";
import { types as tt } from "../tokenizer/types";
const pp = Parser.prototype;

export default function(parser) {
if (parser.__catchExpressionPluginInstalled) return;
parser.__catchExpressionPluginInstalled = true;

pp.parseCatchExpression = function(expr) {
const node = this.startNodeAt(expr.start);
node.expression = expr;
const catchIndentLevel = this.state.indentLevel;
const isEnd = () =>
!this.match(tt._catch) || this.state.indentLevel !== catchIndentLevel || this.match(tt.eof);

node.cases = [];
while (!isEnd()) {
node.cases.push(this.parseCatchCase());
}

return this.finishNode(node, "CatchExpression");
};

pp.parseCatchCase = function() {
const node = this.startNode();
this.eat(tt._catch);
this.parseCatchCaseTest(node);
this.parseCatchCaseConsequent(node);
return this.finishNode(node, "CatchCase");
};

pp.parseCatchCaseConsequent = function(node) {
// disallow return/continue/break, etc. c/p doExpression
const oldInFunction = this.state.inFunction;
const oldLabels = this.state.labels;
this.state.labels = [];
this.state.inFunction = false;

node.consequent = this.parseBlock(false);

this.state.inFunction = oldInFunction;
this.state.labels = oldLabels;
};

pp.parseCatchCaseTest = function(node) {
// can't be nested so no need to read/restore old value
this.state.inMatchCaseTest = true;

this.parseCatchCaseAtoms(node);
if (this.isContextual("as")) {
this.parseCatchCaseBinding(node);
}

this.state.inMatchCaseTest = false;
};

pp.parseCatchCaseAtoms = function(node) {
const atoms = [];
this.state.inMatchAtom = true;
while (true) {
atoms.push(this.parseExprOps());
if (!this.eat(tt.comma)) break;
}
this.state.inMatchAtom = false;
node.atoms = atoms;
};

pp.parseCatchCaseBinding = function(node) {
node.binding = this.parseBindingAtom();
};

pp.isIndentedCatch = function() {
return this.match(tt._catch)
&& this.isLineBreak()
&& this.state.indentLevel > this.indentLevelAt(this.state.lastTokStart);
};

pp.parseMaybeCatchAssignment = function(assignExpr) {
if (!this.isIndentedCatch()) return assignExpr;
assignExpr.right = this.parseCatchExpression(assignExpr.right);
return this.finishNode(assignExpr, assignExpr.type);
};

pp.parseMaybeCatchExpression = function(expr) {
if (!this.isIndentedCatch()) return expr;
return this.parseCatchExpression(expr);
};
}
5 changes: 5 additions & 0 deletions src/registerPlugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import significantWhitespacePlugin from "./plugins/significantWhitespace";
import spreadLoopPlugin from "./plugins/spreadLoop";
import syntacticPlaceholderPlugin from "./plugins/syntacticPlaceholder";
import { matchCoreSyntax, match } from "./plugins/match";
import catchExpressionPlugin from "./plugins/catchExpression";

function noncePlugin() {}

Expand Down Expand Up @@ -91,4 +92,8 @@ export default function registerPlugins(plugins, metadata) {
});

registerPlugin("noLabeledExpressionStatements", noncePlugin);

registerPlugin("catchExpression", catchExpressionPlugin, {
dependencies: ["significantWhitespace"]
});
}
2 changes: 2 additions & 0 deletions test/fixtures/catch-expression/basic/assign/actual.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
a = b!
catch Error: c
202 changes: 202 additions & 0 deletions test/fixtures/catch-expression/basic/assign/expected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
{
"type": "File",
"start": 0,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 2,
"column": 16
}
},
"program": {
"type": "Program",
"start": 0,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 2,
"column": 16
}
},
"sourceType": "script",
"body": [
{
"type": "VariableDeclaration",
"start": 0,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 2,
"column": 16
}
},
"kind": "const",
"extra": {
"implicit": true
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 0,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 2,
"column": 16
}
},
"id": {
"type": "Identifier",
"start": 0,
"end": 1,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 1
},
"identifierName": "a"
},
"name": "a"
},
"init": {
"type": "CatchExpression",
"start": 4,
"end": 23,
"loc": {
"end": {
"line": 2,
"column": 16
}
},
"expression": {
"type": "CallExpression",
"start": 4,
"end": 6,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 6
}
},
"callee": {
"type": "Identifier",
"start": 4,
"end": 5,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 5
},
"identifierName": "b"
},
"name": "b"
},
"arguments": [],
"extra": {
"bang": true
}
},
"cases": [
{
"type": "CatchCase",
"start": 9,
"end": 23,
"loc": {
"start": {
"line": 2,
"column": 2
},
"end": {
"line": 2,
"column": 16
}
},
"atoms": [
{
"type": "Identifier",
"start": 15,
"end": 20,
"loc": {
"start": {
"line": 2,
"column": 8
},
"end": {
"line": 2,
"column": 13
},
"identifierName": "Error"
},
"name": "Error"
}
],
"consequent": {
"type": "ExpressionStatement",
"start": 22,
"end": 23,
"loc": {
"start": {
"line": 2,
"column": 15
},
"end": {
"line": 2,
"column": 16
}
},
"expression": {
"type": "Identifier",
"start": 22,
"end": 23,
"loc": {
"start": {
"line": 2,
"column": 15
},
"end": {
"line": 2,
"column": 16
},
"identifierName": "c"
},
"name": "c"
}
}
}
]
}
}
]
}
],
"directives": []
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
f() -/>
x <- g()
catch Error: false
Loading

0 comments on commit 933d76a

Please sign in to comment.