Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse async do expressions #13043

6 changes: 6 additions & 0 deletions packages/babel-core/src/parser/util/missing-plugin-helper.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
const pluginNameMap = {
asyncDoExpressions: {
syntax: {
name: "@babel/plugin-syntax-async-do-expressions",
url: "https://git.io/JYer8",
},
},
classProperties: {
syntax: {
name: "@babel/plugin-syntax-class-properties",
Expand Down
4 changes: 4 additions & 0 deletions packages/babel-generator/src/generators/expressions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ export function UnaryExpression(this: Printer, node: t.UnaryExpression) {
}

export function DoExpression(this: Printer, node: t.DoExpression) {
if (node.async) {
this.word("async");
this.space();
}
this.word("do");
this.space();
this.print(node.body, node);
Expand Down
3 changes: 2 additions & 1 deletion packages/babel-generator/src/node/parentheses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ export function DoExpression(
parent: any,
printStack: Array<any>,
): boolean {
return isFirstInStatement(printStack);
// `async do` can start an expression statement
return !node.async && isFirstInStatement(printStack);
}

export function Binary(node: any, parent: any): boolean {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
async do {
1;
};

(async do {});
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
async do {
1;
};
async do {};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"plugins": ["asyncDoExpressions", "doExpressions"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/* leading comments
*/async do
{ 1 } + 0;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"retainLines": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/* leading comments
*/async do
{1;} + 0;
1 change: 1 addition & 0 deletions packages/babel-parser/ast/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,7 @@ An expression wrapped by parentheses. By default `@babel/parser` does not create
interface DoExpression <: Expression {
type: "DoExpression";
body: BlockStatement;
async: boolean;
}
```

Expand Down
22 changes: 19 additions & 3 deletions packages/babel-parser/src/parser/expression.js
Original file line number Diff line number Diff line change
Expand Up @@ -1033,6 +1033,8 @@ export default class ExpressionParser extends LValParser {
);
} else if (this.match(tt.name)) {
return this.parseAsyncArrowUnaryFunction(id);
} else if (this.match(tt._do)) {
return this.parseDo(true);
}
}

Expand All @@ -1049,7 +1051,7 @@ export default class ExpressionParser extends LValParser {
}

case tt._do: {
return this.parseDo();
return this.parseDo(false);
}

case tt.regexp: {
Expand Down Expand Up @@ -1231,13 +1233,27 @@ export default class ExpressionParser extends LValParser {
}

// https://github.com/tc39/proposal-do-expressions
parseDo(): N.DoExpression {
// https://github.com/tc39/proposal-async-do-expressions
parseDo(isAsync: boolean): N.DoExpression {
this.expectPlugin("doExpressions");
if (isAsync) {
this.expectPlugin("asyncDoExpressions");
}
JLHwung marked this conversation as resolved.
Show resolved Hide resolved
const node = this.startNode();
node.async = isAsync;
this.next(); // eat `do`
const oldLabels = this.state.labels;
this.state.labels = [];
node.body = this.parseBlock();
if (isAsync) {
// AsyncDoExpression :
// async [no LineTerminator here] do Block[~Yield, +Await, ~Return]
this.prodParam.enter(PARAM_AWAIT);
node.body = this.parseBlock();
this.prodParam.exit();
} else {
node.body = this.parseBlock();
}

this.state.labels = oldLabels;
return this.finishNode(node, "DoExpression");
}
Expand Down
12 changes: 12 additions & 0 deletions packages/babel-parser/src/plugin-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,18 @@ export function validatePlugins(plugins: PluginList) {
RECORD_AND_TUPLE_SYNTAX_TYPES.map(p => `'${p}'`).join(", "),
);
}

if (
hasPlugin(plugins, "asyncDoExpressions") &&
!hasPlugin(plugins, "doExpressions")
) {
const error = new Error(
"'asyncDoExpressions' requires 'doExpressions', please add 'doExpressions' to parser plugins.",
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we add .missingPlugin = ["doExpressions"] to the error (similarly to what expectPlugin does), @babel/core will suggest adding plugin-proposal-do-expressions to the config.

// $FlowIgnore
error.missingPlugins = "doExpressions"; // so @babel/core can provide better error message
throw error;
}
}

// These plugins are defined using a mixin which extends the parser class.
Expand Down
1 change: 1 addition & 0 deletions packages/babel-parser/src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ export type ArrayExpression = NodeBase & {
export type DoExpression = NodeBase & {
type: "DoExpression",
body: ?BlockStatement,
async: boolean,
};

export type TupleExpression = NodeBase & {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(async do {x})
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"throws": "This experimental syntax requires enabling the parser plugin: 'asyncDoExpressions' (1:7)",
"plugins": [
"doExpressions"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(async do {x})
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"throws": "This experimental syntax requires enabling the parser plugin: 'doExpressions' (1:7)",
"plugins": []
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
async
do {
42
}
while (false);
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"type": "File",
"start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":14}},
"program": {
"type": "Program",
"start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":14}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":5,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":5}},
"expression": {
"type": "Identifier",
"start":0,"end":5,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":5},"identifierName":"async"},
"name": "async"
}
},
{
"type": "DoWhileStatement",
"start":6,"end":32,"loc":{"start":{"line":2,"column":0},"end":{"line":5,"column":14}},
"body": {
"type": "BlockStatement",
"start":9,"end":17,"loc":{"start":{"line":2,"column":3},"end":{"line":4,"column":1}},
"body": [
{
"type": "ExpressionStatement",
"start":13,"end":15,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":4}},
"expression": {
"type": "NumericLiteral",
"start":13,"end":15,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":4}},
"extra": {
"rawValue": 42,
"raw": "42"
},
"value": 42
}
}
],
"directives": []
},
"test": {
"type": "BooleanLiteral",
"start":25,"end":30,"loc":{"start":{"line":5,"column":7},"end":{"line":5,"column":12}},
"value": false
}
}
],
"directives": []
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
async do {
42
}
while (false);
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"type": "File",
"start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":14}},
"program": {
"type": "Program",
"start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":14}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":17,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"expression": {
"type": "DoExpression",
"start":6,"end":17,"loc":{"start":{"line":1,"column":6},"end":{"line":3,"column":1}},
"async": true,
"body": {
"type": "BlockStatement",
"start":9,"end":17,"loc":{"start":{"line":1,"column":9},"end":{"line":3,"column":1}},
"body": [
{
"type": "ExpressionStatement",
"start":13,"end":15,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":4}},
"expression": {
"type": "NumericLiteral",
"start":13,"end":15,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":4}},
"extra": {
"rawValue": 42,
"raw": "42"
},
"value": 42
}
}
],
"directives": []
}
}
},
{
"type": "WhileStatement",
"start":18,"end":32,"loc":{"start":{"line":4,"column":0},"end":{"line":4,"column":14}},
"test": {
"type": "BooleanLiteral",
"start":25,"end":30,"loc":{"start":{"line":4,"column":7},"end":{"line":4,"column":12}},
"value": false
},
"body": {
"type": "EmptyStatement",
"start":31,"end":32,"loc":{"start":{"line":4,"column":13},"end":{"line":4,"column":14}}
}
}
],
"directives": []
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
async
do {
42
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"throws": "Unexpected token, expected \"while\" (4:1)"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
let x = async do {
if (foo()) { f() }
else if (bar()) { g() }
else { h() }
};