first cut of async/await (#2098)

- async arrow functions not yet supported


fixes #1789
This commit is contained in:
kzc
2017-06-14 18:15:48 -04:00
committed by Alex Lam S.L
parent 7cc03d4d40
commit 100e18305d
7 changed files with 310 additions and 18 deletions

View File

@@ -47,7 +47,7 @@
var KEYWORDS = 'break case catch class const continue debugger default delete do else export extends finally for function if in instanceof new return switch throw try typeof var let void while with import';
var KEYWORDS_ATOM = 'false null true';
var RESERVED_WORDS = 'enum implements interface package private protected public static super this ' + KEYWORDS_ATOM + " " + KEYWORDS;
var KEYWORDS_BEFORE_EXPRESSION = 'return new delete throw else case yield';
var KEYWORDS_BEFORE_EXPRESSION = 'return new delete throw else case yield await';
KEYWORDS = makePredicate(KEYWORDS);
RESERVED_WORDS = makePredicate(RESERVED_WORDS);
@@ -873,6 +873,7 @@ function parse($TEXT, options) {
prev : null,
peeked : null,
in_function : 0,
in_async : -1,
in_generator : -1,
in_directives : true,
in_loop : 0,
@@ -943,6 +944,10 @@ function parse($TEXT, options) {
return S.in_generator === S.in_function;
}
function is_in_async() {
return S.in_async === S.in_function;
}
function semicolon(optional) {
if (is("punc", ";")) next();
else if (!optional && !can_insert_semicolon()) unexpected();
@@ -999,6 +1004,11 @@ function parse($TEXT, options) {
return simple_statement();
case "name":
if (S.token.value == "async" && is_token(peek(), "keyword", "function")) {
next();
next();
return function_(AST_Defun, false, true);
}
return is_token(peek(), "punc", ":")
? labeled_statement()
: simple_statement();
@@ -1155,6 +1165,9 @@ function parse($TEXT, options) {
// Ecma-262, 12.1.1 Static Semantics: Early Errors
token_error(S.prev, "Yield cannot be used as label inside generators");
}
if (label.name === "await" && is_in_async()) {
token_error(S.prev, "await cannot be used as label inside async function");
}
if (find_if(function(l){ return l.name == label.name }, S.labels)) {
// ECMA-262, 12.12: An ECMAScript program is considered
// syntactically incorrect if it contains a
@@ -1285,13 +1298,14 @@ function parse($TEXT, options) {
});
};
var function_ = function(ctor, is_generator_property) {
var function_ = function(ctor, is_generator_property, is_async) {
if (is_generator_property && is_async) croak("generators cannot be async");
var start = S.token
var in_statement = ctor === AST_Defun;
var is_generator = is("operator", "*");
if (is_generator) {
next();
next();
}
var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null;
@@ -1299,11 +1313,12 @@ function parse($TEXT, options) {
unexpected();
var args = parameters();
var body = _function_body(true, is_generator || is_generator_property, name, args);
var body = _function_body(true, is_generator || is_generator_property, is_async, name, args);
return new ctor({
start : args.start,
end : body.end,
is_generator: is_generator,
async : is_async,
name : name,
argnames: args,
body : body
@@ -1624,13 +1639,16 @@ function parse($TEXT, options) {
return a;
}
function _function_body(block, generator, name, args) {
function _function_body(block, generator, is_async, name, args) {
var loop = S.in_loop;
var labels = S.labels;
var current_generator = S.in_generator;
var current_async = S.in_async;
++S.in_function;
if (generator)
S.in_generator = S.in_function;
if (is_async)
S.in_async = S.in_function;
if (block)
S.in_directives = true;
S.in_loop = 0;
@@ -1650,9 +1668,22 @@ function parse($TEXT, options) {
S.in_loop = loop;
S.labels = labels;
S.in_generator = current_generator;
S.in_async = current_async;
return a;
}
function _await_expression() {
// Previous token must be "await" and not be interpreted as an identifier
if (!is_in_async()) {
croak("Unexpected await expression outside async function",
S.prev.line, S.prev.col, S.prev.pos);
}
// the await expression is parsed as a unary expression in Babel
return new AST_Await({
expression : maybe_unary(true),
});
}
function _yield_expression() {
// Previous token must be keyword yield and not be interpret as an identifier
if (!is_in_generator()) {
@@ -1661,7 +1692,6 @@ function parse($TEXT, options) {
}
var star = false;
var has_expression = true;
var tmp;
// Attempt to get expression or star (and then the mandatory expression)
// behind yield on the same line.
@@ -1986,6 +2016,14 @@ function parse($TEXT, options) {
}
unexpected();
}
if (is("name", "async") && is_token(peek(), "keyword", "function")) {
next();
next();
var func = function_(AST_Function, false, true);
func.start = start;
func.end = prev();
return subscripts(func, allow_calls);
}
if (is("keyword", "function")) {
next();
var func = function_(AST_Function);
@@ -2067,8 +2105,8 @@ function parse($TEXT, options) {
});
});
var create_accessor = embed_tokens(function(is_generator) {
return function_(AST_Accessor, is_generator);
var create_accessor = embed_tokens(function(is_generator, is_async) {
return function_(AST_Accessor, is_generator, is_async);
});
var object_or_object_destructuring_ = embed_tokens(function() {
@@ -2184,6 +2222,7 @@ function parse($TEXT, options) {
}
return name;
}
var is_async = false;
var is_static = false;
var is_generator = false;
var property_token = start;
@@ -2192,6 +2231,11 @@ function parse($TEXT, options) {
property_token = S.token;
name = as_property_name();
}
if (name === "async" && !is("punc", "(")) {
is_async = true;
property_token = S.token;
name = as_property_name();
}
if (name === null) {
is_generator = true;
property_token = S.token;
@@ -2206,10 +2250,11 @@ function parse($TEXT, options) {
start : start,
static : is_static,
is_generator: is_generator,
async : is_async,
key : name,
quote : name instanceof AST_SymbolMethod ?
property_token.quote : undefined,
value : create_accessor(is_generator),
value : create_accessor(is_generator, is_async),
end : prev()
});
return node;
@@ -2574,6 +2619,14 @@ function parse($TEXT, options) {
var maybe_unary = function(allow_calls) {
var start = S.token;
if (start.type == "name" && start.value == "await") {
if (is_in_async()) {
next();
return _await_expression();
} else if (S.input.has_directive("use strict")) {
token_error(S.token, "Unexpected await identifier inside strict mode")
}
}
if (is("operator") && UNARY_PREFIX(start.value)) {
next();
handle_regexp();