},
}, AST_Lambda);
+function is_arrow(node) {
+ return node instanceof AST_AsyncArrow || node instanceof AST_Arrow;
+}
+
function is_function(node) {
- return node instanceof AST_Arrow || node instanceof AST_AsyncFunction || node instanceof AST_Function;
+ return is_arrow(node) || node instanceof AST_AsyncFunction || node instanceof AST_Function;
+}
+
+function walk_lambda(node, tw) {
+ if (is_arrow(node) && node.value) {
+ node.value.walk(tw);
+ } else {
+ walk_body(node, tw);
+ }
}
var AST_Arrow = DEFNODE("Arrow", "inlined value", {
}, AST_Lambda);
function is_async(node) {
- return node instanceof AST_AsyncDefun || node instanceof AST_AsyncFunction;
+ return node instanceof AST_AsyncArrow || node instanceof AST_AsyncDefun || node instanceof AST_AsyncFunction;
}
+var AST_AsyncArrow = DEFNODE("AsyncArrow", "inlined value", {
+ $documentation: "An asynchronous arrow function expression",
+ $propdoc: {
+ value: "[AST_Node?] simple return expression, or null if using function body.",
+ },
+ walk: function(visitor) {
+ var node = this;
+ visitor.visit(node, function() {
+ node.argnames.forEach(function(argname) {
+ argname.walk(visitor);
+ });
+ if (node.rest) node.rest.walk(visitor);
+ if (node.value) {
+ node.value.walk(visitor);
+ } else {
+ walk_body(node, visitor);
+ }
+ });
+ },
+ _validate: function() {
+ if (this.name != null) throw new Error("name must be null");
+ if (this.uses_arguments) throw new Error("uses_arguments must be false");
+ if (this.value != null) {
+ must_be_expression(this, "value");
+ if (this.body.length) throw new Error("body must be empty if value exists");
+ }
+ },
+}, AST_Lambda);
+
var AST_AsyncFunction = DEFNODE("AsyncFunction", "inlined name", {
$documentation: "An asynchronous function expression",
$propdoc: {
}
});
});
- if (fn instanceof AST_Arrow && fn.value) {
- fn.value.walk(tw);
- } else {
- walk_body(fn, tw);
- }
+ walk_lambda(fn, tw);
var safe_ids = tw.safe_ids;
pop(tw);
walk_defuns(tw, fn);
return !(argname instanceof AST_Destructured);
})) {
abort = true;
- } else if (fn instanceof AST_Arrow && fn.value) {
+ } else if (is_arrow(fn) && fn.value) {
fn.value.transform(scanner);
} else for (var i = 0; !abort && i < fn.body.length; i++) {
var stat = fn.body[i];
if (!(stat instanceof AST_Directive)) return stat;
}
}
- AST_Arrow.DEFMETHOD("first_statement", function() {
+
+ function arrow_first_statement() {
if (this.value) return make_node(AST_Return, this.value, {
value: this.value
});
return skip_directives(this.body);
- });
+ }
+ AST_Arrow.DEFMETHOD("first_statement", arrow_first_statement);
+ AST_AsyncArrow.DEFMETHOD("first_statement", arrow_first_statement);
AST_Lambda.DEFMETHOD("first_statement", function() {
return skip_directives(this.body);
});
def(AST_Arrow, function() {
return basic_negation(this);
});
+ def(AST_AsyncArrow, function() {
+ return basic_negation(this);
+ });
def(AST_AsyncFunction, function() {
return basic_negation(this);
});
return true;
}
if (node instanceof AST_This) {
- if (scopes.length == 0 && self instanceof AST_Arrow) result = false;
+ if (scopes.length == 0 && is_arrow(self)) result = false;
return true;
}
}));
return trim_block(self);
});
- OPT(AST_Arrow, function(self, compressor) {
+ function opt_arrow(self, compressor) {
if (!compressor.option("arrows")) return self;
var body = tighten_body(self.value ? [ self.first_statement() ] : self.body, compressor);
switch (body.length) {
break;
}
return self;
- });
+ }
+ OPT(AST_Arrow, opt_arrow);
+ OPT(AST_AsyncArrow, opt_arrow);
OPT(AST_Function, function(self, compressor) {
self.body = tighten_body(self.body, compressor);
});
if (node.rest) node.rest.mark_symbol(marker, scanner);
}
- if (node instanceof AST_Arrow && node.value) {
- node.value.walk(tw);
- } else {
- walk_body(node, tw);
- }
+ walk_lambda(node, tw);
pop();
return true;
}
}
return this;
});
+ def(AST_AsyncArrow, return_null);
def(AST_AsyncFunction, return_null);
def(AST_Await, function(compressor) {
if (!compressor.option("awaits")) return this;
&& can_drop
&& all(fn.body, is_empty)
&& (fn !== exp || fn_name_unused(fn, compressor))
- && !(fn instanceof AST_Arrow && fn.value)) {
+ && !(is_arrow(fn) && fn.value)) {
return make_sequence(self, convert_args()).optimize(compressor);
}
}
if (!safe) return true;
if (node instanceof AST_Scope) {
if (node === fn) return;
- if (node instanceof AST_Arrow) {
+ if (is_arrow(node)) {
for (var i = 0; safe && i < node.argnames.length; i++) node.argnames[i].walk(tw);
} else if (is_defun(node) && node.name.name == "await") {
safe = false;
while (p = compressor.parent(i++)) {
if (p instanceof AST_Lambda) {
if (p instanceof AST_Accessor) return;
- if (p instanceof AST_Arrow) continue;
+ if (is_arrow(p)) continue;
fn_parent = compressor.parent(i);
return p;
}
});
AST_Arrow.DEFMETHOD("contains_this", return_false);
+ AST_AsyncArrow.DEFMETHOD("contains_this", return_false);
AST_Scope.DEFMETHOD("contains_this", function() {
var result;
var self = this;
self.walk(new TreeWalker(function(node) {
if (result) return true;
if (node instanceof AST_This) return result = true;
- if (node !== self && node instanceof AST_Scope && !(node instanceof AST_Arrow)) return true;
+ if (node !== self && node instanceof AST_Scope && !is_arrow(node)) return true;
}));
return result;
});
// [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
return p instanceof AST_Array
// () => (foo, bar)
- || p instanceof AST_Arrow && p.value === this
+ || is_arrow(p) && p.value === this
// await (foo, bar)
|| p instanceof AST_Await
// 1 + (2, 3) + 4 ==> 8
// ({ p: a } = o);
if (this.left instanceof AST_DestructuredObject) return needs_parens_obj(output);
});
+ PARENS(AST_AsyncArrow, function(output) {
+ return needs_parens_assign_cond(this, output);
+ });
PARENS(AST_Conditional, function(output) {
return needs_parens_assign_cond(this, output);
});
}
});
}
- DEFPRINT(AST_Arrow, function(output) {
- var self = this;
+ function print_arrow(self, output) {
if (self.argnames.length == 1 && self.argnames[0] instanceof AST_SymbolFunarg && !self.rest) {
self.argnames[0].print(output);
} else {
} else {
print_braced(self, output, true);
}
+ }
+ DEFPRINT(AST_Arrow, function(output) {
+ print_arrow(this, output);
+ });
+ DEFPRINT(AST_AsyncArrow, function(output) {
+ output.print("async");
+ output.space();
+ print_arrow(this, output);
});
function print_lambda(self, output) {
if (self.name) {
if (noin) node.walk(new TreeWalker(function(node) {
if (parens) return true;
if (node instanceof AST_Binary && node.operator == "in") return parens = true;
- if (node instanceof AST_Scope && !(node instanceof AST_Arrow && node.value)) return true;
+ if (node instanceof AST_Scope && !(is_arrow(node) && node.value)) return true;
}));
node.print(output, parens);
}
next();
return function_(AST_AsyncDefun);
}
+ break;
case "await":
if (S.in_async) return simple_statement();
- default:
- return is_token(peek(), "punc", ":")
- ? labeled_statement()
- : simple_statement();
+ break;
}
+ return is_token(peek(), "punc", ":")
+ ? labeled_statement()
+ : simple_statement();
case "punc":
switch (S.token.value) {
end: node.end,
});
}
+ if (node instanceof AST_SymbolFunarg) return node;
if (node instanceof AST_SymbolRef) return new AST_SymbolFunarg(node);
token_error(node.start, "Invalid arrow parameter");
}
- function arrow(exprs, start) {
+ function arrow(exprs, start, async) {
var was_async = S.in_async;
- S.in_async = false;
+ S.in_async = async;
var was_funarg = S.in_funarg;
S.in_funarg = S.in_function;
var argnames = exprs.map(to_funarg);
+ var rest = exprs.rest || null;
+ if (rest) rest = to_funarg(rest);
S.in_funarg = was_funarg;
expect("=>");
var body, value;
S.in_loop = loop;
S.labels = labels;
S.in_async = was_async;
- return new AST_Arrow({
+ return new (async ? AST_AsyncArrow : AST_Arrow)({
start: start,
argnames: argnames,
- rest: exprs.rest || null,
+ rest: rest,
body: body,
value: value,
end: prev(),
}
unexpected();
}
- var ctor;
- if (is("name", "async") && is_token(peek(), "keyword", "function")) {
+ if (is("keyword", "function")) {
next();
- ctor = AST_AsyncFunction;
- } else if (is("keyword", "function")) {
- ctor = AST_Function;
- }
- if (ctor) {
- next();
- var func = function_(ctor);
+ var func = function_(AST_Function);
func.start = start;
func.end = prev();
return subscripts(func, allow_calls);
if (is("name")) {
var sym = _make_symbol(AST_SymbolRef, start);
next();
+ if (sym.name == "async") {
+ if (is("keyword", "function")) {
+ next();
+ var func = function_(AST_AsyncFunction);
+ func.start = start;
+ func.end = prev();
+ return subscripts(func, allow_calls);
+ }
+ if (is("name")) {
+ start = S.token;
+ sym = _make_symbol(AST_SymbolRef, start);
+ next();
+ return arrow([ sym ], start, true);
+ }
+ if (is("punc", "(")) {
+ var call = subscripts(sym, allow_calls);
+ if (!is("punc", "=>")) return call;
+ var args = call.args;
+ if (args[args.length - 1] instanceof AST_Spread) {
+ args.rest = args.pop().expression;
+ }
+ return arrow(args, start, true);
+ }
+ }
return is("punc", "=>") ? arrow([ sym ], start) : subscripts(sym, allow_calls);
}
if (ATOMIC_START_TOKEN[S.token.type]) {
});
if (node.rest) node.rest.walk(tw);
in_arg.pop();
- if (node instanceof AST_Arrow && node.value) {
- node.value.walk(tw);
- } else {
- walk_body(node, tw);
- }
+ walk_lambda(node, tw);
return true;
}
if (node instanceof AST_LoopControl) {
function is_arguments(sym) {
return sym.orig[0] instanceof AST_SymbolFunarg
&& !(sym.orig[1] instanceof AST_SymbolFunarg || sym.orig[2] instanceof AST_SymbolFunarg)
- && !(sym.scope instanceof AST_Arrow);
+ && !is_arrow(sym.scope);
}
function redefine(node, scope) {
AST_Arrow.DEFMETHOD("init_vars", function(parent_scope) {
init_scope_vars(this, parent_scope);
});
+AST_AsyncArrow.DEFMETHOD("init_vars", function(parent_scope) {
+ init_scope_vars(this, parent_scope);
+});
AST_Lambda.DEFMETHOD("init_vars", function(parent_scope) {
init_scope_vars(this, parent_scope);
this.uses_arguments = false;
if (self.rest) self.rest = self.rest.transform(tw);
self.body = do_list(self.body, tw);
});
- DEF(AST_Arrow, function(self, tw) {
+ function transform_arrow(self, tw) {
self.argnames = do_list(self.argnames, tw);
if (self.rest) self.rest = self.rest.transform(tw);
if (self.value) {
} else {
self.body = do_list(self.body, tw);
}
- });
+ }
+ DEF(AST_Arrow, transform_arrow);
+ DEF(AST_AsyncArrow, transform_arrow);
DEF(AST_Call, function(self, tw) {
self.expression = self.expression.transform(tw);
self.args = do_list(self.args, tw);
function first_in_statement(stack, arrow) {
var node = stack.parent(-1);
for (var i = 0, p; p = stack.parent(i++); node = p) {
- if (p instanceof AST_Arrow) {
+ if (is_arrow(p)) {
return arrow && p.value === node;
} else if (p instanceof AST_Binary) {
if (p.left === node) continue;
+async_arrow: {
+ input: {
+ (async a => console.log(a))("PASS");
+ console.log(typeof (async () => 42)());
+ }
+ expect_exact: '(async a=>console.log(a))("PASS");console.log(typeof(async()=>42)());'
+ expect_stdout: [
+ "PASS",
+ "object",
+ ]
+ node_version: ">=8"
+}
+
+async_label: {
+ input: {
+ (async function() {
+ async: console.log("PASS");
+ })();
+ }
+ expect_exact: '(async function(){async:console.log("PASS")})();'
+ expect_stdout: "PASS"
+ node_version: ">=8"
+}
+
await_await: {
input: {
(async function() {
function is_statement(node) {
return node instanceof U.AST_Statement
- && !(node instanceof U.AST_Arrow || node instanceof U.AST_AsyncFunction || node instanceof U.AST_Function);
+ && !(node instanceof U.AST_Arrow
+ || node instanceof U.AST_AsyncArrow
+ || node instanceof U.AST_AsyncFunction
+ || node instanceof U.AST_Function);
}
function merge_sequence(array, node) {
var s = [];
switch (rng(5)) {
case 0:
- if (SUPPORT.arrow && !async && !name && rng(2)) {
+ if (SUPPORT.arrow && !name && rng(2)) {
var args, suffix;
(rng(2) ? createBlockVariables : function() {
arguments[3]();
} else {
params = createParams(save_async, NO_DUPLICATE);
}
+ params = (async ? "async (" : "(") + params + ") => ";
if (defns) {
s.push(
- "((" + params + ") => {",
+ "(" + params + "{",
strictMode(),
defns(),
_createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth)
);
suffix = "})";
} else {
- s.push("((" + params + ") => ");
+ s.push("(" + params);
switch (rng(10)) {
case 0:
s.push('(typeof arguments != "undefined" && arguments && arguments[' + rng(3) + "])");