diff --git a/README.md b/README.md index 101c99cfa8..873f034253 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,7 @@ require("babylon").parse("code", { | `optionalChaining` ([proposal](https://github.com/tc39/proposal-optional-chaining)) | `a?.b` | | `importMeta` ([proposal](https://github.com/tc39/proposal-import-meta)) | `import.meta.url` | | `bigInt` ([proposal](https://github.com/tc39/proposal-bigint)) | `100n` | +| `optionalCatchBinding` ([proposal](https://github.com/babel/proposals/issues/7)) | `try {throw 0;} catch{do();}` | ### FAQ diff --git a/ast/spec.md b/ast/spec.md index c230951efe..55732ca155 100644 --- a/ast/spec.md +++ b/ast/spec.md @@ -442,7 +442,7 @@ A `try` statement. If `handler` is `null` then `finalizer` must be a `BlockState ```js interface CatchClause <: Node { type: "CatchClause"; - param: Pattern; + param: Pattern | null; body: BlockStatement; } ``` diff --git a/src/parser/statement.js b/src/parser/statement.js index 5d99d9c4d6..bd3c35857b 100644 --- a/src/parser/statement.js +++ b/src/parser/statement.js @@ -491,12 +491,14 @@ export default class StatementParser extends ExpressionParser { if (this.match(tt._catch)) { const clause = this.startNode(); this.next(); - - this.expect(tt.parenL); - clause.param = this.parseBindingAtom(); - this.checkLVal(clause.param, true, Object.create(null), "catch clause"); - this.expect(tt.parenR); - + if (this.match(tt.parenL) || !this.hasPlugin("optionalCatchBinding")) { + this.expect(tt.parenL); + clause.param = this.parseBindingAtom(); + this.checkLVal(clause.param, true, Object.create(null), "catch clause"); + this.expect(tt.parenR); + } else { + clause.param = null; + } clause.body = this.parseBlock(); node.handler = this.finishNode(clause, "CatchClause"); } diff --git a/test/fixtures/experimental/optional-catch-binding/no-plugin-no-binding-finally/actual.js b/test/fixtures/experimental/optional-catch-binding/no-plugin-no-binding-finally/actual.js new file mode 100644 index 0000000000..9faba4b001 --- /dev/null +++ b/test/fixtures/experimental/optional-catch-binding/no-plugin-no-binding-finally/actual.js @@ -0,0 +1,9 @@ +try { + +} +catch { + +} +finally { + +} diff --git a/test/fixtures/experimental/optional-catch-binding/no-plugin-no-binding-finally/options.json b/test/fixtures/experimental/optional-catch-binding/no-plugin-no-binding-finally/options.json new file mode 100644 index 0000000000..04c3ad7d05 --- /dev/null +++ b/test/fixtures/experimental/optional-catch-binding/no-plugin-no-binding-finally/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Unexpected token, expected ( (4:6)" +} diff --git a/test/fixtures/experimental/optional-catch-binding/no-plugin-no-binding/actual.js b/test/fixtures/experimental/optional-catch-binding/no-plugin-no-binding/actual.js new file mode 100644 index 0000000000..2550d2c262 --- /dev/null +++ b/test/fixtures/experimental/optional-catch-binding/no-plugin-no-binding/actual.js @@ -0,0 +1,6 @@ +try { + +} +catch { + +} diff --git a/test/fixtures/experimental/optional-catch-binding/no-plugin-no-binding/options.json b/test/fixtures/experimental/optional-catch-binding/no-plugin-no-binding/options.json new file mode 100644 index 0000000000..04c3ad7d05 --- /dev/null +++ b/test/fixtures/experimental/optional-catch-binding/no-plugin-no-binding/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Unexpected token, expected ( (4:6)" +} diff --git a/test/fixtures/experimental/optional-catch-binding/no-plugin-yes-binding-finally/actual.js b/test/fixtures/experimental/optional-catch-binding/no-plugin-yes-binding-finally/actual.js new file mode 100644 index 0000000000..e0a74b86fa --- /dev/null +++ b/test/fixtures/experimental/optional-catch-binding/no-plugin-yes-binding-finally/actual.js @@ -0,0 +1,4 @@ +try { +} catch (err) { +} finally { +} diff --git a/test/fixtures/experimental/optional-catch-binding/no-plugin-yes-binding-finally/expected.json b/test/fixtures/experimental/optional-catch-binding/no-plugin-yes-binding-finally/expected.json new file mode 100644 index 0000000000..e3930cb2bf --- /dev/null +++ b/test/fixtures/experimental/optional-catch-binding/no-plugin-yes-binding-finally/expected.json @@ -0,0 +1,133 @@ +{ + "type": "File", + "start": 0, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "sourceType": "script", + "body": [ + { + "type": "TryStatement", + "start": 0, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "block": { + "type": "BlockStatement", + "start": 4, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 2, + "column": 1 + } + }, + "body": [], + "directives": [] + }, + "handler": { + "type": "CatchClause", + "start": 8, + "end": 23, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "param": { + "type": "Identifier", + "start": 15, + "end": 18, + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 2, + "column": 12 + }, + "identifierName": "err" + }, + "name": "err" + }, + "body": { + "type": "BlockStatement", + "start": 20, + "end": 23, + "loc": { + "start": { + "line": 2, + "column": 14 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "body": [], + "directives": [] + } + }, + "guardedHandlers": [], + "finalizer": { + "type": "BlockStatement", + "start": 32, + "end": 35, + "loc": { + "start": { + "line": 3, + "column": 10 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "body": [], + "directives": [] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/experimental/optional-catch-binding/no-plugin-yes-binding/actual.js b/test/fixtures/experimental/optional-catch-binding/no-plugin-yes-binding/actual.js new file mode 100644 index 0000000000..c68ec02938 --- /dev/null +++ b/test/fixtures/experimental/optional-catch-binding/no-plugin-yes-binding/actual.js @@ -0,0 +1,2 @@ +try { +} catch (err) {} diff --git a/test/fixtures/experimental/optional-catch-binding/no-plugin-yes-binding/expected.json b/test/fixtures/experimental/optional-catch-binding/no-plugin-yes-binding/expected.json new file mode 100644 index 0000000000..24a4aaa600 --- /dev/null +++ b/test/fixtures/experimental/optional-catch-binding/no-plugin-yes-binding/expected.json @@ -0,0 +1,117 @@ +{ + "type": "File", + "start": 0, + "end": 22, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 16 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 22, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 16 + } + }, + "sourceType": "script", + "body": [ + { + "type": "TryStatement", + "start": 0, + "end": 22, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 16 + } + }, + "block": { + "type": "BlockStatement", + "start": 4, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 2, + "column": 1 + } + }, + "body": [], + "directives": [] + }, + "handler": { + "type": "CatchClause", + "start": 8, + "end": 22, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 16 + } + }, + "param": { + "type": "Identifier", + "start": 15, + "end": 18, + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 2, + "column": 12 + }, + "identifierName": "err" + }, + "name": "err" + }, + "body": { + "type": "BlockStatement", + "start": 20, + "end": 22, + "loc": { + "start": { + "line": 2, + "column": 14 + }, + "end": { + "line": 2, + "column": 16 + } + }, + "body": [], + "directives": [] + } + }, + "guardedHandlers": [], + "finalizer": null + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/experimental/optional-catch-binding/yes-plugin-no-binding-finally/actual.js b/test/fixtures/experimental/optional-catch-binding/yes-plugin-no-binding-finally/actual.js new file mode 100644 index 0000000000..9faba4b001 --- /dev/null +++ b/test/fixtures/experimental/optional-catch-binding/yes-plugin-no-binding-finally/actual.js @@ -0,0 +1,9 @@ +try { + +} +catch { + +} +finally { + +} diff --git a/test/fixtures/experimental/optional-catch-binding/yes-plugin-no-binding-finally/expected.json b/test/fixtures/experimental/optional-catch-binding/yes-plugin-no-binding-finally/expected.json new file mode 100644 index 0000000000..7ffccafce2 --- /dev/null +++ b/test/fixtures/experimental/optional-catch-binding/yes-plugin-no-binding-finally/expected.json @@ -0,0 +1,117 @@ +{ + "type": "File", + "start": 0, + "end": 34, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 9, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 34, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 9, + "column": 1 + } + }, + "sourceType": "script", + "body": [ + { + "type": "TryStatement", + "start": 0, + "end": 34, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 9, + "column": 1 + } + }, + "block": { + "type": "BlockStatement", + "start": 4, + "end": 8, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "body": [], + "directives": [] + }, + "handler": { + "type": "CatchClause", + "start": 9, + "end": 19, + "loc": { + "start": { + "line": 4, + "column": 0 + }, + "end": { + "line": 6, + "column": 1 + } + }, + "param": null, + "body": { + "type": "BlockStatement", + "start": 15, + "end": 19, + "loc": { + "start": { + "line": 4, + "column": 6 + }, + "end": { + "line": 6, + "column": 1 + } + }, + "body": [], + "directives": [] + } + }, + "guardedHandlers": [], + "finalizer": { + "type": "BlockStatement", + "start": 28, + "end": 34, + "loc": { + "start": { + "line": 7, + "column": 8 + }, + "end": { + "line": 9, + "column": 1 + } + }, + "body": [], + "directives": [] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/experimental/optional-catch-binding/yes-plugin-no-binding-finally/options.json b/test/fixtures/experimental/optional-catch-binding/yes-plugin-no-binding-finally/options.json new file mode 100644 index 0000000000..b937a8bb5d --- /dev/null +++ b/test/fixtures/experimental/optional-catch-binding/yes-plugin-no-binding-finally/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["optionalCatchBinding"] +} diff --git a/test/fixtures/experimental/optional-catch-binding/yes-plugin-no-binding/actual.js b/test/fixtures/experimental/optional-catch-binding/yes-plugin-no-binding/actual.js new file mode 100644 index 0000000000..2550d2c262 --- /dev/null +++ b/test/fixtures/experimental/optional-catch-binding/yes-plugin-no-binding/actual.js @@ -0,0 +1,6 @@ +try { + +} +catch { + +} diff --git a/test/fixtures/experimental/optional-catch-binding/yes-plugin-no-binding/expected.json b/test/fixtures/experimental/optional-catch-binding/yes-plugin-no-binding/expected.json new file mode 100644 index 0000000000..e053c3b5cd --- /dev/null +++ b/test/fixtures/experimental/optional-catch-binding/yes-plugin-no-binding/expected.json @@ -0,0 +1,101 @@ +{ + "type": "File", + "start": 0, + "end": 21, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 6, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 21, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 6, + "column": 1 + } + }, + "sourceType": "script", + "body": [ + { + "type": "TryStatement", + "start": 0, + "end": 21, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 6, + "column": 1 + } + }, + "block": { + "type": "BlockStatement", + "start": 4, + "end": 8, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "body": [], + "directives": [] + }, + "handler": { + "type": "CatchClause", + "start": 9, + "end": 21, + "loc": { + "start": { + "line": 4, + "column": 0 + }, + "end": { + "line": 6, + "column": 1 + } + }, + "param": null, + "body": { + "type": "BlockStatement", + "start": 15, + "end": 21, + "loc": { + "start": { + "line": 4, + "column": 6 + }, + "end": { + "line": 6, + "column": 1 + } + }, + "body": [], + "directives": [] + } + }, + "guardedHandlers": [], + "finalizer": null + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/experimental/optional-catch-binding/yes-plugin-no-binding/options.json b/test/fixtures/experimental/optional-catch-binding/yes-plugin-no-binding/options.json new file mode 100644 index 0000000000..b937a8bb5d --- /dev/null +++ b/test/fixtures/experimental/optional-catch-binding/yes-plugin-no-binding/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["optionalCatchBinding"] +} diff --git a/test/fixtures/experimental/optional-catch-binding/yes-plugin-yes-binding-finally/actual.js b/test/fixtures/experimental/optional-catch-binding/yes-plugin-yes-binding-finally/actual.js new file mode 100644 index 0000000000..e0a74b86fa --- /dev/null +++ b/test/fixtures/experimental/optional-catch-binding/yes-plugin-yes-binding-finally/actual.js @@ -0,0 +1,4 @@ +try { +} catch (err) { +} finally { +} diff --git a/test/fixtures/experimental/optional-catch-binding/yes-plugin-yes-binding-finally/expected.json b/test/fixtures/experimental/optional-catch-binding/yes-plugin-yes-binding-finally/expected.json new file mode 100644 index 0000000000..e3930cb2bf --- /dev/null +++ b/test/fixtures/experimental/optional-catch-binding/yes-plugin-yes-binding-finally/expected.json @@ -0,0 +1,133 @@ +{ + "type": "File", + "start": 0, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "sourceType": "script", + "body": [ + { + "type": "TryStatement", + "start": 0, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "block": { + "type": "BlockStatement", + "start": 4, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 2, + "column": 1 + } + }, + "body": [], + "directives": [] + }, + "handler": { + "type": "CatchClause", + "start": 8, + "end": 23, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "param": { + "type": "Identifier", + "start": 15, + "end": 18, + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 2, + "column": 12 + }, + "identifierName": "err" + }, + "name": "err" + }, + "body": { + "type": "BlockStatement", + "start": 20, + "end": 23, + "loc": { + "start": { + "line": 2, + "column": 14 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "body": [], + "directives": [] + } + }, + "guardedHandlers": [], + "finalizer": { + "type": "BlockStatement", + "start": 32, + "end": 35, + "loc": { + "start": { + "line": 3, + "column": 10 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "body": [], + "directives": [] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/experimental/optional-catch-binding/yes-plugin-yes-binding-finally/options.json b/test/fixtures/experimental/optional-catch-binding/yes-plugin-yes-binding-finally/options.json new file mode 100644 index 0000000000..b937a8bb5d --- /dev/null +++ b/test/fixtures/experimental/optional-catch-binding/yes-plugin-yes-binding-finally/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["optionalCatchBinding"] +} diff --git a/test/fixtures/experimental/optional-catch-binding/yes-plugin-yes-binding/actual.js b/test/fixtures/experimental/optional-catch-binding/yes-plugin-yes-binding/actual.js new file mode 100644 index 0000000000..c68ec02938 --- /dev/null +++ b/test/fixtures/experimental/optional-catch-binding/yes-plugin-yes-binding/actual.js @@ -0,0 +1,2 @@ +try { +} catch (err) {} diff --git a/test/fixtures/experimental/optional-catch-binding/yes-plugin-yes-binding/expected.json b/test/fixtures/experimental/optional-catch-binding/yes-plugin-yes-binding/expected.json new file mode 100644 index 0000000000..24a4aaa600 --- /dev/null +++ b/test/fixtures/experimental/optional-catch-binding/yes-plugin-yes-binding/expected.json @@ -0,0 +1,117 @@ +{ + "type": "File", + "start": 0, + "end": 22, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 16 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 22, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 16 + } + }, + "sourceType": "script", + "body": [ + { + "type": "TryStatement", + "start": 0, + "end": 22, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 16 + } + }, + "block": { + "type": "BlockStatement", + "start": 4, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 2, + "column": 1 + } + }, + "body": [], + "directives": [] + }, + "handler": { + "type": "CatchClause", + "start": 8, + "end": 22, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 16 + } + }, + "param": { + "type": "Identifier", + "start": 15, + "end": 18, + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 2, + "column": 12 + }, + "identifierName": "err" + }, + "name": "err" + }, + "body": { + "type": "BlockStatement", + "start": 20, + "end": 22, + "loc": { + "start": { + "line": 2, + "column": 14 + }, + "end": { + "line": 2, + "column": 16 + } + }, + "body": [], + "directives": [] + } + }, + "guardedHandlers": [], + "finalizer": null + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/experimental/optional-catch-binding/yes-plugin-yes-binding/options.json b/test/fixtures/experimental/optional-catch-binding/yes-plugin-yes-binding/options.json new file mode 100644 index 0000000000..b937a8bb5d --- /dev/null +++ b/test/fixtures/experimental/optional-catch-binding/yes-plugin-yes-binding/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["optionalCatchBinding"] +}