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,10 +2058,36 @@
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:
unexpected(); 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();
}
}
else {
retNode = finishedAsync;
}
} }
return retNode;
} }
function parseIfStatement(node) { function parseIfStatement(node) {
@ -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) { if (options.ecmaVersion >= 6) {
prop.method = false;
prop.shorthand = false;
isGenerator = eat(_star); isGenerator = eat(_star);
} }
parsePropertyName(prop);
if (tokType === _name || tokType.keyword) {
// possibly an async function
if (isAsync && options.ecmaVersion < 7) {
unexpected();
}
if (isAsync && isGenerator) {
unexpected();
}
if (options.ecmaVersion >= 6) {
prop.method = false;
prop.shorthand = false;
}
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
}
},
"body": [
{
"type": "ExpressionStatement",
"start": 0,
"end": 21,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 21
} }
}, },
arguments: [ "expression": {
{ "type": "CallExpression",
type: "Identifier", "start": 0,
name: "a", "end": 20,
loc: { "loc": {
start: {line: 1, column: 2}, "start": {
end: {line: 1, column: 3} "line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 20
} }
}, },
{ "callee": {
type: "CallExpression", "type": "Identifier",
callee: { "start": 0,
type: "Identifier", "end": 1,
name: "async", "loc": {
loc: { "start": {
start: {line: 1, column: 5}, "line": 1,
end: {line: 1, column: 10} "column": 0
},
"end": {
"line": 1,
"column": 1
} }
}, },
arguments: [ "name": "f"
{ },
type: "Literal", "arguments": [
value: 1, {
loc: { "type": "Identifier",
start: {line: 1,column: 11}, "start": 2,
end: {line: 1,column: 12} "end": 3,
"loc": {
"start": {
"line": 1,
"column": 2
},
"end": {
"line": 1,
"column": 3
} }
}, },
{ "name": "a"
type: "Literal", },
value: 2, {
loc: { "type": "CallExpression",
start: {line: 1,column: 14}, "start": 5,
end: {line: 1,column: 15} "end": 16,
"loc": {
"start": {
"line": 1,
"column": 5
},
"end": {
"line": 1,
"column": 16
} }
} },
], "callee": {
loc: { "type": "Identifier",
start: {line: 1,column: 5}, "start": 5,
end: {line: 1,column: 16} "end": 10,
"loc": {
"start": {
"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",
"start": 14,
"end": 15,
"loc": {
"start": {
"line": 1,
"column": 14
},
"end": {
"line": 1,
"column": 15
}
},
"value": 2,
"raw": "2"
}
]
},
{
"type": "Identifier",
"start": 18,
"end": 19,
"loc": {
"start": {
"line": 1,
"column": 18
},
"end": {
"line": 1,
"column": 19
}
},
"name": "b"
} }
}, ]
{
type: "Identifier",
name: "b",
loc: {
start: {line: 1,column: 18},
end: {line: 1,column: 19}
}
}
],
loc: {
start: {line: 1,column: 0},
end: {line: 1,column: 20}
} }
},
loc: {
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: [ "body": [
{ {
type: "VariableDeclarator", "type": "VariableDeclaration",
id: { "start": 0,
type: "Identifier", "end": 10,
name: "async", "loc": {
loc: { "start": {
start: {line: 1,column: 18}, "line": 1,
end: {line: 1,column: 23} "column": 0
} },
}, "end": {
init: null, "line": 1,
loc: { "column": 10
start: {line: 1,column: 18},
end: {line: 1,column: 23}
}
}
],
kind: "var",
loc: {
start: {line: 1,column: 14},
end: {line: 1,column: 24}
}
},
{
type: "ExpressionStatement",
expression: {
type: "AssignmentExpression",
operator: "=",
left: {
type: "Identifier",
name: "async",
loc: {
start: {line: 1,column: 25},
end: {line: 1,column: 30}
}
},
right: {
type: "Literal",
value: 10,
loc: {
start: {line: 1,column: 33},
end: {line: 1,column: 35}
}
},
loc: {
start: {line: 1,column: 25},
end: {line: 1,column: 35}
}
},
loc: {
start: {line: 1,column: 25},
end: {line: 1,column: 36}
}
}
],
loc: {
start: {line: 1,column: 12},
end: {line: 1,column: 37}
} }
}, },
rest: null, "declarations": [
generator: false, {
expression: false, "type": "VariableDeclarator",
loc: { "start": 4,
start: {line: 1,column: 1}, "end": 9,
end: {line: 1,column: 37} "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"
}, },
loc: { {
start: {line: 1,column: 0}, "type": "AssignmentExpression",
end: {line: 1,column: 38} "start": 11,
"end": 21,
"loc": {
"start": {
"line": 1,
"column": 11
},
"end": {
"line": 1,
"column": 21
}
},
"operator": "=",
"left": {
"type": "Identifier",
"start": 11,
"end": 16,
"loc": {
"start": {
"line": 1,
"column": 11
},
"end": {
"line": 1,
"column": 16
}
},
"name": "async"
},
"right": {
"type": "Literal",
"start": 19,
"end": 21,
"loc": {
"start": {
"line": 1,
"column": 19
},
"end": {
"line": 1,
"column": 21
}
},
"value": 10,
"raw": "10"
}
} }
}] ]
}, { }, {
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});