455 lines
12 KiB
JavaScript
455 lines
12 KiB
JavaScript
/**
|
|
* Copyright (c) 2014, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* https://raw.github.com/facebook/regenerator/master/LICENSE file. An
|
|
* additional grant of patent rights can be found in the PATENTS file in
|
|
* the same directory.
|
|
*/
|
|
|
|
var iteratorSymbol = typeof Symbol === "function" && Symbol.iterator || "@@iterator";
|
|
var runtime = global.regeneratorRuntime = exports;
|
|
var hasOwn = Object.prototype.hasOwnProperty;
|
|
|
|
var wrap = runtime.wrap = function wrap(innerFn, outerFn, self, tryList) {
|
|
return new Generator(innerFn, outerFn, self || null, tryList || []);
|
|
};
|
|
|
|
var GenStateSuspendedStart = "suspendedStart";
|
|
var GenStateSuspendedYield = "suspendedYield";
|
|
var GenStateExecuting = "executing";
|
|
var GenStateCompleted = "completed";
|
|
|
|
// Returning this object from the innerFn has the same effect as
|
|
// breaking out of the dispatch switch statement.
|
|
var ContinueSentinel = {};
|
|
|
|
// Dummy constructor that we use as the .constructor property for
|
|
// functions that return Generator objects.
|
|
var GF = function GeneratorFunction() {};
|
|
var GFp = function GeneratorFunctionPrototype() {};
|
|
var Gp = GFp.prototype = Generator.prototype;
|
|
(GFp.constructor = GF).prototype =
|
|
Gp.constructor = GFp;
|
|
|
|
// Ensure isGeneratorFunction works when Function#name not supported.
|
|
var GFName = "GeneratorFunction";
|
|
if (GF.name !== GFName) GF.name = GFName;
|
|
if (GF.name !== GFName) throw new Error(GFName + " renamed?");
|
|
|
|
runtime.isGeneratorFunction = function (genFun) {
|
|
var ctor = genFun && genFun.constructor;
|
|
return ctor ? GF.name === ctor.name : false;
|
|
};
|
|
|
|
runtime.mark = function (genFun) {
|
|
genFun.__proto__ = GFp;
|
|
genFun.prototype = Object.create(Gp);
|
|
return genFun;
|
|
};
|
|
|
|
runtime.async = function (innerFn, outerFn, self, tryList) {
|
|
return new Promise(function (resolve, reject) {
|
|
var generator = wrap(innerFn, outerFn, self, tryList);
|
|
var callNext = step.bind(generator.next);
|
|
var callThrow = step.bind(generator["throw"]);
|
|
|
|
function step(arg) {
|
|
var info;
|
|
var value;
|
|
|
|
try {
|
|
info = this(arg);
|
|
value = info.value;
|
|
} catch (error) {
|
|
return reject(error);
|
|
}
|
|
|
|
if (info.done) {
|
|
resolve(value);
|
|
} else {
|
|
Promise.resolve(value).then(callNext, callThrow);
|
|
}
|
|
}
|
|
|
|
callNext();
|
|
});
|
|
};
|
|
|
|
function Generator(innerFn, outerFn, self, tryList) {
|
|
var generator = outerFn ? Object.create(outerFn.prototype) : this;
|
|
var context = new Context(tryList);
|
|
var state = GenStateSuspendedStart;
|
|
|
|
function invoke(method, arg) {
|
|
if (state === GenStateExecuting) {
|
|
throw new Error("Generator is already running");
|
|
}
|
|
|
|
if (state === GenStateCompleted) {
|
|
throw new Error("Generator has already finished");
|
|
}
|
|
|
|
while (true) {
|
|
var delegate = context.delegate;
|
|
var info;
|
|
|
|
if (delegate) {
|
|
try {
|
|
info = delegate.iterator[method](arg);
|
|
|
|
// Delegate generator ran and handled its own exceptions so
|
|
// regardless of what the method was, we continue as if it is
|
|
// "next" with an undefined arg.
|
|
method = "next";
|
|
arg = undefined;
|
|
|
|
} catch (uncaught) {
|
|
context.delegate = null;
|
|
|
|
// Like returning generator.throw(uncaught), but without the
|
|
// overhead of an extra function call.
|
|
method = "throw";
|
|
arg = uncaught;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (info.done) {
|
|
context[delegate.resultName] = info.value;
|
|
context.next = delegate.nextLoc;
|
|
} else {
|
|
state = GenStateSuspendedYield;
|
|
return info;
|
|
}
|
|
|
|
context.delegate = null;
|
|
}
|
|
|
|
if (method === "next") {
|
|
if (state === GenStateSuspendedStart &&
|
|
typeof arg !== "undefined") {
|
|
// https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume
|
|
throw new TypeError(
|
|
"attempt to send " + JSON.stringify(arg) + " to newborn generator"
|
|
);
|
|
}
|
|
|
|
if (state === GenStateSuspendedYield) {
|
|
context.sent = arg;
|
|
} else {
|
|
delete context.sent;
|
|
}
|
|
|
|
} else if (method === "throw") {
|
|
if (state === GenStateSuspendedStart) {
|
|
state = GenStateCompleted;
|
|
throw arg;
|
|
}
|
|
|
|
if (context.dispatchException(arg)) {
|
|
// If the dispatched exception was caught by a catch block,
|
|
// then let that catch block handle the exception normally.
|
|
method = "next";
|
|
arg = undefined;
|
|
}
|
|
|
|
} else if (method === "return") {
|
|
context.abrupt("return", arg);
|
|
}
|
|
|
|
state = GenStateExecuting;
|
|
|
|
try {
|
|
var value = innerFn.call(self, context);
|
|
|
|
// If an exception is thrown from innerFn, we leave state ===
|
|
// GenStateExecuting and loop back for another invocation.
|
|
state = context.done ? GenStateCompleted : GenStateSuspendedYield;
|
|
|
|
info = {
|
|
value: value,
|
|
done: context.done
|
|
};
|
|
|
|
if (value === ContinueSentinel) {
|
|
if (context.delegate && method === "next") {
|
|
// Deliberately forget the last sent value so that we don't
|
|
// accidentally pass it on to the delegate.
|
|
arg = undefined;
|
|
}
|
|
} else {
|
|
return info;
|
|
}
|
|
|
|
} catch (thrown) {
|
|
state = GenStateCompleted;
|
|
|
|
if (method === "next") {
|
|
context.dispatchException(thrown);
|
|
} else {
|
|
arg = thrown;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
generator.next = invoke.bind(generator, "next");
|
|
generator["throw"] = invoke.bind(generator, "throw");
|
|
generator["return"] = invoke.bind(generator, "return");
|
|
|
|
return generator;
|
|
}
|
|
|
|
Gp[iteratorSymbol] = function () {
|
|
return this;
|
|
};
|
|
|
|
Gp.toString = function () {
|
|
return "[object Generator]";
|
|
};
|
|
|
|
function pushTryEntry(triple) {
|
|
var entry = { tryLoc: triple[0] };
|
|
|
|
if (1 in triple) {
|
|
entry.catchLoc = triple[1];
|
|
}
|
|
|
|
if (2 in triple) {
|
|
entry.finallyLoc = triple[2];
|
|
}
|
|
|
|
this.tryEntries.push(entry);
|
|
}
|
|
|
|
function resetTryEntry(entry, i) {
|
|
var record = entry.completion || {};
|
|
record.type = i === 0 ? "normal" : "return";
|
|
delete record.arg;
|
|
entry.completion = record;
|
|
}
|
|
|
|
function Context(tryList) {
|
|
// The root entry object (effectively a try statement without a catch
|
|
// or a finally block) gives us a place to store values thrown from
|
|
// locations where there is no enclosing try statement.
|
|
this.tryEntries = [{ tryLoc: "root" }];
|
|
tryList.forEach(pushTryEntry, this);
|
|
this.reset();
|
|
}
|
|
|
|
runtime.keys = function (object) {
|
|
var keys = [];
|
|
for (var key in object) {
|
|
keys.push(key);
|
|
}
|
|
keys.reverse();
|
|
|
|
// Rather than returning an object with a next method, we keep
|
|
// things simple and return the next function itself.
|
|
return function next() {
|
|
while (keys.length) {
|
|
var key = keys.pop();
|
|
if (key in object) {
|
|
next.value = key;
|
|
next.done = false;
|
|
return next;
|
|
}
|
|
}
|
|
|
|
// To avoid creating an additional object, we just hang the .value
|
|
// and .done properties off the next function object itself. This
|
|
// also ensures that the minifier will not anonymize the function.
|
|
next.done = true;
|
|
return next;
|
|
};
|
|
};
|
|
|
|
function values(iterable) {
|
|
var iterator = iterable;
|
|
if (iteratorSymbol in iterable) {
|
|
iterator = iterable[iteratorSymbol]();
|
|
} else if (!isNaN(iterable.length)) {
|
|
var i = -1;
|
|
iterator = function next() {
|
|
while (++i < iterable.length) {
|
|
if (i in iterable) {
|
|
next.value = iterable[i];
|
|
next.done = false;
|
|
return next;
|
|
}
|
|
}
|
|
next.done = true;
|
|
return next;
|
|
};
|
|
iterator.next = iterator;
|
|
}
|
|
return iterator;
|
|
}
|
|
runtime.values = values;
|
|
|
|
Context.prototype = {
|
|
constructor: Context,
|
|
|
|
reset: function () {
|
|
this.prev = 0;
|
|
this.next = 0;
|
|
this.sent = undefined;
|
|
this.done = false;
|
|
this.delegate = null;
|
|
|
|
this.tryEntries.forEach(resetTryEntry);
|
|
|
|
// Pre-initialize at least 20 temporary variables to enable hidden
|
|
// class optimizations for simple generators.
|
|
for (var tempIndex = 0, tempName;
|
|
hasOwn.call(this, tempName = "t" + tempIndex) || tempIndex < 20;
|
|
++tempIndex) {
|
|
this[tempName] = null;
|
|
}
|
|
},
|
|
|
|
stop: function () {
|
|
this.done = true;
|
|
|
|
var rootEntry = this.tryEntries[0];
|
|
var rootRecord = rootEntry.completion;
|
|
if (rootRecord.type === "throw") {
|
|
throw rootRecord.arg;
|
|
}
|
|
|
|
return this.rval;
|
|
},
|
|
|
|
dispatchException: function (exception) {
|
|
if (this.done) {
|
|
throw exception;
|
|
}
|
|
|
|
var context = this;
|
|
function handle(loc, caught) {
|
|
record.type = "throw";
|
|
record.arg = exception;
|
|
context.next = loc;
|
|
return !!caught;
|
|
}
|
|
|
|
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
|
|
var entry = this.tryEntries[i];
|
|
var record = entry.completion;
|
|
|
|
if (entry.tryLoc === "root") {
|
|
// Exception thrown outside of any try block that could handle
|
|
// it, so set the completion value of the entire function to
|
|
// throw the exception.
|
|
return handle("end");
|
|
}
|
|
|
|
if (entry.tryLoc <= this.prev) {
|
|
var hasCatch = hasOwn.call(entry, "catchLoc");
|
|
var hasFinally = hasOwn.call(entry, "finallyLoc");
|
|
|
|
if (hasCatch && hasFinally) {
|
|
if (this.prev < entry.catchLoc) {
|
|
return handle(entry.catchLoc, true);
|
|
} else if (this.prev < entry.finallyLoc) {
|
|
return handle(entry.finallyLoc);
|
|
}
|
|
|
|
} else if (hasCatch) {
|
|
if (this.prev < entry.catchLoc) {
|
|
return handle(entry.catchLoc, true);
|
|
}
|
|
|
|
} else if (hasFinally) {
|
|
if (this.prev < entry.finallyLoc) {
|
|
return handle(entry.finallyLoc);
|
|
}
|
|
|
|
} else {
|
|
throw new Error("try statement without catch or finally");
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
_findFinallyEntry: function (finallyLoc) {
|
|
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
|
|
var entry = this.tryEntries[i];
|
|
if (entry.tryLoc <= this.prev &&
|
|
hasOwn.call(entry, "finallyLoc") && (
|
|
entry.finallyLoc === finallyLoc ||
|
|
this.prev < entry.finallyLoc)) {
|
|
return entry;
|
|
}
|
|
}
|
|
},
|
|
|
|
abrupt: function (type, arg) {
|
|
var entry = this._findFinallyEntry();
|
|
var record = entry ? entry.completion : {};
|
|
|
|
record.type = type;
|
|
record.arg = arg;
|
|
|
|
if (entry) {
|
|
this.next = entry.finallyLoc;
|
|
} else {
|
|
this.complete(record);
|
|
}
|
|
|
|
return ContinueSentinel;
|
|
},
|
|
|
|
complete: function (record) {
|
|
if (record.type === "throw") {
|
|
throw record.arg;
|
|
}
|
|
|
|
if (record.type === "break" || record.type === "continue") {
|
|
this.next = record.arg;
|
|
} else if (record.type === "return") {
|
|
this.rval = record.arg;
|
|
this.next = "end";
|
|
}
|
|
|
|
return ContinueSentinel;
|
|
},
|
|
|
|
finish: function (finallyLoc) {
|
|
var entry = this._findFinallyEntry(finallyLoc);
|
|
return this.complete(entry.completion);
|
|
},
|
|
|
|
"catch": function (tryLoc) {
|
|
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
|
|
var entry = this.tryEntries[i];
|
|
if (entry.tryLoc === tryLoc) {
|
|
var record = entry.completion;
|
|
var thrown;
|
|
if (record.type === "throw") {
|
|
thrown = record.arg;
|
|
resetTryEntry(entry, i);
|
|
}
|
|
return thrown;
|
|
}
|
|
}
|
|
|
|
// The context.catch method must only be called with a location
|
|
// argument that corresponds to a known catch block.
|
|
throw new Error("illegal catch attempt");
|
|
},
|
|
|
|
delegateYield: function (iterable, resultName, nextLoc) {
|
|
this.delegate = {
|
|
iterator: values(iterable),
|
|
resultName: resultName,
|
|
nextLoc: nextLoc
|
|
};
|
|
|
|
return ContinueSentinel;
|
|
}
|
|
};
|