Follow up issue to #1789
$ bin/uglifyjs -V
uglify-es 3.0.16
$ echo 'async()=>1;' | bin/uglifyjs
Parse error at 0:1,7
async()=>1;
^
ERROR: Unexpected token: arrow (=>)
@alexlamsl If only async were not a valid identifier and was a keyword instead then this would be trivial be implement.
Indeed - I thought the whole point of having all these reserved but unused keywords was to allow for future language expansion. And then when they needed one... :smirk:
Now that I'm looking into it - there isn't any mention of async arrow functions on MDN:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/async_function
Now that I'm looking into it - there isn't any mention of async arrow functions on MDN
You can see it in the ECMAScript 2018 Language Specification:
which would make it ES9 rather than ES8 as I first thought. Edit: see https://github.com/mishoo/UglifyJS2/issues/2102#issuecomment-310721938
However it happens to run on acorn with the ecma2017 flag:
$ echo 'let a = async (x, y) => await x - y;' | node_modules/.bin/acorn --ecma2017
{
"type": "Program",
"start": 0,
"end": 38,
"body": [
{
"type": "VariableDeclaration",
"start": 0,
"end": 37,
"declarations": [
{
"type": "VariableDeclarator",
"start": 4,
"end": 36,
"id": {
"type": "Identifier",
"start": 4,
"end": 5,
"name": "a"
},
"init": {
"type": "ArrowFunctionExpression",
"start": 9,
"end": 36,
"id": null,
"generator": false,
"expression": true,
"async": true,
...
Numerous acorn test cases:
FireFox 54 and Chrome 59 allow it:
let a = async (x, y) => await x - y;
alert(a);
babel allows it:
$ echo 'let a = async (x, y) => await x - y;' | babel
"use strict";
var _this = this;
var a = function a(x, y) {
return regeneratorRuntime.async(function a$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
context$1$0.next = 2;
return regeneratorRuntime.awrap(x);
case 2:
context$1$0.t0 = context$1$0.sent;
context$1$0.t1 = y;
return context$1$0.abrupt("return", context$1$0.t0 - context$1$0.t1);
case 5:
case "end":
return context$1$0.stop();
}
}, null, _this);
};
According to this link, the ECMAScript 8th Edition which introduces async/await is not yet finished:
https://en.wikipedia.org/wiki/ECMAScript#8th_Edition_.28not_yet_finished.29
which is the reason for the confusion over the ES201x name.
I'm currently half way through this mess - past the async hurdle, but lib/parse.js doesn't like await within the arrow function body, so... joy!
The once proposed alternate async/await syntax would have been much easier to implement:
https://github.com/tc39/ecmascript-asyncawait#surface-syntax
Does Node.js 8 not support await?
$ echo 'await x()' | node
[stdin]:1
await x()
^
SyntaxError: Unexpected identifier
at createScript (vm.js:74:10)
at Object.runInThisContext (vm.js:116:10)
await may only appear directly within in an async function.
Search for await in https://github.com/ternjs/acorn/blob/master/test/tests-asyncawait.js for both the valid an invalid await use cases.
Oh, okay, even acorn needs a special flag to run.
@kzc at least I have your commented-out test cases to work with, so that's been very helpful :wink:
$ echo 'function foo(x) { return await x(); }' | node_modules/.bin/acorn --ecma2017
Unexpected token (1:31)
$ echo 'async function foo(x) { return await x(); }' | node_modules/.bin/acorn --ecma2017 | head -18
{
"type": "Program",
"start": 0,
"end": 44,
"body": [
{
"type": "FunctionDeclaration",
"start": 0,
"end": 43,
"id": {
"type": "Identifier",
"start": 15,
"end": 18,
"name": "foo"
},
"generator": false,
"expression": false,
"async": true,
Almost there:
--- async.js
Running test [await_precedence]
Running test [async_function_declaration]
Running test [async_function_expression]
Running test [async_class]
Running test [async_object_literal]
Running test [async_export]
Running test [async_inline]
Running test [async_identifiers]
Running test [async_shorthand_property]
Running test [async_arrow]
!!! Test matched expected result but cannot parse output
---INPUT---
{
let a1 = x => await foo(x);
let a2 = () => await bar();
let a3 = x => await baz(x);
let a4 = (x, y) => {
await far(x, y);
};
let a5 = ({x: x = [ 1 ], y: z = 2}) => {
await wow(x, y);
};
}
---OUTPUT---
let a1=x=>await foo(x);let a2=()=>await bar();let a3=x=>await baz(x);let a4=(x,y)=>{await far(x,y)};let a5=({x:x=[1],y:z=2})=>{await wow(x,y)};
--REPARSE ERROR--
SyntaxError: Unexpected token: name (foo)
That one async_arrow test case I wrote:
let a5 = async ({x = [1], y: z = 2}) => { await wow(x, y); }
should probably be:
let a5 = async ({x = [1], y: z = 2}) => { await wow(x, z); }
Since z is a an arrow function parameter, not y.
--REPARSE ERROR--
That test runner feature saved me a lot of grief implementing new stuff.
The REPARSE error is correct as the await operator is not allowed in a non-async function:
let a1=x=>await foo(x);let a2=()=>await bar();let a3=x=>await baz(x);let a4=(x,y)=>{await far(x,y)};let a5=({x:x=[1],y:z=2})=>{await wow(x,y)};
--REPARSE ERROR--
SyntaxError: Unexpected token: name (foo)
But how did it parse in the first place?
But how did it parse in the first place?
lib/output.js does not handle AST_Arrow.async at all, hence the fireworks.
Currently stuck on this test:
$ type test.js
typeof (x) => 0;
$ uglifyjs test.js
typeof(x=>0);
$ type test.js | node
[stdin]:1
typeof (x) => 0;
^^^^^^
SyntaxError: Unexpected token typeof
at createScript (vm.js:74:10)
test/mocha/arrow.js only tested the case without parenthesis, i.e. typeof x => 0;, which does correctly fail on current harmony
Which has higher precedence - typeof or =>?
Presumably typeof.
=> is an operator?
=>is an operator?
You're correct that it's not an operator, but I don't know what to call it.
Should typeof x => 0 be parsed as (typeof x) => 0 or typeof (x => 0)?
Since acorn errors out with:
$ echo 'typeof x => 0' | node_modules/.bin/acorn
Unexpected token (1:9)
typeof appears to have higher precedence.
This may also be worth testing:
$ echo 'typeof async x => 0' | node_modules/.bin/acorn --ecma2017
Unexpected token (1:13)
$ echo 'typeof (async x => 0)' | node_modules/.bin/acorn --ecma2017
{
"type": "Program",
...valid...
In case that sounded pedantic - was just confused as I only know precedence in the context of operators :sweat_smile:
Your cases above should be taken care of in the upcoming PR - have to fix up test/compress/harmony.js with invalid syntax. If only they have expect_stdout back then... :smirk: