Better async/await support

This commit is contained in:
Richard Eames 2014-11-18 13:08:24 -07:00
parent 61810eef8d
commit 68acfb7cc5
3 changed files with 674 additions and 158 deletions

View File

@ -2028,8 +2028,9 @@
if (options.ecmaVersion < 7) { if (options.ecmaVersion < 7) {
unexpected(); unexpected();
} }
var start = storeCurrentPos();
next(); var retNode = startNodeAt(start);
var finishedAsync = parseIdent(true);
switch (tokType) { switch (tokType) {
case _function: case _function:
@ -2057,11 +2058,37 @@
if (metParenL === oldParenL && eat(_arrow)) { if (metParenL === oldParenL && eat(_arrow)) {
return parseArrowExpression(node, exprList, true); return parseArrowExpression(node, exprList, true);
} }
retNode.callee = finishedAsync;
retNode.arguments = exprList;
retNode = parseSubscripts(finishNode(retNode, "CallExpression"), start);
break;
default: default:
if (isStatement) {
if (tokType.beforeExpr) {
// Probably using async as an ident
if (tokType.isAssign) {
retNode.operator = tokVal;
retNode.left = tokType === _eq ? toAssignable(finishedAsync) : finishedAsync;
checkLVal(finishedAsync);
next();
retNode.right = parseMaybeAssign();
retNode = finishNode(retNode, "AssignmentExpression");
}
else {
unexpected
}
semicolon();
}
else {
unexpected(); unexpected();
} }
} }
else {
retNode = finishedAsync;
}
}
return retNode;
}
function parseIfStatement(node) { function parseIfStatement(node) {
next(); next();
@ -2615,19 +2642,65 @@
} else first = false; } else first = false;
var prop = startNode(), isGenerator, isAsync; var prop = startNode(), isGenerator, isAsync;
if (options.ecmaVersion >= 7) { if (tokType == _async) { // "async" is a valid key
isAsync = eat(_async); prop.computed = false;
if (isAsync && tokType === _star) unexpected(); prop.key = parseIdent(true);
isAsync = true;
}
if (options.ecmaVersion >= 6) {
isGenerator = eat(_star);
}
if (tokType === _name || tokType.keyword) {
// possibly an async function
if (isAsync && options.ecmaVersion < 7) {
unexpected();
}
if (isAsync && isGenerator) {
unexpected();
} }
if (options.ecmaVersion >= 6) { if (options.ecmaVersion >= 6) {
prop.method = false; prop.method = false;
prop.shorthand = false; prop.shorthand = false;
isGenerator = eat(_star);
} }
parsePropertyName(prop); parsePropertyName(prop);
}
else if (tokType === _colon) {
// key could be "async"
if (options.ecmaVersion >= 6) {
prop.method = false;
prop.shorthand = false;
}
isAsync = false;
}
else if (tokType === _bracketL) {
// could be async computed
if (isAsync && isGenerator) {
unexpected();
}
parsePropertyName(prop);
}
else if (tokType === _braceR) {
// object unpack, and key could be == "async"
if (isAsync) {
isAsync = false;
prop.computed = false;
}
else {
parsePropertyName(prop);
}
}
else {
//unexpected();
isAsync = false;
parsePropertyName(prop);
}
if (eat(_colon)) { if (eat(_colon)) {
prop.value = parseExpression(true); prop.value = parseExpression(true);
prop.kind = "init"; prop.kind = "init";
if (isAsync) {
unexpected();
}
} else if (options.ecmaVersion >= 6 && tokType === _parenL) { } else if (options.ecmaVersion >= 6 && tokType === _parenL) {
prop.kind = "init"; prop.kind = "init";
prop.method = true; prop.method = true;

View File

@ -20,6 +20,7 @@ for (var i = 2; i < process.argv.length; ++i) {
else if (arg == "--ecma3") options.ecmaVersion = 3; else if (arg == "--ecma3") options.ecmaVersion = 3;
else if (arg == "--ecma5") options.ecmaVersion = 5; else if (arg == "--ecma5") options.ecmaVersion = 5;
else if (arg == "--ecma6") options.ecmaVersion = 6; else if (arg == "--ecma6") options.ecmaVersion = 6;
else if (arg == "--ecma7") options.ecmaVersion = 7;
else if (arg == "--strictSemicolons") options.strictSemicolons = true; else if (arg == "--strictSemicolons") options.strictSemicolons = true;
else if (arg == "--locations") options.locations = true; else if (arg == "--locations") options.locations = true;
else if (arg == "--silent") silent = true; else if (arg == "--silent") silent = true;

View File

@ -14371,81 +14371,170 @@ test('f(async function(promise) { await promise })', {
}); });
test("f(a, async(1, 2), b);", { test("f(a, async(1, 2), b);", {
type: "Program", "type": "Program",
body: [{ "start": 0,
type: "ExpressionStatement", "end": 21,
expression: { "loc": {
type: "CallExpression", "start": {
callee: { "line": 1,
type: "Identifier", "column": 0
name: "f", },
loc: { "end": {
start: {line: 1, column: 0}, "line": 1,
end: {line: 1, column: 1} "column": 21
} }
}, },
arguments: [ "body": [
{ {
type: "Identifier", "type": "ExpressionStatement",
name: "a", "start": 0,
loc: { "end": 21,
start: {line: 1, column: 2}, "loc": {
end: {line: 1, column: 3} "start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 21
} }
}, },
"expression": {
"type": "CallExpression",
"start": 0,
"end": 20,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 20
}
},
"callee": {
"type": "Identifier",
"start": 0,
"end": 1,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 1
}
},
"name": "f"
},
"arguments": [
{
"type": "Identifier",
"start": 2,
"end": 3,
"loc": {
"start": {
"line": 1,
"column": 2
},
"end": {
"line": 1,
"column": 3
}
},
"name": "a"
},
{ {
type: "CallExpression", "type": "CallExpression",
callee: { "start": 5,
type: "Identifier", "end": 16,
name: "async", "loc": {
loc: { "start": {
start: {line: 1, column: 5}, "line": 1,
end: {line: 1, column: 10} "column": 5
},
"end": {
"line": 1,
"column": 16
} }
}, },
arguments: [ "callee": {
{ "type": "Identifier",
type: "Literal", "start": 5,
value: 1, "end": 10,
loc: { "loc": {
start: {line: 1,column: 11}, "start": {
end: {line: 1,column: 12} "line": 1,
"column": 5
},
"end": {
"line": 1,
"column": 10
} }
}, },
"name": "async"
},
"arguments": [
{
"type": "Literal",
"start": 11,
"end": 12,
"loc": {
"start": {
"line": 1,
"column": 11
},
"end": {
"line": 1,
"column": 12
}
},
"value": 1,
"raw": "1"
},
{ {
type: "Literal", "type": "Literal",
value: 2, "start": 14,
loc: { "end": 15,
start: {line: 1,column: 14}, "loc": {
end: {line: 1,column: 15} "start": {
"line": 1,
"column": 14
},
"end": {
"line": 1,
"column": 15
} }
},
"value": 2,
"raw": "2"
} }
], ]
loc: {
start: {line: 1,column: 5},
end: {line: 1,column: 16}
}
}, },
{ {
type: "Identifier", "type": "Identifier",
name: "b", "start": 18,
loc: { "end": 19,
start: {line: 1,column: 18}, "loc": {
end: {line: 1,column: 19} "start": {
} "line": 1,
} "column": 18
], },
loc: { "end": {
start: {line: 1,column: 0}, "line": 1,
end: {line: 1,column: 20} "column": 19
} }
}, },
loc: { "name": "b"
start: {line: 1,column: 0},
end: {line: 1,column: 20}
} }
}] ]
}, { }
}
]
}
, {
ecmaVersion: 7, ecmaVersion: 7,
locations: true locations: true
}); });
@ -14499,7 +14588,7 @@ test("var ok = async(x);", {
kind: "var", kind: "var",
loc: { loc: {
start: {line: 1,column: 0}, start: {line: 1,column: 0},
end: {line: 1,column: 17} end: {line: 1,column: 18}
} }
}] }]
}, { }, {
@ -14508,98 +14597,448 @@ test("var ok = async(x);", {
}); });
test("var async; async = 10;", { test("var async; async = 10;", {
type: "Program", "type": "Program",
body: [{ "start": 0,
type: "ExpressionStatement", "end": 22,
expression: { "loc": {
type: "FunctionExpression", "start": {
id: null, "line": 1,
params: [], "column": 0
defaults: [], },
body: { "end": {
type: "BlockStatement", "line": 1,
body: [ "column": 22
{
type: "VariableDeclaration",
declarations: [
{
type: "VariableDeclarator",
id: {
type: "Identifier",
name: "async",
loc: {
start: {line: 1,column: 18},
end: {line: 1,column: 23}
} }
}, },
init: null, "body": [
loc: { {
start: {line: 1,column: 18}, "type": "VariableDeclaration",
end: {line: 1,column: 23} "start": 0,
"end": 10,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 10
} }
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 4,
"end": 9,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 9
}
},
"id": {
"type": "Identifier",
"start": 4,
"end": 9,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 9
}
},
"name": "async"
},
"init": null
} }
], ],
kind: "var", "kind": "var"
loc: {
start: {line: 1,column: 14},
end: {line: 1,column: 24}
}
}, },
{ {
type: "ExpressionStatement", "type": "AssignmentExpression",
expression: { "start": 11,
type: "AssignmentExpression", "end": 21,
operator: "=", "loc": {
left: { "start": {
type: "Identifier", "line": 1,
name: "async", "column": 11
loc: { },
start: {line: 1,column: 25}, "end": {
end: {line: 1,column: 30} "line": 1,
"column": 21
} }
}, },
right: { "operator": "=",
type: "Literal", "left": {
value: 10, "type": "Identifier",
loc: { "start": 11,
start: {line: 1,column: 33}, "end": 16,
end: {line: 1,column: 35} "loc": {
"start": {
"line": 1,
"column": 11
},
"end": {
"line": 1,
"column": 16
} }
}, },
loc: { "name": "async"
start: {line: 1,column: 25}, },
end: {line: 1,column: 35} "right": {
"type": "Literal",
"start": 19,
"end": 21,
"loc": {
"start": {
"line": 1,
"column": 19
},
"end": {
"line": 1,
"column": 21
} }
}, },
loc: { "value": 10,
start: {line: 1,column: 25}, "raw": "10"
end: {line: 1,column: 36}
} }
} }
], ]
loc: {
start: {line: 1,column: 12},
end: {line: 1,column: 37}
}
},
rest: null,
generator: false,
expression: false,
loc: {
start: {line: 1,column: 1},
end: {line: 1,column: 37}
}
},
loc: {
start: {line: 1,column: 0},
end: {line: 1,column: 38}
}
}]
}, { }, {
ecmaVersion: 7, ecmaVersion: 7,
locations: true locations: true
}); });
test("var {a, async} = b;" {
"type": "Program",
"start": 0,
"end": 19,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 19
}
},
"body": [
{
"type": "VariableDeclaration",
"start": 0,
"end": 19,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 19
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 4,
"end": 18,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 18
}
},
"id": {
"type": "ObjectPattern",
"start": 4,
"end": 14,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 14
}
},
"properties": [
{
"type": "Property",
"start": 5,
"end": 6,
"loc": {
"start": {
"line": 1,
"column": 5
},
"end": {
"line": 1,
"column": 6
}
},
"method": false,
"shorthand": true,
"computed": false,
"key": {
"type": "Identifier",
"start": 5,
"end": 6,
"loc": {
"start": {
"line": 1,
"column": 5
},
"end": {
"line": 1,
"column": 6
}
},
"name": "a"
},
"kind": "init",
"value": {
"type": "Identifier",
"start": 5,
"end": 6,
"loc": {
"start": {
"line": 1,
"column": 5
},
"end": {
"line": 1,
"column": 6
}
},
"name": "a"
}
},
{
"type": "Property",
"start": 8,
"end": 13,
"loc": {
"start": {
"line": 1,
"column": 8
},
"end": {
"line": 1,
"column": 13
}
},
"computed": false,
"key": {
"type": "Identifier",
"start": 8,
"end": 13,
"loc": {
"start": {
"line": 1,
"column": 8
},
"end": {
"line": 1,
"column": 13
}
},
"name": "async"
},
"kind": "init",
"value": {
"type": "Identifier",
"start": 8,
"end": 13,
"loc": {
"start": {
"line": 1,
"column": 8
},
"end": {
"line": 1,
"column": 13
}
},
"name": "async"
},
"shorthand": true
}
]
},
"init": {
"type": "Identifier",
"start": 17,
"end": 18,
"loc": {
"start": {
"line": 1,
"column": 17
},
"end": {
"line": 1,
"column": 18
}
},
"name": "b"
}
}
],
"kind": "var"
}
]
}, {
ecmaVersion: 7,
locations: true
});
test("var x = { async: true };", {
"type": "Program",
"start": 0,
"end": 24,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 24
}
},
"body": [
{
"type": "VariableDeclaration",
"start": 0,
"end": 24,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 24
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 4,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 23
}
},
"id": {
"type": "Identifier",
"start": 4,
"end": 5,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 5
}
},
"name": "x"
},
"init": {
"type": "ObjectExpression",
"start": 8,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 8
},
"end": {
"line": 1,
"column": 23
}
},
"properties": [
{
"type": "Property",
"start": 10,
"end": 21,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 21
}
},
"computed": false,
"key": {
"type": "Identifier",
"start": 10,
"end": 15,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 15
}
},
"name": "async"
},
"method": false,
"shorthand": false,
"value": {
"type": "Literal",
"start": 17,
"end": 21,
"loc": {
"start": {
"line": 1,
"column": 17
},
"end": {
"line": 1,
"column": 21
}
},
"value": true,
"raw": "true"
},
"kind": "init"
}
]
}
}
],
"kind": "var"
}
]
}, {ecmaVersion: 7, locations: true});
// Harmony Invalid syntax // Harmony Invalid syntax
testFail("0o", "Expected number in radix 8 (1:2)", {ecmaVersion: 6}); testFail("0o", "Expected number in radix 8 (1:2)", {ecmaVersion: 6});
@ -14716,6 +15155,9 @@ testFail("function foo(promise) { await promise; }", "Unexpected token (1:30)",
testFail("async function* foo(promise) { await promise; }", "Unexpected token (1:14)", {ecmaVersion: 7}); testFail("async function* foo(promise) { await promise; }", "Unexpected token (1:14)", {ecmaVersion: 7});
testFail("var a = { async ['a']: true }", "Unexpected token (1:28)", {ecmaVersion: 7});
testFail("var a = { async *['a'](){} }", "Unexpected token (1:17)", {ecmaVersion: 7});
testFail("yield v", "Unexpected token (1:6)", {ecmaVersion: 6}); testFail("yield v", "Unexpected token (1:6)", {ecmaVersion: 6});
testFail("yield 10", "Unexpected token (1:6)", {ecmaVersion: 6}); testFail("yield 10", "Unexpected token (1:6)", {ecmaVersion: 6});