Add async await related things

pull/9962/head
Nguyen Tran 3 years ago
parent 85d07681e2
commit c8f1621174

@ -103,6 +103,154 @@ export function serialize_get_binding(node, state) {
return node;
}
/**
* @param {import('estree').Expression} expression
* @returns {boolean}
*/
function is_async(expression) {
switch (expression.type) {
case 'ArrayExpression': {
for (const element of expression.elements) {
if (!element) {
continue;
} else if (element.type === 'SpreadElement') {
if (is_async(element.argument)) {
return true;
}
} else {
if (is_async(element)) {
return true;
}
}
}
return false;
}
case 'ArrowFunctionExpression':
case 'FunctionExpression': {
return expression.async ?? false;
}
case 'AwaitExpression': {
return true;
}
case 'BinaryExpression': {
return is_async(expression.left) || is_async(expression.right);
}
case 'CallExpression':
case 'NewExpression': {
const callee_is_async = expression.callee.type === 'Super' ? false : is_async(expression.callee);
if (callee_is_async) {
return true;
}
for (const element of expression.arguments) {
if (element.type === 'SpreadElement') {
if (is_async(element.argument)) {
return true;
}
} else {
if (is_async(element)) {
return true;
}
}
}
return false;
}
case 'ChainExpression': {
return is_async(expression.expression);
}
case 'ClassExpression': {
return false;
}
case 'ConditionalExpression': {
return is_async(expression.test) || is_async(expression.alternate) || is_async(expression.consequent);
}
case 'Identifier': {
return false;
}
case 'Literal': {
return false;
}
case 'ImportExpression': {
return is_async(expression.source);
}
case 'LogicalExpression': {
return is_async(expression.left) || is_async(expression.right);
}
case 'MemberExpression': {
const object_is_async = expression.object.type === 'Super' ? false : is_async(expression.object);
if (object_is_async) {
return true;
}
const property_is_async = expression.property.type === 'PrivateIdentifier' ? false : is_async(expression.property);
if (property_is_async) {
return true;
}
return false;
}
case 'MetaProperty': {
return false;
}
case 'ObjectExpression': {
for (const property of expression.properties) {
if (property.type === 'SpreadElement') {
if (is_async(property.argument)) {
return true;
}
} else {
const key_is_async = property.key.type === 'PrivateIdentifier' ? false : is_async(property.key);
if (key_is_async) {
return true;
}
const value_is_async = is_async(/** @type {import('estree').Expression} */ (property.value));
if (value_is_async) {
return true;
}
}
}
return false
}
case 'SequenceExpression': {
for (const subexpression of expression.expressions) {
if (is_async(subexpression)) {
return true;
}
}
return false;
}
case 'TaggedTemplateExpression': {
return is_async(expression.tag) || is_async(expression.quasi);
}
case 'TemplateLiteral': {
for (const subexpression of expression.expressions) {
if (is_async(subexpression)) {
return true;
}
}
return false;
}
case 'ThisExpression': {
return false;
}
case 'UnaryExpression': {
return is_async(expression.argument);
}
case 'UpdateExpression': {
return is_async(expression.argument);
}
case 'YieldExpression': {
return expression.argument ? is_async(expression.argument) : false;
}
default:
return false;
}
}
/**
* @template {import('./types').ClientTransformState} State
* @param {import('estree').AssignmentExpression} node
@ -141,18 +289,29 @@ export function serialize_set_binding(node, context, fallback) {
return fallback();
}
return b.call(
b.arrow(
[b.id(tmp_id)],
b.block([
b.stmt(b.sequence(assignments)),
// return because it could be used in a nested expression where the value is needed.
// example: { foo: ({ bar } = { bar: 1 })}
b.return(b.id(tmp_id))
])
),
/** @type {import('estree').Expression} */ (visit(node.right))
const rhs_expression = /** @type {import('estree').Expression} */ (visit(node.right));
const iife_is_async = is_async(rhs_expression) || assignments.some((assignment) => is_async(assignment));
let iife = b.arrow(
[],
b.block([
b.const(tmp_id, rhs_expression),
b.stmt(b.sequence(assignments)),
// return because it could be used in a nested expression where the value is needed.
// example: { foo: ({ bar } = { bar: 1 })}
b.return(b.id(tmp_id))
])
);
if (iife_is_async) {
iife = b.async(iife);
}
let iife_call = /** @type {import('estree').Expression} */ (b.call(iife));
if (iife_is_async) {
iife_call = b.await(iife_call);
}
return iife_call;
}
if (node.left.type !== 'Identifier' && node.left.type !== 'MemberExpression') {

@ -43,6 +43,23 @@ export function assignment(operator, left, right) {
return { type: 'AssignmentExpression', operator, left, right };
}
/**
* @template T
* @param {T & import('estree').BaseFunction} func
* @returns {T & import('estree').BaseFunction}
*/
export function async(func) {
return { ...func, async: true };
}
/**
* @param {import('estree').Expression} argument
* @returns {import('estree').AwaitExpression}
*/
export function await_builder(argument) {
return { type: 'AwaitExpression', argument };
}
/**
* @param {import('estree').BinaryOperator} operator
* @param {import('estree').Expression} left
@ -572,6 +589,7 @@ export function throw_error(str) {
}
export {
await_builder as await,
new_builder as new,
let_builder as let,
const_builder as const,

Loading…
Cancel
Save