diff --git a/README.md b/README.md index 8b69868222..3f53ee6faa 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,7 @@ require("babylon").parse("code", { | `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();}` | +| `throwExpressions` ([proposal](https://github.com/babel/proposals/issues/23)) | `() => throw new Error("")` | ### FAQ diff --git a/ast/spec.md b/ast/spec.md index 596acb462e..28695b477a 100644 --- a/ast/spec.md +++ b/ast/spec.md @@ -736,7 +736,7 @@ A unary operator expression. ```js enum UnaryOperator { - "-" | "+" | "!" | "~" | "typeof" | "void" | "delete" + "-" | "+" | "!" | "~" | "typeof" | "void" | "delete" | "throw" } ``` diff --git a/src/parser/expression.js b/src/parser/expression.js index 6e97527d71..f97f3f9f76 100644 --- a/src/parser/expression.js +++ b/src/parser/expression.js @@ -324,6 +324,10 @@ export default class ExpressionParser extends LValParser { const update = this.match(tt.incDec); node.operator = this.state.value; node.prefix = true; + + if (node.operator === "throw") { + this.expectPlugin("throwExpressions"); + } this.next(); const argType = this.state.type; diff --git a/src/tokenizer/types.js b/src/tokenizer/types.js index 59ebcd52d0..83f0bb0719 100644 --- a/src/tokenizer/types.js +++ b/src/tokenizer/types.js @@ -165,7 +165,7 @@ export const keywords = { if: new KeywordTokenType("if"), return: new KeywordTokenType("return", { beforeExpr }), switch: new KeywordTokenType("switch"), - throw: new KeywordTokenType("throw", { beforeExpr }), + throw: new KeywordTokenType("throw", { beforeExpr, prefix, startsExpr }), try: new KeywordTokenType("try"), var: new KeywordTokenType("var"), let: new KeywordTokenType("let"), diff --git a/src/types.js b/src/types.js index 846d74b451..b444606733 100644 --- a/src/types.js +++ b/src/types.js @@ -423,7 +423,8 @@ export type UnaryOperator = | "~" | "typeof" | "void" - | "delete"; + | "delete" + | "throw"; export type UpdateExpression = NodeBase & { type: "UpdateExpression", diff --git a/test/fixtures/experimental/throw-expression/comma/actual.js b/test/fixtures/experimental/throw-expression/comma/actual.js new file mode 100644 index 0000000000..a4ccb189b4 --- /dev/null +++ b/test/fixtures/experimental/throw-expression/comma/actual.js @@ -0,0 +1,3 @@ +function test() { + (throw 1, 2); +} diff --git a/test/fixtures/experimental/throw-expression/comma/expected.json b/test/fixtures/experimental/throw-expression/comma/expected.json new file mode 100644 index 0000000000..77b94cdde9 --- /dev/null +++ b/test/fixtures/experimental/throw-expression/comma/expected.json @@ -0,0 +1,184 @@ +{ + "type": "File", + "start": 0, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "sourceType": "script", + "body": [ + { + "type": "FunctionDeclaration", + "start": 0, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "id": { + "type": "Identifier", + "start": 9, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 1, + "column": 13 + }, + "identifierName": "test" + }, + "name": "test" + }, + "generator": false, + "expression": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start": 16, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "body": [ + { + "type": "ExpressionStatement", + "start": 20, + "end": 33, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 15 + } + }, + "expression": { + "type": "SequenceExpression", + "start": 21, + "end": 31, + "loc": { + "start": { + "line": 2, + "column": 3 + }, + "end": { + "line": 2, + "column": 13 + } + }, + "expressions": [ + { + "type": "UnaryExpression", + "start": 21, + "end": 28, + "loc": { + "start": { + "line": 2, + "column": 3 + }, + "end": { + "line": 2, + "column": 10 + } + }, + "operator": "throw", + "prefix": true, + "argument": { + "type": "NumericLiteral", + "start": 27, + "end": 28, + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 2, + "column": 10 + } + }, + "extra": { + "rawValue": 1, + "raw": "1" + }, + "value": 1 + }, + "extra": { + "parenthesizedArgument": false + } + }, + { + "type": "NumericLiteral", + "start": 30, + "end": 31, + "loc": { + "start": { + "line": 2, + "column": 12 + }, + "end": { + "line": 2, + "column": 13 + } + }, + "extra": { + "rawValue": 2, + "raw": "2" + }, + "value": 2 + } + ], + "extra": { + "parenthesized": true, + "parenStart": 20 + } + } + } + ], + "directives": [] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/experimental/throw-expression/comma/options.json b/test/fixtures/experimental/throw-expression/comma/options.json new file mode 100644 index 0000000000..7605cf2deb --- /dev/null +++ b/test/fixtures/experimental/throw-expression/comma/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["throwExpressions"] +} diff --git a/test/fixtures/experimental/throw-expression/expression/actual.js b/test/fixtures/experimental/throw-expression/expression/actual.js new file mode 100644 index 0000000000..5507d7486d --- /dev/null +++ b/test/fixtures/experimental/throw-expression/expression/actual.js @@ -0,0 +1,3 @@ +function test() { + (throw 1); +} diff --git a/test/fixtures/experimental/throw-expression/expression/expected.json b/test/fixtures/experimental/throw-expression/expression/expected.json new file mode 100644 index 0000000000..14f3d23c12 --- /dev/null +++ b/test/fixtures/experimental/throw-expression/expression/expected.json @@ -0,0 +1,145 @@ +{ + "type": "File", + "start": 0, + "end": 32, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 32, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "sourceType": "script", + "body": [ + { + "type": "FunctionDeclaration", + "start": 0, + "end": 32, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "id": { + "type": "Identifier", + "start": 9, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 1, + "column": 13 + }, + "identifierName": "test" + }, + "name": "test" + }, + "generator": false, + "expression": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start": 16, + "end": 32, + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "body": [ + { + "type": "ExpressionStatement", + "start": 20, + "end": 30, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 12 + } + }, + "expression": { + "type": "UnaryExpression", + "start": 21, + "end": 28, + "loc": { + "start": { + "line": 2, + "column": 3 + }, + "end": { + "line": 2, + "column": 10 + } + }, + "operator": "throw", + "prefix": true, + "argument": { + "type": "NumericLiteral", + "start": 27, + "end": 28, + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 2, + "column": 10 + } + }, + "extra": { + "rawValue": 1, + "raw": "1" + }, + "value": 1 + }, + "extra": { + "parenthesizedArgument": false, + "parenthesized": true, + "parenStart": 20 + } + } + } + ], + "directives": [] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/experimental/throw-expression/expression/options.json b/test/fixtures/experimental/throw-expression/expression/options.json new file mode 100644 index 0000000000..7605cf2deb --- /dev/null +++ b/test/fixtures/experimental/throw-expression/expression/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["throwExpressions"] +} diff --git a/test/fixtures/experimental/throw-expression/logical/actual.js b/test/fixtures/experimental/throw-expression/logical/actual.js new file mode 100644 index 0000000000..aca983fc58 --- /dev/null +++ b/test/fixtures/experimental/throw-expression/logical/actual.js @@ -0,0 +1,3 @@ +function test() { + true && throw 1; +} diff --git a/test/fixtures/experimental/throw-expression/logical/expected.json b/test/fixtures/experimental/throw-expression/logical/expected.json new file mode 100644 index 0000000000..9567c711e4 --- /dev/null +++ b/test/fixtures/experimental/throw-expression/logical/expected.json @@ -0,0 +1,175 @@ +{ + "type": "File", + "start": 0, + "end": 38, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 38, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "sourceType": "script", + "body": [ + { + "type": "FunctionDeclaration", + "start": 0, + "end": 38, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "id": { + "type": "Identifier", + "start": 9, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 1, + "column": 13 + }, + "identifierName": "test" + }, + "name": "test" + }, + "generator": false, + "expression": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start": 16, + "end": 38, + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "body": [ + { + "type": "ExpressionStatement", + "start": 20, + "end": 36, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 18 + } + }, + "expression": { + "type": "LogicalExpression", + "start": 20, + "end": 35, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 17 + } + }, + "left": { + "type": "BooleanLiteral", + "start": 20, + "end": 24, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 6 + } + }, + "value": true + }, + "operator": "&&", + "right": { + "type": "UnaryExpression", + "start": 28, + "end": 35, + "loc": { + "start": { + "line": 2, + "column": 10 + }, + "end": { + "line": 2, + "column": 17 + } + }, + "operator": "throw", + "prefix": true, + "argument": { + "type": "NumericLiteral", + "start": 34, + "end": 35, + "loc": { + "start": { + "line": 2, + "column": 16 + }, + "end": { + "line": 2, + "column": 17 + } + }, + "extra": { + "rawValue": 1, + "raw": "1" + }, + "value": 1 + }, + "extra": { + "parenthesizedArgument": false + } + } + } + } + ], + "directives": [] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/experimental/throw-expression/logical/options.json b/test/fixtures/experimental/throw-expression/logical/options.json new file mode 100644 index 0000000000..7605cf2deb --- /dev/null +++ b/test/fixtures/experimental/throw-expression/logical/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["throwExpressions"] +} diff --git a/test/fixtures/experimental/throw-expression/not-enabled/actual.js b/test/fixtures/experimental/throw-expression/not-enabled/actual.js new file mode 100644 index 0000000000..a4ccb189b4 --- /dev/null +++ b/test/fixtures/experimental/throw-expression/not-enabled/actual.js @@ -0,0 +1,3 @@ +function test() { + (throw 1, 2); +} diff --git a/test/fixtures/experimental/throw-expression/not-enabled/options.json b/test/fixtures/experimental/throw-expression/not-enabled/options.json new file mode 100644 index 0000000000..47934f7082 --- /dev/null +++ b/test/fixtures/experimental/throw-expression/not-enabled/options.json @@ -0,0 +1,3 @@ +{ + "throws": "This experimental syntax requires enabling the parser plugin: 'throwExpressions' (2:3)" +} diff --git a/test/fixtures/experimental/throw-expression/statement/actual.js b/test/fixtures/experimental/throw-expression/statement/actual.js new file mode 100644 index 0000000000..a40fcbd4fe --- /dev/null +++ b/test/fixtures/experimental/throw-expression/statement/actual.js @@ -0,0 +1,3 @@ +function test() { + throw 1; +} diff --git a/test/fixtures/experimental/throw-expression/statement/expected.json b/test/fixtures/experimental/throw-expression/statement/expected.json new file mode 100644 index 0000000000..35c16d0838 --- /dev/null +++ b/test/fixtures/experimental/throw-expression/statement/expected.json @@ -0,0 +1,123 @@ +{ + "type": "File", + "start": 0, + "end": 30, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 30, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "sourceType": "script", + "body": [ + { + "type": "FunctionDeclaration", + "start": 0, + "end": 30, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "id": { + "type": "Identifier", + "start": 9, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 1, + "column": 13 + }, + "identifierName": "test" + }, + "name": "test" + }, + "generator": false, + "expression": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start": 16, + "end": 30, + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "body": [ + { + "type": "ThrowStatement", + "start": 20, + "end": 28, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 10 + } + }, + "argument": { + "type": "NumericLiteral", + "start": 26, + "end": 27, + "loc": { + "start": { + "line": 2, + "column": 8 + }, + "end": { + "line": 2, + "column": 9 + } + }, + "extra": { + "rawValue": 1, + "raw": "1" + }, + "value": 1 + } + } + ], + "directives": [] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/experimental/throw-expression/statement/options.json b/test/fixtures/experimental/throw-expression/statement/options.json new file mode 100644 index 0000000000..7605cf2deb --- /dev/null +++ b/test/fixtures/experimental/throw-expression/statement/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["throwExpressions"] +}