diff --git a/src/parser/statement.js b/src/parser/statement.js index 18482415f8..8a6744f8c0 100644 --- a/src/parser/statement.js +++ b/src/parser/statement.js @@ -483,11 +483,15 @@ pp.parseVarHead = function (decl) { // Parse a function declaration or literal (depending on the // `isStatement` parameter). -pp.parseFunction = function (node, isStatement, allowExpressionBody, isAsync) { +pp.parseFunction = function (node, isStatement, allowExpressionBody, isAsync, optionalId) { this.initFunction(node, isAsync); node.generator = this.eat(tt.star); - if (isStatement || this.match(tt.name)) { + if (isStatement && !optionalId && !this.match(tt.name)) { + this.unexpected(); + } + + if (this.match(tt.name)) { node.id = this.parseIdent(); } @@ -504,9 +508,9 @@ pp.parseFunctionParams = function (node) { // Parse a class declaration or literal (depending on the // `isStatement` parameter). -pp.parseClass = function (node, isStatement) { +pp.parseClass = function (node, isStatement, optionalId) { this.next(); - this.parseClassId(node, isStatement); + this.parseClassId(node, isStatement, optionalId); this.parseClassSuper(node); var classBody = this.startNode(); let hadConstructor = false; @@ -607,8 +611,16 @@ pp.parseClassMethod = function (classBody, method, isGenerator, isAsync) { classBody.body.push(this.finishNode(method, "MethodDefinition")); }; -pp.parseClassId = function (node, isStatement) { - node.id = this.match(tt.name) ? this.parseIdent() : isStatement ? this.unexpected() : null; +pp.parseClassId = function (node, isStatement, optionalId) { + if (this.match(tt.name)) { + node.id = this.parseIdent(); + } else { + if (optionalId || !isStatement) { + node.id = null; + } else { + this.unexpected(); + } + } }; pp.parseClassSuper = function (node) { @@ -648,14 +660,17 @@ pp.parseExport = function (node) { } this.parseExportFrom(node, true); } else if (this.eat(tt._default)) { // export default ... - let possibleDeclaration = this.match(tt._function) || this.match(tt._class); - let expr = this.parseMaybeAssign(); - let needsSemi = true; - if (possibleDeclaration) { - needsSemi = false; - if (expr.id) { - expr.type = expr.type === "FunctionExpression" ? "FunctionDeclaration" : "ClassDeclaration"; - } + let expr = this.startNode(); + let needsSemi = false; + if (this.eat(tt._function)) { + expr = this.parseFunction(expr, true, false, false, true); + if (!expr.id) expr.type = "FunctionExpression"; + } else if (this.match(tt._class)) { + expr = this.parseClass(expr, true, true); + if (!expr.id) expr.type = "ClassExpression"; + } else { + needsSemi = true; + expr = this.parseMaybeAssign(); } node.declaration = expr; if (needsSemi) this.semicolon(); diff --git a/test/fixtures/harmony/modules/export-default-function-declaration-expression-disambiguation/actual.js b/test/fixtures/harmony/modules/export-default-function-declaration-expression-disambiguation/actual.js new file mode 100644 index 0000000000..1f9bc179c3 --- /dev/null +++ b/test/fixtures/harmony/modules/export-default-function-declaration-expression-disambiguation/actual.js @@ -0,0 +1,2 @@ +export default function () {} +(foo); diff --git a/test/fixtures/harmony/modules/export-default-function-declaration-expression-disambiguation/expected.json b/test/fixtures/harmony/modules/export-default-function-declaration-expression-disambiguation/expected.json new file mode 100644 index 0000000000..c204457d46 --- /dev/null +++ b/test/fixtures/harmony/modules/export-default-function-declaration-expression-disambiguation/expected.json @@ -0,0 +1,115 @@ +{ + "type": "File", + "start": 0, + "end": 36, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 6 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 36, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 6 + } + }, + "sourceType": "module", + "body": [ + { + "type": "ExportDefaultDeclaration", + "start": 0, + "end": 29, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 29 + } + }, + "declaration": { + "type": "FunctionExpression", + "start": 15, + "end": 29, + "loc": { + "start": { + "line": 1, + "column": 15 + }, + "end": { + "line": 1, + "column": 29 + } + }, + "id": null, + "generator": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "start": 27, + "end": 29, + "loc": { + "start": { + "line": 1, + "column": 27 + }, + "end": { + "line": 1, + "column": 29 + } + }, + "body": [] + } + } + }, + { + "type": "ExpressionStatement", + "start": 30, + "end": 36, + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 6 + } + }, + "expression": { + "type": "Identifier", + "start": 31, + "end": 34, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 4 + } + }, + "name": "foo", + "parenthesizedExpression": true + } + } + ] + } +} \ No newline at end of file diff --git a/test/fixtures/harmony/modules/export-default-function-expression/options.json b/test/fixtures/harmony/modules/export-default-function-expression/options.json deleted file mode 100644 index 2104ca4328..0000000000 --- a/test/fixtures/harmony/modules/export-default-function-expression/options.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "sourceType": "module" -} diff --git a/test/fixtures/harmony/modules/export-default-function-declaration/options.json b/test/fixtures/harmony/modules/options.json similarity index 100% rename from test/fixtures/harmony/modules/export-default-function-declaration/options.json rename to test/fixtures/harmony/modules/options.json