Fix support for flow optional parameters in arrow functions T7096

This overwrites the conditional handling in babylon for flow to support
optional parameters in arrow functions.
This commit is contained in:
Daniel Tschinder 2016-04-10 12:56:21 +02:00
parent b926e401c6
commit e6c11a0673
8 changed files with 409 additions and 4 deletions

View File

@ -88,7 +88,7 @@ pp.parseExpression = function (noIn, refShorthandDefaultPos) {
// Parse an assignment expression. This includes applications of // Parse an assignment expression. This includes applications of
// operators like `+=`. // operators like `+=`.
pp.parseMaybeAssign = function (noIn, refShorthandDefaultPos, afterLeftParse) { pp.parseMaybeAssign = function (noIn, refShorthandDefaultPos, afterLeftParse, refNeedsArrowPos) {
if (this.match(tt._yield) && this.state.inGenerator) { if (this.match(tt._yield) && this.state.inGenerator) {
return this.parseYield(); return this.parseYield();
} }
@ -108,7 +108,7 @@ pp.parseMaybeAssign = function (noIn, refShorthandDefaultPos, afterLeftParse) {
this.state.potentialArrowAt = this.state.start; this.state.potentialArrowAt = this.state.start;
} }
let left = this.parseMaybeConditional(noIn, refShorthandDefaultPos); let left = this.parseMaybeConditional(noIn, refShorthandDefaultPos, refNeedsArrowPos);
if (afterLeftParse) left = afterLeftParse.call(this, left, startPos, startLoc); if (afterLeftParse) left = afterLeftParse.call(this, left, startPos, startLoc);
if (this.state.type.isAssign) { if (this.state.type.isAssign) {
let node = this.startNodeAt(startPos, startLoc); let node = this.startNodeAt(startPos, startLoc);
@ -142,10 +142,15 @@ pp.parseMaybeAssign = function (noIn, refShorthandDefaultPos, afterLeftParse) {
// Parse a ternary conditional (`?:`) operator. // Parse a ternary conditional (`?:`) operator.
pp.parseMaybeConditional = function (noIn, refShorthandDefaultPos) { pp.parseMaybeConditional = function (noIn, refShorthandDefaultPos, refNeedsArrowPos) {
let startPos = this.state.start, startLoc = this.state.startLoc; let startPos = this.state.start, startLoc = this.state.startLoc;
let expr = this.parseExprOps(noIn, refShorthandDefaultPos); let expr = this.parseExprOps(noIn, refShorthandDefaultPos);
if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr; if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr;
return this.parseConditional(expr, noIn, startPos, startLoc, refNeedsArrowPos);
};
pp.parseConditional = function (expr, noIn, startPos, startLoc) {
if (this.eat(tt.question)) { if (this.eat(tt.question)) {
let node = this.startNodeAt(startPos, startLoc); let node = this.startNodeAt(startPos, startLoc);
node.test = expr; node.test = expr;
@ -541,6 +546,7 @@ pp.parseParenAndDistinguishExpression = function (startPos, startLoc, canBeArrow
let innerStartPos = this.state.start, innerStartLoc = this.state.startLoc; let innerStartPos = this.state.start, innerStartLoc = this.state.startLoc;
let exprList = [], first = true; let exprList = [], first = true;
let refShorthandDefaultPos = { start: 0 }, spreadStart, optionalCommaStart; let refShorthandDefaultPos = { start: 0 }, spreadStart, optionalCommaStart;
let refNeedsArrowPos = { start: 0 };
while (!this.match(tt.parenR)) { while (!this.match(tt.parenR)) {
if (first) { if (first) {
first = false; first = false;
@ -558,7 +564,7 @@ pp.parseParenAndDistinguishExpression = function (startPos, startLoc, canBeArrow
exprList.push(this.parseParenItem(this.parseRest(), spreadNodeStartLoc, spreadNodeStartPos)); exprList.push(this.parseParenItem(this.parseRest(), spreadNodeStartLoc, spreadNodeStartPos));
break; break;
} else { } else {
exprList.push(this.parseMaybeAssign(false, refShorthandDefaultPos, this.parseParenItem)); exprList.push(this.parseMaybeAssign(false, refShorthandDefaultPos, this.parseParenItem, refNeedsArrowPos));
} }
} }
@ -584,6 +590,7 @@ pp.parseParenAndDistinguishExpression = function (startPos, startLoc, canBeArrow
if (optionalCommaStart && !allowOptionalCommaStart) this.unexpected(optionalCommaStart); if (optionalCommaStart && !allowOptionalCommaStart) this.unexpected(optionalCommaStart);
if (spreadStart) this.unexpected(spreadStart); if (spreadStart) this.unexpected(spreadStart);
if (refShorthandDefaultPos.start) this.unexpected(refShorthandDefaultPos.start); if (refShorthandDefaultPos.start) this.unexpected(refShorthandDefaultPos.start);
if (refNeedsArrowPos.start) this.unexpected(refNeedsArrowPos.start);
if (exprList.length > 1) { if (exprList.length > 1) {
val = this.startNodeAt(innerStartPos, innerStartLoc); val = this.startNodeAt(innerStartPos, innerStartLoc);

View File

@ -717,9 +717,30 @@ export default function (instance) {
}; };
}); });
instance.extend("parseConditional", function (inner) {
return function (expr, noIn, startPos, startLoc, refNeedsArrowPos) {
const state = this.state.clone();
try {
return inner.call(this, expr, noIn, startPos, startLoc);
} catch (err) {
if (refNeedsArrowPos && err instanceof SyntaxError) {
this.state = state;
refNeedsArrowPos.start = this.state.start;
return expr;
} else {
throw err;
}
}
};
});
instance.extend("parseParenItem", function () { instance.extend("parseParenItem", function () {
return function (node, startLoc, startPos, forceArrow?) { return function (node, startLoc, startPos, forceArrow?) {
let canBeArrow = this.state.potentialArrowAt = startPos; let canBeArrow = this.state.potentialArrowAt = startPos;
if (this.eat(tt.question)) {
node.optional = true;
}
if (this.match(tt.colon)) { if (this.match(tt.colon)) {
let typeCastNode = this.startNodeAt(startLoc, startPos); let typeCastNode = this.startNodeAt(startLoc, startPos);
typeCastNode.expression = node; typeCastNode.expression = node;

View File

@ -0,0 +1 @@
const f = (x?) => {}

View File

@ -0,0 +1,138 @@
{
"type": "File",
"start": 0,
"end": 20,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 20
}
},
"program": {
"type": "Program",
"start": 0,
"end": 20,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 20
}
},
"sourceType": "module",
"body": [
{
"type": "VariableDeclaration",
"start": 0,
"end": 20,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 20
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 6,
"end": 20,
"loc": {
"start": {
"line": 1,
"column": 6
},
"end": {
"line": 1,
"column": 20
}
},
"id": {
"type": "Identifier",
"start": 6,
"end": 7,
"loc": {
"start": {
"line": 1,
"column": 6
},
"end": {
"line": 1,
"column": 7
}
},
"name": "f"
},
"init": {
"type": "ArrowFunctionExpression",
"start": 10,
"end": 20,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 20
}
},
"id": null,
"generator": false,
"expression": false,
"async": false,
"params": [
{
"type": "Identifier",
"start": 11,
"end": 12,
"loc": {
"start": {
"line": 1,
"column": 11
},
"end": {
"line": 1,
"column": 12
}
},
"name": "x",
"optional": true
}
],
"body": {
"type": "BlockStatement",
"start": 18,
"end": 20,
"loc": {
"start": {
"line": 1,
"column": 18
},
"end": {
"line": 1,
"column": 20
}
},
"body": [],
"directives": []
}
}
}
],
"kind": "const"
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
const f = (x?)

View File

@ -0,0 +1,3 @@
{
"throws": "Unexpected token (1:12)"
}

View File

@ -0,0 +1 @@
const f = (x?, y?:Object = {}) => {}

View File

@ -0,0 +1,233 @@
{
"type": "File",
"start": 0,
"end": 36,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 36
}
},
"program": {
"type": "Program",
"start": 0,
"end": 36,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 36
}
},
"sourceType": "module",
"body": [
{
"type": "VariableDeclaration",
"start": 0,
"end": 36,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 36
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 6,
"end": 36,
"loc": {
"start": {
"line": 1,
"column": 6
},
"end": {
"line": 1,
"column": 36
}
},
"id": {
"type": "Identifier",
"start": 6,
"end": 7,
"loc": {
"start": {
"line": 1,
"column": 6
},
"end": {
"line": 1,
"column": 7
}
},
"name": "f"
},
"init": {
"type": "ArrowFunctionExpression",
"start": 10,
"end": 36,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 36
}
},
"id": null,
"generator": false,
"expression": false,
"async": false,
"params": [
{
"type": "Identifier",
"start": 11,
"end": 12,
"loc": {
"start": {
"line": 1,
"column": 11
},
"end": {
"line": 1,
"column": 12
}
},
"name": "x",
"optional": true
},
{
"type": "AssignmentPattern",
"start": 15,
"end": 29,
"loc": {
"start": {
"line": 1,
"column": 15
},
"end": {
"line": 1,
"column": 29
}
},
"left": {
"type": "Identifier",
"start": 15,
"end": 16,
"loc": {
"start": {
"line": 1,
"column": 15
},
"end": {
"line": 1,
"column": 16
}
},
"name": "y",
"optional": true,
"typeAnnotation": {
"type": "TypeAnnotation",
"start": 17,
"end": 24,
"loc": {
"start": {
"line": 1,
"column": 17
},
"end": {
"line": 1,
"column": 24
}
},
"typeAnnotation": {
"type": "GenericTypeAnnotation",
"start": 18,
"end": 24,
"loc": {
"start": {
"line": 1,
"column": 18
},
"end": {
"line": 1,
"column": 24
}
},
"typeParameters": null,
"id": {
"type": "Identifier",
"start": 18,
"end": 24,
"loc": {
"start": {
"line": 1,
"column": 18
},
"end": {
"line": 1,
"column": 24
}
},
"name": "Object"
}
}
}
},
"right": {
"type": "ObjectExpression",
"start": 27,
"end": 29,
"loc": {
"start": {
"line": 1,
"column": 27
},
"end": {
"line": 1,
"column": 29
}
},
"properties": []
}
}
],
"body": {
"type": "BlockStatement",
"start": 34,
"end": 36,
"loc": {
"start": {
"line": 1,
"column": 34
},
"end": {
"line": 1,
"column": 36
}
},
"body": [],
"directives": []
}
}
}
],
"kind": "const"
}
],
"directives": []
}
}