Implement support for async generator functions and for-await statements

This commit is contained in:
zenparsing
2016-04-14 09:35:25 -04:00
committed by Henry Zhu
parent bf0e256c3a
commit 26e79c5433
44 changed files with 779 additions and 25 deletions

View File

@@ -61,6 +61,158 @@ helpers.jsx = template(`
})()
`);
helpers.asyncIterator = template(`
(function (iterable) {
if (typeof Symbol === "function") {
if (Symbol.asyncIterator) {
var method = iterable[Symbol.asyncIterator];
if (method != null) return method.call(iterable);
}
if (Symbol.iterator) {
return iterable[Symbol.iterator]();
}
}
throw new TypeError("Object is not async iterable");
})
`);
helpers.asyncGenerator = template(`
(function () {
function AwaitValue(value) {
this.value = value;
}
function AsyncGenerator(gen) {
var front, back;
function send(key, arg) {
return new Promise(function (resolve, reject) {
var request = {
key: key,
arg: arg,
resolve: resolve,
reject: reject,
next: null
};
if (back) {
back = back.next = request;
} else {
front = back = request;
resume(key, arg);
}
});
}
function resume(key, arg) {
try {
var result = gen[key](arg)
var value = result.value;
if (value instanceof AwaitValue) {
Promise.resolve(value.value).then(
function (arg) { resume("next", arg); },
function (arg) { resume("throw", arg); });
} else {
settle(result.done ? "return" : "normal", result.value);
}
} catch (err) {
settle("throw", err);
}
}
function settle(type, value) {
switch (type) {
case "return":
front.resolve({ value: value, done: true });
break;
case "throw":
front.reject(value);
break;
default:
front.resolve({ value: value, done: false });
break;
}
front = front.next;
if (front) {
resume(front.key, front.arg);
} else {
back = null;
}
}
this._invoke = send;
// Hide "return" method if generator return is not supported
if (typeof gen.return !== "function") {
this.return = undefined;
}
}
if (typeof Symbol === "function" && Symbol.asyncIterator) {
AsyncGenerator.prototype[Symbol.asyncIterator] = function () { return this; };
}
AsyncGenerator.prototype.next = function (arg) { return this._invoke("next", arg); };
AsyncGenerator.prototype.throw = function (arg) { return this._invoke("throw", arg); };
AsyncGenerator.prototype.return = function (arg) { return this._invoke("return", arg); };
return {
wrap: function (fn) {
return function () {
return new AsyncGenerator(fn.apply(this, arguments));
};
},
await: function (value) {
return new AwaitValue(value);
}
};
})()
`);
helpers.asyncGeneratorDelegate = template(`
(function (inner, awaitWrap) {
var iter = {}, waiting = false;
function pump(key, value) {
waiting = true;
value = new Promise(function (resolve) { resolve(inner[key](value)); });
return { done: false, value: awaitWrap(value) };
};
if (typeof Symbol === "function" && Symbol.iterator) {
iter[Symbol.iterator] = function () { return this; };
}
iter.next = function (value) {
if (waiting) {
waiting = false;
return value;
}
return pump("next", value);
};
if (typeof inner.throw === "function") {
iter.throw = function (value) {
if (waiting) {
waiting = false;
throw value;
}
return pump("throw", value);
};
}
if (typeof inner.return === "function") {
iter.return = function (value) {
return pump("return", value);
};
}
return iter;
})
`);
helpers.asyncToGenerator = template(`
(function (fn) {
return function () {
@@ -92,7 +244,6 @@ helpers.asyncToGenerator = template(`
})
`);
helpers.classCallCheck = template(`
(function (instance, Constructor) {
if (!(instance instanceof Constructor)) {