diff --git a/.gitignore b/.gitignore index a5fd8ecfca..9516761f30 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,5 @@ dist /packages/babel-runtime/helpers/*.js /packages/babel-runtime/regenerator/*.js /packages/*/lib -!/packages/babel-plugin-transform-regenerator/lib _babel.github.io /tests/.browser-build.js diff --git a/packages/babel-browser/test/index.js b/packages/babel-browser/test/index.js deleted file mode 100644 index 2ebb76ce39..0000000000 --- a/packages/babel-browser/test/index.js +++ /dev/null @@ -1,12 +0,0 @@ -var vm = require("vm"); -var fs = require("fs"); - -var loc = __dirname + "/../dist/browser.js"; - -suite("browser", function () { - test("sanity check", function () { - if (fs.existsSync(loc)) { - require(loc); - } - }); -}); diff --git a/packages/babel-plugin-transform-regenerator/.gitignore b/packages/babel-plugin-transform-regenerator/.gitignore deleted file mode 100644 index 51641efe5b..0000000000 --- a/packages/babel-plugin-transform-regenerator/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -npm-debug.log -node_modules - -test/mocha.js -test/mocha.css - -test/tests.es5.js -test/async.es5.js -test/tests.browser.js - -.idea diff --git a/packages/babel-plugin-transform-regenerator/.test/async.es5.js b/packages/babel-plugin-transform-regenerator/.test/async.es5.js deleted file mode 100644 index 7285217adf..0000000000 --- a/packages/babel-plugin-transform-regenerator/.test/async.es5.js +++ /dev/null @@ -1,805 +0,0 @@ -/** - * 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 assert = require("assert"); - -describe("async functions and await expressions", function () { - Promise = require("promise"); - - describe("regeneratorRuntime", function () { - it("should be defined globally", function () { - var global = Function("return this")(); - assert.ok("regeneratorRuntime" in global); - assert.strictEqual(global.regeneratorRuntime, regeneratorRuntime); - }); - - it("should have a .wrap method", function () { - assert.strictEqual(typeof regeneratorRuntime.wrap, "function"); - }); - }); - - describe("Promise", function () { - it("should be defined globally", function () { - var global = Function("return this")(); - assert.ok("Promise" in global); - assert.strictEqual(global.Promise, Promise); - }); - - it("should be a function", function () { - assert.strictEqual(typeof Promise, "function"); - }); - }); - - describe("no-await async function", function () { - it("should return a Promise", function (done) { - var called = false; - - function noAwait(value) { - return regeneratorRuntime.async(function noAwait$(_context) { - while (1) switch (_context.prev = _context.next) { - case 0: - called = true; - return _context.abrupt("return", value); - - case 2: - case "end": - return _context.stop(); - } - }, null, this); - } - - var promise = noAwait("asdf"); - assert.strictEqual(called, true); - - promise.then(function (value) { - assert.strictEqual(called, true); - assert.strictEqual(value, "asdf"); - done(); - }).catch(done); - }); - }); - - describe("one-await async function", function () { - it("should finish asynchronously", function (done) { - var flag1 = false; - var flag2 = false; - - function oneAwait(value) { - var result; - return regeneratorRuntime.async(function oneAwait$(_context2) { - while (1) switch (_context2.prev = _context2.next) { - case 0: - flag1 = true; - _context2.next = 3; - return regeneratorRuntime.awrap(value); - - case 3: - result = _context2.sent; - - flag2 = true; - return _context2.abrupt("return", result); - - case 6: - case "end": - return _context2.stop(); - } - }, null, this); - } - - var promise = oneAwait("asdf"); - assert.strictEqual(flag1, true); - assert.strictEqual(flag2, false); - - promise.then(function (value) { - assert.strictEqual(flag2, true); - assert.strictEqual(value, "asdf"); - done(); - }).catch(done); - }); - }); - - describe("nested async function calls", function () { - it("should evaluate in the right order", function (done) { - var markers = []; - - function innerMost(marker) { - return regeneratorRuntime.async(function innerMost$(_context3) { - while (1) switch (_context3.prev = _context3.next) { - case 0: - markers.push(marker); - _context3.next = 3; - return regeneratorRuntime.awrap(marker); - - case 3: - return _context3.abrupt("return", _context3.sent); - - case 4: - case "end": - return _context3.stop(); - } - }, null, this); - } - - function inner(marker) { - return regeneratorRuntime.async(function inner$(_context4) { - while (1) switch (_context4.prev = _context4.next) { - case 0: - markers.push(marker); - - _context4.t0 = assert; - _context4.next = 4; - return regeneratorRuntime.awrap(innerMost(marker + 1)); - - case 4: - _context4.t1 = _context4.sent; - _context4.t2 = marker + 1; - - _context4.t0.strictEqual.call(_context4.t0, _context4.t1, _context4.t2); - - markers.push(marker + 2); - - _context4.t3 = assert; - _context4.next = 11; - return regeneratorRuntime.awrap(innerMost(marker + 3)); - - case 11: - _context4.t4 = _context4.sent; - _context4.t5 = marker + 3; - - _context4.t3.strictEqual.call(_context4.t3, _context4.t4, _context4.t5); - - markers.push(marker + 4); - - case 15: - case "end": - return _context4.stop(); - } - }, null, this); - } - - function outer() { - return regeneratorRuntime.async(function outer$(_context5) { - while (1) switch (_context5.prev = _context5.next) { - case 0: - markers.push(0); - _context5.next = 3; - return regeneratorRuntime.awrap(inner(1)); - - case 3: - markers.push(6); - _context5.next = 6; - return regeneratorRuntime.awrap(inner(7)); - - case 6: - markers.push(12); - - case 7: - case "end": - return _context5.stop(); - } - }, null, this); - } - - outer().then(function () { - var expected = []; - for (var i = 0; i <= 12; ++i) expected.push(i); - assert.deepEqual(markers, expected); - done(); - }).catch(done); - }); - }); - - describe("dependent promises", function () { - it("should be awaitable out of order", function (done) { - function outer(value) { - var resolved, p1, v2, v1; - return regeneratorRuntime.async(function outer$(_context6) { - while (1) switch (_context6.prev = _context6.next) { - case 0: - resolved = false; - p1 = new Promise(function (resolve) { - setTimeout(function () { - resolve(value + 1); - resolved = true; - }, 0); - }); - - assert.strictEqual(resolved, false); - - _context6.next = 5; - return regeneratorRuntime.awrap(p1.then(function (value) { - return value + 1; - })); - - case 5: - v2 = _context6.sent; - - assert.strictEqual(resolved, true); - - _context6.next = 9; - return regeneratorRuntime.awrap(p1); - - case 9: - v1 = _context6.sent; - return _context6.abrupt("return", [v1, v2]); - - case 11: - case "end": - return _context6.stop(); - } - }, null, this); - } - - outer(1).then(function (pair) { - assert.deepEqual(pair, [2, 3]); - done(); - }).catch(done); - }); - }); - - describe("rejected promises", function () { - it("should cause await expressions to throw", function (done) { - var error = new Error("rejected"); - - function f(arg) { - return regeneratorRuntime.async(function f$(_context7) { - while (1) switch (_context7.prev = _context7.next) { - case 0: - _context7.prev = 0; - _context7.next = 3; - return regeneratorRuntime.awrap(arg); - - case 3: - return _context7.abrupt("return", _context7.sent); - - case 6: - _context7.prev = 6; - _context7.t0 = _context7["catch"](0); - - assert.strictEqual(_context7.t0, error); - return _context7.abrupt("return", "did throw"); - - case 10: - case "end": - return _context7.stop(); - } - }, null, this, [[0, 6]]); - } - - Promise.all([f(Promise.reject(error)), f(Promise.resolve("did not throw"))]).then(function (results) { - assert.deepEqual(results, ["did throw", "did not throw"]); - done(); - }).catch(done); - }); - - it("should be returned by exceptional async functions", function (done) { - var error = new Error("rejected"); - - function e(arg) { - return regeneratorRuntime.async(function e$(_context8) { - while (1) switch (_context8.prev = _context8.next) { - case 0: - if (!arg) { - _context8.next = 2; - break; - } - - throw arg; - - case 2: - return _context8.abrupt("return", "did not throw"); - - case 3: - case "end": - return _context8.stop(); - } - }, null, this); - } - - function f(arg) { - return regeneratorRuntime.async(function f$(_context9) { - while (1) switch (_context9.prev = _context9.next) { - case 0: - _context9.next = 2; - return regeneratorRuntime.awrap(e(arg)); - - case 2: - return _context9.abrupt("return", _context9.sent); - - case 3: - case "end": - return _context9.stop(); - } - }, null, this); - } - - function g(arg) { - return regeneratorRuntime.async(function g$(_context10) { - while (1) switch (_context10.prev = _context10.next) { - case 0: - _context10.next = 2; - return regeneratorRuntime.awrap(f(arg)); - - case 2: - return _context10.abrupt("return", _context10.sent); - - case 3: - case "end": - return _context10.stop(); - } - }, null, this); - } - - function h(arg) { - return regeneratorRuntime.async(function h$(_context11) { - while (1) switch (_context11.prev = _context11.next) { - case 0: - _context11.next = 2; - return regeneratorRuntime.awrap(Promise.all([g(arg), Promise.resolve("dummy")])); - - case 2: - return _context11.abrupt("return", _context11.sent); - - case 3: - case "end": - return _context11.stop(); - } - }, null, this); - } - - Promise.all([h(error).then(function () { - done(new Error("should not have resolved")); - }, function (e) { - assert.strictEqual(e, error); - return "ok1"; - }), h(null).then(function (result) { - assert.deepEqual(result, ["did not throw", "dummy"]); - return "ok2"; - })]).then(function (results) { - assert.deepEqual(results, ["ok1", "ok2"]); - done(); - }).catch(done); - }); - - it("should propagate failure when returned", function () { - var rejection = new Error("rejection"); - - function f() { - return regeneratorRuntime.async(function f$(_context12) { - while (1) switch (_context12.prev = _context12.next) { - case 0: - return _context12.abrupt("return", new Promise(function (resolve, reject) { - reject(rejection); - })); - - case 1: - case "end": - return _context12.stop(); - } - }, null, this); - } - - return f().then(function (result) { - assert.ok(false, "should have been rejected"); - }, function (error) { - assert.strictEqual(error, rejection); - }); - }); - }); - - describe("async function expressions", function () { - it("should be allowed", function (done) { - (function _callee(arg) { - return regeneratorRuntime.async(function _callee$(_context13) { - while (1) switch (_context13.prev = _context13.next) { - case 0: - _context13.next = 2; - return regeneratorRuntime.awrap(arg); - - case 2: - return _context13.abrupt("return", _context13.sent); - - case 3: - case "end": - return _context13.stop(); - } - }, null, this); - })(Promise.resolve(1234)).then(function (value) { - assert.strictEqual(value, 1234); - done(); - }).catch(done); - }); - }); -}); - -describe("async generator functions", function () { - it("should return a working AsyncIterator", function () { - var _marked = [gen].map(regeneratorRuntime.mark); - - var markers = []; - - function gen(arg) { - var sent, result; - return regeneratorRuntime.async(function gen$(_context14) { - while (1) switch (_context14.prev = _context14.next) { - case 0: - markers.push(0); - _context14.next = 3; - return arg; - - case 3: - sent = _context14.sent; - - markers.push(1); - _context14.next = 7; - return regeneratorRuntime.awrap(sent); - - case 7: - result = _context14.sent; - - markers.push(2); - _context14.t0 = assert; - _context14.t1 = regeneratorRuntime; - _context14.next = 13; - return "second"; - - case 13: - _context14.t2 = _context14.sent; - _context14.next = 16; - return _context14.t1.awrap.call(_context14.t1, _context14.t2); - - case 16: - _context14.t3 = _context14.sent; - - _context14.t0.strictEqual.call(_context14.t0, _context14.t3, "sent after second"); - - markers.push(3); - return _context14.abrupt("return", result); - - case 20: - case "end": - return _context14.stop(); - } - }, _marked[0], this); - } - - var iter = gen("initial argument"); - assert.deepEqual(markers, []); - - var firstPromise = iter.next(); - assert.deepEqual(markers, [0]); - - return firstPromise.then(function (firstResult) { - assert.deepEqual(firstResult, { - value: "initial argument", - done: false - }); - - assert.deepEqual(markers, [0]); - - return iter.next(new Promise(function (resolve) { - setTimeout(resolve, 100); - }).then(function () { - assert.deepEqual(markers, [0, 1]); - return "will become final result"; - })); - }).then(function (secondResult) { - assert.deepEqual(secondResult, { - value: "second", - done: false - }); - - assert.deepEqual(markers, [0, 1, 2]); - - return iter.next("sent after second"); - }).then(function (finalResult) { - assert.deepEqual(markers, [0, 1, 2, 3]); - assert.deepEqual(finalResult, { - value: "will become final result", - done: true - }); - }); - }); - - it("should keep results in order", function () { - var _marked2 = [range].map(regeneratorRuntime.mark); - - function range(limit) { - var before, after, i; - return regeneratorRuntime.async(function range$(_context15) { - while (1) switch (_context15.prev = _context15.next) { - case 0: - before = []; - after = []; - i = 0; - - case 3: - if (!(i < limit)) { - _context15.next = 11; - break; - } - - before.push(i); - _context15.next = 7; - return i; - - case 7: - after.push(i); - - case 8: - ++i; - _context15.next = 3; - break; - - case 11: - assert.deepEqual(before, after); - return _context15.abrupt("return", before); - - case 13: - case "end": - return _context15.stop(); - } - }, _marked2[0], this); - } - - var limit = 10; - var iter = range(limit); - var promises = []; - var results = []; - - for (var i = 0; i < limit; ++i) { - var promise = iter.next(); - promises.push(promise); - - promise.then(function (result) { - assert.strictEqual(result.done, false); - results.push(result); - }); - } - - assert.deepEqual(results, []); - - return Promise.all(promises).then(function (promiseResults) { - assert.deepEqual(results, promiseResults); - - return iter.next(); - }).then(function (finalResult) { - assert.deepEqual(results.map(function (result) { - return result.value; - }), finalResult.value); - - assert.strictEqual(finalResult.done, true); - }); - }); - - it("should be able to handle many awaits", function () { - var _marked3 = [gen].map(regeneratorRuntime.mark); - - var awaitCount = 0; - - function countAwait(i) { - return Promise.resolve(i).then(function () { - ++awaitCount; - }); - } - - function gen(limit) { - var i; - return regeneratorRuntime.async(function gen$(_context16) { - while (1) switch (_context16.prev = _context16.next) { - case 0: - _context16.next = 2; - return regeneratorRuntime.awrap(countAwait(0)); - - case 2: - _context16.next = 4; - return 1; - - case 4: - _context16.next = 6; - return regeneratorRuntime.awrap(countAwait(2)); - - case 6: - _context16.next = 8; - return regeneratorRuntime.awrap(countAwait(3)); - - case 8: - _context16.next = 10; - return 4; - - case 10: - _context16.next = 12; - return regeneratorRuntime.awrap(countAwait(5)); - - case 12: - _context16.next = 14; - return regeneratorRuntime.awrap(countAwait(6)); - - case 14: - _context16.next = 16; - return regeneratorRuntime.awrap(countAwait(7)); - - case 16: - _context16.next = 18; - return 8; - - case 18: - i = 0; - - case 19: - if (!(i < limit)) { - _context16.next = 25; - break; - } - - _context16.next = 22; - return regeneratorRuntime.awrap(countAwait(i)); - - case 22: - ++i; - _context16.next = 19; - break; - - case 25: - return _context16.abrupt("return", "done"); - - case 26: - case "end": - return _context16.stop(); - } - }, _marked3[0], this); - } - - var iter = gen(100); - - return iter.next().then(function (result) { - assert.strictEqual(awaitCount, 1); - - assert.deepEqual(result, { - value: 1, - done: false - }); - - return iter.next(); - }).then(function (result) { - assert.strictEqual(awaitCount, 3); - - assert.deepEqual(result, { - value: 4, - done: false - }); - - return iter.next(); - }).then(function (result) { - assert.strictEqual(awaitCount, 6); - - assert.deepEqual(result, { - value: 8, - done: false - }); - - return iter.next(); - }).then(function (result) { - assert.strictEqual(awaitCount, 6 + 100); - - assert.deepEqual(result, { - value: "done", - done: true - }); - - return iter.next(); - }).then(function (result) { - assert.deepEqual(result, { - value: void 0, - done: true - }); - }); - }); - - it("should not propagate exceptions between iterations", function () { - var _marked4 = [gen].map(regeneratorRuntime.mark); - - function gen() { - return regeneratorRuntime.async(function gen$(_context17) { - while (1) switch (_context17.prev = _context17.next) { - case 0: - _context17.next = 2; - return 1; - - case 2: - _context17.next = 4; - return 2; - - case 4: - case "end": - return _context17.stop(); - } - }, _marked4[0], this); - } - - var iter = gen(); - - return iter.next().then(function (result) { - assert.deepEqual(result, { - value: 1, - done: false - }); - - return iter.throw(new Error("thrown from first yield")); - }).then(function () { - throw new Error("should have thrown"); - }, function (error) { - assert.strictEqual(error.message, "thrown from first yield"); - return iter.next(); - }).then(function (result) { - assert.deepEqual(result, { - value: void 0, - done: true - }); - }); - }); - - it("should allow yielding a rejected Promise", function () { - var _marked5 = [gen].map(regeneratorRuntime.mark); - - var yielded = new Error("yielded rejection"); - var returned = new Error("returned rejection"); - - function gen() { - return regeneratorRuntime.async(function gen$(_context18) { - while (1) switch (_context18.prev = _context18.next) { - case 0: - _context18.t0 = assert; - _context18.next = 3; - return Promise.reject(yielded); - - case 3: - _context18.t1 = _context18.sent; - - _context18.t0.strictEqual.call(_context18.t0, _context18.t1, "first sent"); - - _context18.t2 = assert; - _context18.next = 8; - return "middle"; - - case 8: - _context18.t3 = _context18.sent; - - _context18.t2.strictEqual.call(_context18.t2, _context18.t3, "second sent"); - - return _context18.abrupt("return", Promise.reject(returned)); - - case 11: - case "end": - return _context18.stop(); - } - }, _marked5[0], this); - } - - var iter = gen(); - - return iter.next().then(function (result) { - assert.ok(false, "should have yielded a rejected Promise"); - }, function (error) { - assert.strictEqual(error, yielded); - return iter.next("first sent"); - }).then(function (result) { - assert.deepEqual(result, { - value: "middle", - done: false - }); - return iter.next("second sent"); - }).then(function (result) { - assert.ok(false, "should have returned a rejected Promise"); - }, function (error) { - assert.strictEqual(error, returned); - }); - }); -}); \ No newline at end of file diff --git a/packages/babel-plugin-transform-regenerator/.test/index.html b/packages/babel-plugin-transform-regenerator/.test/index.html deleted file mode 100644 index ace946a498..0000000000 --- a/packages/babel-plugin-transform-regenerator/.test/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - Mocha - - - - - -
- - - - - - diff --git a/packages/babel-plugin-transform-regenerator/.test/nothing-to-transform.js b/packages/babel-plugin-transform-regenerator/.test/nothing-to-transform.js deleted file mode 100644 index 3ab38103d4..0000000000 --- a/packages/babel-plugin-transform-regenerator/.test/nothing-to-transform.js +++ /dev/null @@ -1,3 +0,0 @@ -function asdf() { - return "no generators or a-s-y-n-c functions to see here"; -} diff --git a/packages/babel-plugin-transform-regenerator/.test/run.js b/packages/babel-plugin-transform-regenerator/.test/run.js deleted file mode 100644 index a2c3419c19..0000000000 --- a/packages/babel-plugin-transform-regenerator/.test/run.js +++ /dev/null @@ -1,154 +0,0 @@ -/** - * 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 fs = require("fs"); -var path = require("path"); -var semver = require("semver"); -var spawn = require("child_process").spawn; -var regenerator = require("../main"); -var mochaDir = path.dirname(require.resolve("mocha")); - -function convert(es6File, es5File, callback) { - fs.readFile(es6File, "utf-8", function(err, es6) { - if (err) { - return callback(err); - } - - fs.writeFile(es5File, regenerator.compile(es6).code, callback); - }); -} - -function bundle(es5Files, browserFile, callback) { - var bundle = require("browserify")(); - es5Files.forEach(bundle.add, bundle); - bundle.bundle(function(err, src) { - if (err) { - return callback(err); - } - fs.writeFile(browserFile, src, callback); - }); -} - -var queue = []; -function enqueue(cmd, args, quiet) { - queue.push({ - cmd: cmd, - args: args || [], - quiet: !!quiet - }); -} - -function flush() { - var entry = queue.shift(); - if (entry) { - var cmd = entry.cmd; - if (typeof cmd === "function") { - cmd.apply(null, entry.args.concat(asyncCallback)); - } else { - spawn(cmd, entry.args, { - stdio: [ - process.stdin, - entry.quiet ? "ignore" : process.stdout, - process.stderr - ] - }).on("exit", asyncCallback); - } - } -} - -function asyncCallback(err) { - if (err) { - console.error("process exited abnormally:", err); - process.exit(typeof err === "number" ? err : -1); - } else { - process.nextTick(flush); - } -} - -function makeMochaCopyFunction(fileName) { - return function copy(callback) { - var src = path.join(mochaDir, fileName); - var dst = path.join(__dirname, fileName); - fs.unlink(dst, function() { - fs.symlink(src, dst, callback); - }); - }; -} - -if (semver.gte(process.version, "0.11.2")) { - enqueue("mocha", [ - "--harmony", - "--reporter", "spec", - "--require", "./runtime", - "./test/tests.es6.js" - ]); -} - -enqueue(convert, [ - "./test/tests.es6.js", - "./test/tests.es5.js" -]); - -enqueue(convert, [ - "./test/async.es6.js", - "./test/async.es5.js" -]); - -enqueue(makeMochaCopyFunction("mocha.js")); -enqueue(makeMochaCopyFunction("mocha.css")); - -// uglify-js does not work properly due to Node 0.11.7 bug. -// (https://github.com/joyent/node/issues/6235) -if (!semver.eq(process.version, "0.11.7")) { - try { - require.resolve("browserify"); // Throws if missing. - enqueue(bundle, [ - ["./runtime.js", - "./test/tests.es5.js", - "./test/async.es5.js"], - "./test/tests.browser.js" - ]); - } catch (ignored) { - console.error("browserify not installed; skipping bundle step"); - } -} - -enqueue("mocha", [ - "--reporter", "spec", - "--require", "./runtime", - "./test/tests.es5.js", - "./test/async.es5.js", - "./test/tests.transform.js" -]); - -// Run command-line tool with available options to make sure it works. - -enqueue("./bin/regenerator", [ - "./test/async.es5.js" -], true); - -enqueue("./bin/regenerator", [ - "--include-runtime", - "./test/async.es5.js" -], true); - -// Make sure we run the command-line tool on a file that does not need any -// transformation, too. - -enqueue("./bin/regenerator", [ - "./test/nothing-to-transform.js" -], true); - -enqueue("./bin/regenerator", [ - "--include-runtime", - "./test/nothing-to-transform.js" -], true); - -flush(); diff --git a/packages/babel-plugin-transform-regenerator/.test/tests.es5.js b/packages/babel-plugin-transform-regenerator/.test/tests.es5.js deleted file mode 100644 index 1d24a7cfca..0000000000 --- a/packages/babel-plugin-transform-regenerator/.test/tests.es5.js +++ /dev/null @@ -1,5262 +0,0 @@ -var _marked4 = [range].map(regeneratorRuntime.mark); - -/** - * 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 assert = require("assert"); -var runningInTranslation = /\.wrap\(/.test(regeneratorRuntime.mark(function _callee() { - return regeneratorRuntime.wrap(function _callee$(_context) { - while (1) switch (_context.prev = _context.next) { - case 0: - case "end": - return _context.stop(); - } - }, _callee, this); -})); -var iteratorSymbol = typeof Symbol === "function" && Symbol.iterator || "@@iterator"; - -function check(g, yields, returnValue) { - for (var i = 0; i < yields.length; ++i) { - var info = g.next(i); - assert.deepEqual(info.value, yields[i]); - assert.strictEqual(info.done, false); - } - - assert.deepEqual(i > 0 ? g.next(i) : g.next(), { value: returnValue, done: true }); -} - -// A version of `throw` whose behavior can't be statically analyzed. -// Useful for testing dynamic exception dispatching. -function raise(argument) { - throw argument; -} - -function assertAlreadyFinished(generator) { - assert.deepEqual(generator.next(), { - value: void 0, - done: true - }); -} - -describe("regeneratorRuntime", function () { - it("should be defined globally", function () { - var global = Function("return this")(); - assert.ok("regeneratorRuntime" in global); - assert.strictEqual(global.regeneratorRuntime, regeneratorRuntime); - }); - - it("should have a .wrap method", function () { - assert.strictEqual(typeof regeneratorRuntime.wrap, "function"); - }); - - it("should have a .mark method", function () { - assert.strictEqual(typeof regeneratorRuntime.mark, "function"); - }); - - it("should be the object name returned by util.runtimeProperty", function () { - assert.strictEqual(require("../lib/util").runtimeProperty("foo").object.name, "regeneratorRuntime"); - }); -}); - -(runningInTranslation ? describe : xdescribe)("@@iterator", function () { - it("is defined on Generator.prototype and returns this", function () { - var _marked = [gen].map(regeneratorRuntime.mark); - - function gen() { - return regeneratorRuntime.wrap(function gen$(_context2) { - while (1) switch (_context2.prev = _context2.next) { - case 0: - case "end": - return _context2.stop(); - } - }, _marked[0], this); - } - var iterator = gen(); - assert.ok(!iterator.hasOwnProperty(iteratorSymbol)); - assert.ok(!Object.getPrototypeOf(iterator).hasOwnProperty(iteratorSymbol)); - assert.ok(Object.getPrototypeOf(Object.getPrototypeOf(iterator)).hasOwnProperty(iteratorSymbol)); - assert.strictEqual(iterator[iteratorSymbol](), iterator); - }); -}); - -describe("simple argument yielder", function () { - it("should yield only its first argument", function () { - var _marked2 = [gen].map(regeneratorRuntime.mark); - - function gen(x) { - return regeneratorRuntime.wrap(function gen$(_context3) { - while (1) switch (_context3.prev = _context3.next) { - case 0: - _context3.next = 2; - return x; - - case 2: - case "end": - return _context3.stop(); - } - }, _marked2[0], this); - } - - check(gen("oyez"), ["oyez"]); - check(gen("foo", "bar"), ["foo"]); - }); - - it("should support multiple yields in expression", function () { - var _marked3 = [gen].map(regeneratorRuntime.mark); - - function gen() { - return regeneratorRuntime.wrap(function gen$(_context4) { - while (1) switch (_context4.prev = _context4.next) { - case 0: - _context4.next = 2; - return 0; - - case 2: - _context4.t0 = _context4.sent; - _context4.next = 5; - return 0; - - case 5: - _context4.t1 = _context4.sent; - return _context4.abrupt("return", _context4.t0 + _context4.t1); - - case 7: - case "end": - return _context4.stop(); - } - }, _marked3[0], this); - } - var itr = gen(); - itr.next(); - itr.next(1); - assert.equal(itr.next(2).value, 3); - }); -}); - -function range(n) { - var i; - return regeneratorRuntime.wrap(function range$(_context5) { - while (1) switch (_context5.prev = _context5.next) { - case 0: - i = 0; - - case 1: - if (!(i < n)) { - _context5.next = 7; - break; - } - - _context5.next = 4; - return i; - - case 4: - ++i; - _context5.next = 1; - break; - - case 7: - case "end": - return _context5.stop(); - } - }, _marked4[0], this); -} - -describe("range generator", function () { - it("should yield the empty range", function () { - check(range(0), []); - }); - - it("should yield the range 0..n-1", function () { - check(range(5), [0, 1, 2, 3, 4]); - }); -}); - -describe("collatz generator", function () { - var _marked5 = [gen].map(regeneratorRuntime.mark); - - function gen(n) { - var count; - return regeneratorRuntime.wrap(function gen$(_context6) { - while (1) switch (_context6.prev = _context6.next) { - case 0: - count = 0; - _context6.next = 3; - return n; - - case 3: - if (!(n !== 1)) { - _context6.next = 14; - break; - } - - count += 1; - - if (!(n % 2)) { - _context6.next = 10; - break; - } - - _context6.next = 8; - return n = n * 3 + 1; - - case 8: - _context6.next = 12; - break; - - case 10: - _context6.next = 12; - return n >>= 1; - - case 12: - _context6.next = 3; - break; - - case 14: - return _context6.abrupt("return", count); - - case 15: - case "end": - return _context6.stop(); - } - }, _marked5[0], this); - } - - function collatz(n) { - var result = [n]; - - while (n !== 1) { - if (n % 2) { - n *= 3; - n += 1; - } else { - n >>= 1; - } - - result.push(n); - } - - return result; - } - - var seven = collatz(7); - var fiftyTwo = seven.slice(seven.indexOf(52)); - var eightyTwo = collatz(82); - - it("seven", function () { - check(gen(7), seven, 16); - }); - - it("fifty two", function () { - check(gen(52), fiftyTwo, 11); - }); - - it("eighty two", function () { - check(gen(82), eightyTwo, 110); - }); -}); - -describe("throw", function () { - (runningInTranslation ? it : xit)("should complete generator", function () { - var _marked6 = [gen].map(regeneratorRuntime.mark); - - function gen(x) { - return regeneratorRuntime.wrap(function gen$(_context7) { - while (1) switch (_context7.prev = _context7.next) { - case 0: - throw 1; - - case 1: - case "end": - return _context7.stop(); - } - }, _marked6[0], this); - } - - var u = gen(); - - try { - u.next(); - } catch (err) { - assert.strictEqual(err, 1); - } - - assertAlreadyFinished(u); - }); -}); - -describe("try-catch generator", function () { - var _marked7 = [usingThrow, usingRaise].map(regeneratorRuntime.mark); - - function usingThrow(x) { - return regeneratorRuntime.wrap(function usingThrow$(_context8) { - while (1) switch (_context8.prev = _context8.next) { - case 0: - _context8.next = 2; - return 0; - - case 2: - _context8.prev = 2; - _context8.next = 5; - return 1; - - case 5: - if (!(x % 2 === 0)) { - _context8.next = 7; - break; - } - - throw 2; - - case 7: - _context8.next = 9; - return x; - - case 9: - _context8.next = 15; - break; - - case 11: - _context8.prev = 11; - _context8.t0 = _context8["catch"](2); - _context8.next = 15; - return _context8.t0; - - case 15: - _context8.next = 17; - return 3; - - case 17: - case "end": - return _context8.stop(); - } - }, _marked7[0], this, [[2, 11]]); - } - - function usingRaise(x) { - return regeneratorRuntime.wrap(function usingRaise$(_context9) { - while (1) switch (_context9.prev = _context9.next) { - case 0: - _context9.next = 2; - return 0; - - case 2: - _context9.prev = 2; - _context9.next = 5; - return 1; - - case 5: - if (x % 2 === 0) raise(2); - _context9.next = 8; - return x; - - case 8: - _context9.next = 14; - break; - - case 10: - _context9.prev = 10; - _context9.t0 = _context9["catch"](2); - _context9.next = 14; - return _context9.t0; - - case 14: - _context9.next = 16; - return 3; - - case 16: - case "end": - return _context9.stop(); - } - }, _marked7[1], this, [[2, 10]]); - } - - it("should catch static exceptions properly", function () { - check(usingThrow(4), [0, 1, 2, 3]); - check(usingThrow(5), [0, 1, 5, 3]); - }); - - it("should catch dynamic exceptions properly", function () { - check(usingRaise(4), [0, 1, 2, 3]); - check(usingRaise(5), [0, 1, 5, 3]); - }); -}); - -describe("nested generators in try-catch", function () { - var _marked8 = [gen].map(regeneratorRuntime.mark); - - function gen() { - return regeneratorRuntime.wrap(function gen$(_context11) { - while (1) switch (_context11.prev = _context11.next) { - case 0: - _context11.prev = 0; - - nonExistent; - _context11.next = 8; - break; - - case 4: - _context11.prev = 4; - _context11.t0 = _context11["catch"](0); - _context11.next = 8; - return regeneratorRuntime.mark(function _callee2() { - return regeneratorRuntime.wrap(function _callee2$(_context10) { - while (1) switch (_context10.prev = _context10.next) { - case 0: - _context10.next = 2; - return _context11.t0; - - case 2: - case "end": - return _context10.stop(); - } - }, _callee2, this); - }); - - case 8: - case "end": - return _context11.stop(); - } - }, _marked8[0], this, [[0, 4]]); - } - - it('should get a reference to the caught error', function () { - var genFun2 = gen().next().value; - assert.ok(regeneratorRuntime.isGeneratorFunction(genFun2)); - var gen2 = genFun2(); - var res = gen2.next(); - assert.ok(res.value instanceof ReferenceError); - // Note that we don't do strict equality over the message because it varies - // across browsers (if we ever want to run tests in browsers). - assert.ok(res.value.message.match(/nonExistent/)); - }); -}); - -describe("try-finally generator", function () { - var _marked9 = [usingThrow, usingRaise, usingAbrupt].map(regeneratorRuntime.mark); - - function usingThrow(condition) { - return regeneratorRuntime.wrap(function usingThrow$(_context12) { - while (1) switch (_context12.prev = _context12.next) { - case 0: - _context12.next = 2; - return 0; - - case 2: - _context12.prev = 2; - _context12.next = 5; - return 1; - - case 5: - throw 2; - - case 8: - _context12.prev = 8; - - if (!condition) { - _context12.next = 13; - break; - } - - _context12.next = 12; - return 4; - - case 12: - return _context12.abrupt("return", 5); - - case 13: - _context12.next = 15; - return 6; - - case 15: - return _context12.abrupt("return", 7); - - case 17: - case "end": - return _context12.stop(); - } - }, _marked9[0], this, [[2,, 8, 17]]); - } - - function usingRaise(condition) { - return regeneratorRuntime.wrap(function usingRaise$(_context13) { - while (1) switch (_context13.prev = _context13.next) { - case 0: - _context13.next = 2; - return 0; - - case 2: - _context13.prev = 2; - _context13.next = 5; - return 1; - - case 5: - raise(2); - _context13.next = 8; - return 3; - - case 8: - _context13.prev = 8; - - if (!condition) { - _context13.next = 13; - break; - } - - _context13.next = 12; - return 4; - - case 12: - return _context13.abrupt("return", 5); - - case 13: - _context13.next = 15; - return 6; - - case 15: - return _context13.abrupt("return", 7); - - case 17: - case "end": - return _context13.stop(); - } - }, _marked9[1], this, [[2,, 8, 17]]); - } - - function usingAbrupt(abruptType, finallyAbruptType) { - return regeneratorRuntime.wrap(function usingAbrupt$(_context14) { - while (1) switch (_context14.prev = _context14.next) { - case 0: - _context14.next = 2; - return 0; - - case 2: - _context14.prev = 2; - _context14.next = 5; - return 1; - - case 5: - if (!(abruptType === "return")) { - _context14.next = 9; - break; - } - - return _context14.abrupt("return", 2); - - case 9: - if (!(abruptType === "break")) { - _context14.next = 13; - break; - } - - return _context14.abrupt("break", 33); - - case 13: - if (!(abruptType === "continue")) { - _context14.next = 16; - break; - } - - abruptType = "return"; - return _context14.abrupt("continue", 31); - - case 16: - _context14.prev = 16; - _context14.next = 19; - return 3; - - case 19: - if (!(finallyAbruptType === "return")) { - _context14.next = 23; - break; - } - - return _context14.abrupt("return", 4); - - case 23: - if (!(finallyAbruptType === "break")) { - _context14.next = 27; - break; - } - - return _context14.abrupt("break", 33); - - case 27: - if (!(finallyAbruptType === "continue")) { - _context14.next = 30; - break; - } - - finallyAbruptType = null; - return _context14.abrupt("continue", 31); - - case 30: - return _context14.finish(16); - - case 31: - _context14.next = 2; - break; - - case 33: - return _context14.abrupt("return", 5); - - case 34: - case "end": - return _context14.stop(); - } - }, _marked9[2], this, [[2,, 16, 31]]); - } - - it("should honor return", function () { - check(usingAbrupt("return", null), [0, 1, 3], 2); - }); - - it("should honor break", function () { - check(usingAbrupt("break", null), [0, 1, 3], 5); - }); - - it("should honor continue", function () { - check(usingAbrupt("continue", null), [0, 1, 3, 1, 3], 2); - }); - - it("should override abrupt with return", function () { - check(usingAbrupt("return", "return"), [0, 1, 3], 4); - check(usingAbrupt("break", "return"), [0, 1, 3], 4); - check(usingAbrupt("continue", "return"), [0, 1, 3], 4); - }); - - it("should override abrupt with break", function () { - check(usingAbrupt("return", "break"), [0, 1, 3], 5); - check(usingAbrupt("break", "break"), [0, 1, 3], 5); - check(usingAbrupt("continue", "break"), [0, 1, 3], 5); - }); - - it("should override abrupt with continue", function () { - check(usingAbrupt("return", "continue"), [0, 1, 3, 1, 3], 2); - check(usingAbrupt("break", "continue"), [0, 1, 3, 1, 3], 5); - check(usingAbrupt("continue", "continue"), [0, 1, 3, 1, 3], 2); - }); - - it("should execute finally blocks statically", function () { - check(usingThrow(true), [0, 1, 4], 5); - check(usingThrow(false), [0, 1, 6], 7); - }); - - it("should execute finally blocks dynamically", function () { - check(usingRaise(true), [0, 1, 4], 5); - check(usingRaise(false), [0, 1, 6], 7); - }); - - it("should execute finally blocks before throwing", function () { - var _marked10 = [uncaught].map(regeneratorRuntime.mark); - - var uncaughtError = new Error("uncaught"); - - function uncaught(condition) { - return regeneratorRuntime.wrap(function uncaught$(_context15) { - while (1) switch (_context15.prev = _context15.next) { - case 0: - _context15.prev = 0; - _context15.next = 3; - return 0; - - case 3: - if (!condition) { - _context15.next = 7; - break; - } - - _context15.next = 6; - return 1; - - case 6: - raise(uncaughtError); - - case 7: - _context15.next = 9; - return 2; - - case 9: - _context15.prev = 9; - _context15.next = 12; - return 3; - - case 12: - return _context15.finish(9); - - case 13: - _context15.next = 15; - return 4; - - case 15: - case "end": - return _context15.stop(); - } - }, _marked10[0], this, [[0,, 9, 13]]); - } - - check(uncaught(false), [0, 2, 3, 4]); - - var u = uncaught(true); - - assert.deepEqual(u.next(), { value: 0, done: false }); - assert.deepEqual(u.next(), { value: 1, done: false }); - assert.deepEqual(u.next(), { value: 3, done: false }); - - try { - u.next(); - assert.ok(false, "should have thrown an exception"); - } catch (err) { - assert.strictEqual(err, uncaughtError); - } - }); - - it("should throw correct error when finally contains catch", function () { - var _marked11 = [gen].map(regeneratorRuntime.mark); - - var right = new Error("right"); - var wrong = new Error("wrong"); - - function gen() { - return regeneratorRuntime.wrap(function gen$(_context16) { - while (1) switch (_context16.prev = _context16.next) { - case 0: - _context16.prev = 0; - _context16.next = 3; - return 0; - - case 3: - raise(right); - - case 4: - _context16.prev = 4; - _context16.next = 7; - return 1; - - case 7: - _context16.prev = 7; - - raise(wrong); - _context16.next = 16; - break; - - case 11: - _context16.prev = 11; - _context16.t0 = _context16["catch"](7); - - assert.strictEqual(_context16.t0, wrong); - _context16.next = 16; - return 2; - - case 16: - return _context16.finish(4); - - case 17: - case "end": - return _context16.stop(); - } - }, _marked11[0], this, [[0,, 4, 17], [7, 11]]); - } - - var g = gen(); - - assert.deepEqual(g.next(), { - value: 0, - done: false - }); - - assert.deepEqual(g.next(), { - value: 1, - done: false - }); - - assert.deepEqual(g.next(), { - value: 2, - done: false - }); - - try { - g.next(); - assert.ok(false, "should have thrown an exception"); - } catch (err) { - assert.strictEqual(err, right); - } - }); - - it("should run finally after break within try", function () { - var _marked12 = [gen].map(regeneratorRuntime.mark); - - function gen() { - return regeneratorRuntime.wrap(function gen$(_context17) { - while (1) switch (_context17.prev = _context17.next) { - case 0: - _context17.prev = 0; - _context17.next = 3; - return 0; - - case 3: - if (!true) { - _context17.next = 9; - break; - } - - _context17.next = 6; - return 1; - - case 6: - return _context17.abrupt("break", 9); - - case 9: - _context17.prev = 9; - _context17.next = 12; - return 2; - - case 12: - return _context17.finish(9); - - case 13: - _context17.next = 15; - return 3; - - case 15: - case "end": - return _context17.stop(); - } - }, _marked12[0], this, [[0,, 9, 13]]); - } - - check(gen(), [0, 1, 2, 3]); - }); -}); - -describe("try-catch-finally generator", function () { - var _marked13 = [usingThrow, usingRaise].map(regeneratorRuntime.mark); - - function usingThrow() { - return regeneratorRuntime.wrap(function usingThrow$(_context18) { - while (1) switch (_context18.prev = _context18.next) { - case 0: - _context18.next = 2; - return 0; - - case 2: - _context18.prev = 2; - _context18.prev = 3; - _context18.next = 6; - return 1; - - case 6: - throw 2; - - case 9: - _context18.next = 16; - break; - - case 11: - _context18.prev = 11; - _context18.t0 = _context18["catch"](3); - _context18.next = 15; - return _context18.t0; - - case 15: - throw _context18.sent; - - case 16: - _context18.prev = 16; - _context18.next = 19; - return 5; - - case 19: - return _context18.finish(16); - - case 20: - _context18.next = 26; - break; - - case 22: - _context18.prev = 22; - _context18.t1 = _context18["catch"](2); - _context18.next = 26; - return _context18.t1; - - case 26: - _context18.next = 28; - return 6; - - case 28: - case "end": - return _context18.stop(); - } - }, _marked13[0], this, [[2, 22], [3, 11, 16, 20]]); - } - - function usingRaise() { - return regeneratorRuntime.wrap(function usingRaise$(_context19) { - while (1) switch (_context19.prev = _context19.next) { - case 0: - _context19.next = 2; - return 0; - - case 2: - _context19.prev = 2; - _context19.prev = 3; - _context19.next = 6; - return 1; - - case 6: - raise(2); - _context19.next = 9; - return 3; - - case 9: - _context19.next = 16; - break; - - case 11: - _context19.prev = 11; - _context19.t0 = _context19["catch"](3); - _context19.next = 15; - return _context19.t0; - - case 15: - throw _context19.sent; - - case 16: - _context19.prev = 16; - _context19.next = 19; - return 5; - - case 19: - return _context19.finish(16); - - case 20: - _context19.next = 26; - break; - - case 22: - _context19.prev = 22; - _context19.t1 = _context19["catch"](2); - _context19.next = 26; - return _context19.t1; - - case 26: - _context19.next = 28; - return 6; - - case 28: - case "end": - return _context19.stop(); - } - }, _marked13[1], this, [[2, 22], [3, 11, 16, 20]]); - } - - it("should statically catch and then finalize", function () { - check(usingThrow(), [0, 1, 2, 5, 3, 6]); - }); - - it("should dynamically catch and then finalize", function () { - check(usingRaise(), [0, 1, 2, 5, 3, 6]); - }); - - it("should execute catch and finally blocks at most once", function () { - var _marked14 = [gen].map(regeneratorRuntime.mark); - - var error = new Error(); - - function gen() { - return regeneratorRuntime.wrap(function gen$(_context20) { - while (1) switch (_context20.prev = _context20.next) { - case 0: - _context20.prev = 0; - _context20.t0 = 1; - _context20.next = _context20.t0 === 1 ? 4 : 7; - break; - - case 4: - _context20.next = 6; - return "a"; - - case 6: - return _context20.abrupt("break", 8); - - case 7: - return _context20.abrupt("break", 8); - - case 8: - throw error; - - case 11: - _context20.prev = 11; - _context20.t1 = _context20["catch"](0); - - assert.strictEqual(_context20.t1, error); - _context20.next = 16; - return "b"; - - case 16: - _context20.next = 18; - return "c"; - - case 18: - return _context20.abrupt("break", 20); - - case 19: - if (false) { - _context20.next = 16; - break; - } - - case 20: - _context20.next = 22; - return "d"; - - case 22: - return _context20.abrupt("break", 24); - - case 23: - if (false) { - _context20.next = 16; - break; - } - - case 24: - _context20.next = 26; - return "e"; - - case 26: - _context20.prev = 26; - _context20.next = 29; - return "f"; - - case 29: - return _context20.finish(26); - - case 30: - case "end": - return _context20.stop(); - } - }, _marked14[0], this, [[0, 11, 26, 30]]); - } - - check(gen(), ["a", "b", "c", "d", "e", "f"]); - }); - - it("should handle backwards jumps in labeled loops", function () { - var _marked15 = [gen].map(regeneratorRuntime.mark); - - function gen() { - var firstTime; - return regeneratorRuntime.wrap(function gen$(_context21) { - while (1) switch (_context21.prev = _context21.next) { - case 0: - firstTime = true; - - case 1: - if (!true) { - _context21.next = 31; - break; - } - - _context21.next = 4; - return 0; - - case 4: - _context21.prev = 4; - - case 5: - if (!true) { - _context21.next = 20; - break; - } - - _context21.next = 8; - return 1; - - case 8: - if (!firstTime) { - _context21.next = 15; - break; - } - - firstTime = false; - _context21.next = 12; - return 2; - - case 12: - return _context21.abrupt("continue", 1); - - case 15: - _context21.next = 17; - return 3; - - case 17: - return _context21.abrupt("break", 20); - - case 18: - _context21.next = 5; - break; - - case 20: - _context21.next = 22; - return 4; - - case 22: - return _context21.abrupt("break", 31); - - case 23: - _context21.prev = 23; - _context21.next = 26; - return 5; - - case 26: - return _context21.finish(23); - - case 27: - _context21.next = 29; - return 6; - - case 29: - _context21.next = 1; - break; - - case 31: - _context21.next = 33; - return 7; - - case 33: - case "end": - return _context21.stop(); - } - }, _marked15[0], this, [[4,, 23, 27]]); - } - - check(gen(), [0, 1, 2, 5, 0, 1, 3, 4, 5, 7]); - }); - - it("should handle loop continue statements properly", function () { - var _marked16 = [gen].map(regeneratorRuntime.mark); - - var error = new Error("thrown"); - var markers = []; - - function gen() { - var c; - return regeneratorRuntime.wrap(function gen$(_context22) { - while (1) switch (_context22.prev = _context22.next) { - case 0: - c = 2; - - case 1: - if (!(c > 0)) { - _context22.next = 20; - break; - } - - _context22.prev = 2; - - markers.push("try"); - _context22.next = 6; - return c; - - case 6: - _context22.next = 13; - break; - - case 8: - _context22.prev = 8; - _context22.t0 = _context22["catch"](2); - - assert.strictEqual(_context22.t0, error); - markers.push("catch"); - return _context22.abrupt("continue", 1); - - case 13: - _context22.prev = 13; - - markers.push("finally"); - return _context22.finish(13); - - case 16: - markers.push("decrement"); - --c; - _context22.next = 1; - break; - - case 20: - case "end": - return _context22.stop(); - } - }, _marked16[0], this, [[2, 8, 13, 16]]); - } - - var g = gen(); - - assert.deepEqual(g.next(), { value: 2, done: false }); - assert.deepEqual(g.throw(error), { value: 2, done: false }); - assert.deepEqual(g.next(), { value: 1, done: false }); - assert.deepEqual(g.next(), { value: void 0, done: true }); - - assert.deepEqual(markers, ["try", "catch", "finally", "try", "finally", "decrement", "try", "finally", "decrement"]); - }); -}); - -describe("dynamic exception", function () { - var _marked17 = [gen].map(regeneratorRuntime.mark); - - function gen(x, fname) { - return regeneratorRuntime.wrap(function gen$(_context23) { - while (1) switch (_context23.prev = _context23.next) { - case 0: - _context23.prev = 0; - return _context23.abrupt("return", fns[fname](x)); - - case 4: - _context23.prev = 4; - _context23.t0 = _context23["catch"](0); - _context23.next = 8; - return _context23.t0; - - case 8: - case "end": - return _context23.stop(); - } - }, _marked17[0], this, [[0, 4]]); - } - - var fns = { - f: function (x) { - throw x; - }, - - g: function (x) { - return x; - } - }; - - it("should be dispatched correctly", function () { - check(gen("asdf", "f"), ["asdf"]); - check(gen("asdf", "g"), [], "asdf"); - }); -}); - -describe("nested finally blocks", function () { - var _marked18 = [usingThrow, usingRaise].map(regeneratorRuntime.mark); - - function usingThrow() { - return regeneratorRuntime.wrap(function usingThrow$(_context24) { - while (1) switch (_context24.prev = _context24.next) { - case 0: - _context24.prev = 0; - _context24.prev = 1; - _context24.prev = 2; - throw "thrown"; - - case 4: - _context24.prev = 4; - _context24.next = 7; - return 1; - - case 7: - return _context24.finish(4); - - case 8: - _context24.next = 14; - break; - - case 10: - _context24.prev = 10; - _context24.t0 = _context24["catch"](1); - _context24.next = 14; - return _context24.t0; - - case 14: - _context24.prev = 14; - _context24.next = 17; - return 2; - - case 17: - return _context24.finish(14); - - case 18: - _context24.prev = 18; - _context24.next = 21; - return 3; - - case 21: - return _context24.finish(18); - - case 22: - case "end": - return _context24.stop(); - } - }, _marked18[0], this, [[0,, 18, 22], [1, 10, 14, 18], [2,, 4, 8]]); - } - - function usingRaise() { - return regeneratorRuntime.wrap(function usingRaise$(_context25) { - while (1) switch (_context25.prev = _context25.next) { - case 0: - _context25.prev = 0; - _context25.prev = 1; - _context25.prev = 2; - - raise("thrown"); - - case 4: - _context25.prev = 4; - _context25.next = 7; - return 1; - - case 7: - return _context25.finish(4); - - case 8: - _context25.next = 14; - break; - - case 10: - _context25.prev = 10; - _context25.t0 = _context25["catch"](1); - _context25.next = 14; - return _context25.t0; - - case 14: - _context25.prev = 14; - _context25.next = 17; - return 2; - - case 17: - return _context25.finish(14); - - case 18: - _context25.prev = 18; - _context25.next = 21; - return 3; - - case 21: - return _context25.finish(18); - - case 22: - case "end": - return _context25.stop(); - } - }, _marked18[1], this, [[0,, 18, 22], [1, 10, 14, 18], [2,, 4, 8]]); - } - - it("should statically execute in order", function () { - check(usingThrow(), [1, "thrown", 2, 3]); - }); - - it("should dynamically execute in order", function () { - check(usingRaise(), [1, "thrown", 2, 3]); - }); -}); - -describe("for-in loop generator", function () { - it("should handle the simple case", function () { - var _marked19 = [gen].map(regeneratorRuntime.mark); - - function gen() { - var count, obj, key; - return regeneratorRuntime.wrap(function gen$(_context26) { - while (1) switch (_context26.prev = _context26.next) { - case 0: - count = 0; - obj = { foo: 1, bar: 2 }; - _context26.t0 = regeneratorRuntime.keys(obj); - - case 3: - if ((_context26.t1 = _context26.t0()).done) { - _context26.next = 11; - break; - } - - key = _context26.t1.value; - - assert(obj.hasOwnProperty(key), key + " must be own property"); - _context26.next = 8; - return [key, obj[key]]; - - case 8: - count += 1; - _context26.next = 3; - break; - - case 11: - return _context26.abrupt("return", count); - - case 12: - case "end": - return _context26.stop(); - } - }, _marked19[0], this); - } - - check(gen(), [["foo", 1], ["bar", 2]], 2); - }); - - it("should handle break in loop", function () { - var _marked20 = [gen].map(regeneratorRuntime.mark); - - function gen(obj) { - var count, key; - return regeneratorRuntime.wrap(function gen$(_context27) { - while (1) switch (_context27.prev = _context27.next) { - case 0: - count = 0; - _context27.next = 3; - return "why not"; - - case 3: - _context27.t0 = regeneratorRuntime.keys(obj); - - case 4: - if ((_context27.t1 = _context27.t0()).done) { - _context27.next = 14; - break; - } - - key = _context27.t1.value; - - if (!obj.hasOwnProperty(key)) { - _context27.next = 12; - break; - } - - if (!(key === "skip")) { - _context27.next = 9; - break; - } - - return _context27.abrupt("break", 14); - - case 9: - count += 1; - _context27.next = 12; - return [key, obj[key]]; - - case 12: - _context27.next = 4; - break; - - case 14: - return _context27.abrupt("return", count); - - case 15: - case "end": - return _context27.stop(); - } - }, _marked20[0], this); - } - - check(gen({ a: 1, b: 2, skip: 3, c: 4 }), ["why not", ["a", 1], ["b", 2]], 2); - }); - - it("should handle property deletion in loop", function () { - var _marked21 = [gen].map(regeneratorRuntime.mark); - - function gen() { - var count, obj, key; - return regeneratorRuntime.wrap(function gen$(_context28) { - while (1) switch (_context28.prev = _context28.next) { - case 0: - count = 0; - obj = { foo: 1, bar: 2 }; - _context28.t0 = regeneratorRuntime.keys(obj); - - case 3: - if ((_context28.t1 = _context28.t0()).done) { - _context28.next = 12; - break; - } - - key = _context28.t1.value; - - assert(obj.hasOwnProperty(key), key + " must be own property"); - _context28.next = 8; - return [key, obj[key]]; - - case 8: - delete obj.bar; - count += 1; - _context28.next = 3; - break; - - case 12: - return _context28.abrupt("return", count); - - case 13: - case "end": - return _context28.stop(); - } - }, _marked21[0], this); - } - - check(gen(), [["foo", 1]], 1); - }); - - it("should loop over inherited properties", function () { - var _marked22 = [gen].map(regeneratorRuntime.mark); - - function gen() { - var count, Foo, foo, key; - return regeneratorRuntime.wrap(function gen$(_context29) { - while (1) switch (_context29.prev = _context29.next) { - case 0: - Foo = function Foo() { - this.baz = 1; - }; - - count = 0; - - Foo.prototype.bar = 2; - - foo = new Foo(); - _context29.t0 = regeneratorRuntime.keys(foo); - - case 5: - if ((_context29.t1 = _context29.t0()).done) { - _context29.next = 12; - break; - } - - key = _context29.t1.value; - _context29.next = 9; - return [key, foo[key]]; - - case 9: - count += 1; - _context29.next = 5; - break; - - case 12: - return _context29.abrupt("return", count); - - case 13: - case "end": - return _context29.stop(); - } - }, _marked22[0], this); - } - - check(gen(), [["baz", 1], ["bar", 2]], 2); - }); - - it("should handle risky object expressions", function () { - var _marked23 = [gen].map(regeneratorRuntime.mark); - - function a(sent) { - assert.strictEqual(sent, 1); - a.called = true; - } - - function b(sent) { - assert.strictEqual(sent, 2); - b.called = true; - return { callee: b }; - } - - function gen() { - var key; - return regeneratorRuntime.wrap(function gen$(_context30) { - while (1) switch (_context30.prev = _context30.next) { - case 0: - assert.ok(!a.called); - assert.ok(!b.called); - _context30.next = 4; - return 0; - - case 4: - _context30.t1 = _context30.sent; - a(_context30.t1); - _context30.next = 8; - return 1; - - case 8: - _context30.t2 = _context30.sent; - _context30.t0 = regeneratorRuntime.keys(b(_context30.t2)); - - case 10: - if ((_context30.t3 = _context30.t0()).done) { - _context30.next = 21; - break; - } - - key = _context30.t3.value; - - assert.ok(a.called); - assert.ok(b.called); - _context30.t4 = assert; - _context30.next = 17; - return key; - - case 17: - _context30.t5 = _context30.sent; - - _context30.t4.strictEqual.call(_context30.t4, _context30.t5, 3); - - _context30.next = 10; - break; - - case 21: - _context30.t6 = regeneratorRuntime.keys((a(1), { foo: "foo", bar: "bar" })); - - case 22: - if ((_context30.t7 = _context30.t6()).done) { - _context30.next = 28; - break; - } - - key = _context30.t7.value; - _context30.next = 26; - return key; - - case 26: - _context30.next = 22; - break; - - case 28: - case "end": - return _context30.stop(); - } - }, _marked23[0], this); - } - - check(gen(), [0, 1, "callee", "foo", "bar"]); - }); - - it("should allow non-Identifier left-hand expressions", function () { - var _marked24 = [gen].map(regeneratorRuntime.mark); - - var obj = {}; - var baz = { a: 1, b: 2, c: 3 }; - var markers = []; - - function foo() { - markers.push("called foo"); - return obj; - } - - function gen() { - return regeneratorRuntime.wrap(function gen$(_context31) { - while (1) switch (_context31.prev = _context31.next) { - case 0: - _context31.t0 = regeneratorRuntime.keys(baz); - - case 1: - if ((_context31.t1 = _context31.t0()).done) { - _context31.next = 8; - break; - } - - foo().bar = _context31.t1.value; - - markers.push(obj.bar); - _context31.next = 6; - return obj.bar; - - case 6: - _context31.next = 1; - break; - - case 8: - case "end": - return _context31.stop(); - } - }, _marked24[0], this); - } - - check(gen(), ["a", "b", "c"]); - - assert.deepEqual(markers, ["called foo", "a", "called foo", "b", "called foo", "c"]); - }); -}); - -describe("yield chain", function () { - var _marked25 = [gen].map(regeneratorRuntime.mark); - - function gen(n) { - return regeneratorRuntime.wrap(function gen$(_context32) { - while (1) switch (_context32.prev = _context32.next) { - case 0: - _context32.next = 2; - return n; - - case 2: - _context32.next = 4; - return _context32.sent; - - case 4: - _context32.next = 6; - return _context32.sent; - - case 6: - _context32.next = 8; - return _context32.sent; - - case 8: - return _context32.abrupt("return", _context32.sent); - - case 9: - case "end": - return _context32.stop(); - } - }, _marked25[0], this); - } - - it("should have correct associativity", function () { - check(gen(5), [5, 1, 2, 3], 4); - check(gen("asdf"), ["asdf", 1, 2, 3], 4); - }); -}); - -describe("object literal generator", function () { - var _marked26 = [gen].map(regeneratorRuntime.mark); - - function gen(a, b) { - return regeneratorRuntime.wrap(function gen$(_context33) { - while (1) switch (_context33.prev = _context33.next) { - case 0: - _context33.t0 = a; - _context33.next = 3; - return a; - - case 3: - _context33.t1 = _context33.sent; - _context33.t2 = _context33.t0 - _context33.t1; - _context33.next = 7; - return b; - - case 7: - _context33.t3 = _context33.sent; - _context33.next = 10; - return { - a: _context33.t2, - b: _context33.t3 - }; - - case 10: - case "end": - return _context33.stop(); - } - }, _marked26[0], this); - } - - it("should yield the correct object", function () { - check(gen(1, 2), [1, 2, { a: 0, b: 2 }]); - check(gen(4, 2), [4, 2, { a: 3, b: 2 }]); - }); -}); - -describe("switch statement generator", function () { - var _marked27 = [gen].map(regeneratorRuntime.mark); - - function gen(a) { - return regeneratorRuntime.wrap(function gen$(_context34) { - while (1) switch (_context34.prev = _context34.next) { - case 0: - _context34.next = 2; - return a; - - case 2: - _context34.t0 = _context34.sent; - _context34.t1 = _context34.t0; - _context34.next = 6; - return "x"; - - case 6: - _context34.t2 = _context34.sent; - _context34.t3 = a; - _context34.t4 = _context34.t2 - _context34.t3; - - if (!(_context34.t1 === _context34.t4)) { - _context34.next = 13; - break; - } - - _context34.t5 = 27; - _context34.next = 25; - break; - - case 13: - _context34.t6 = _context34.t0; - _context34.next = 16; - return "y"; - - case 16: - _context34.t7 = _context34.sent; - _context34.t8 = a; - _context34.t9 = _context34.t7 - _context34.t8; - - if (!(_context34.t6 === _context34.t9)) { - _context34.next = 23; - break; - } - - _context34.t10 = 28; - _context34.next = 24; - break; - - case 23: - _context34.t10 = 29; - - case 24: - _context34.t5 = _context34.t10; - - case 25: - _context34.next = _context34.t5; - break; - - case 27: - return _context34.abrupt("return", "first case"); - - case 28: - return _context34.abrupt("return", "second case"); - - case 29: - case "end": - return _context34.stop(); - } - }, _marked27[0], this); - } - - it("should jump to the correct cases", function () { - check(gen(1), [1, "x"], "first case"); - check(gen(2), [2, "x", "y"], "second case"); - }); -}); - -describe("infinite sequence generator", function () { - var _marked28 = [gen, limit].map(regeneratorRuntime.mark); - - function gen(start, step) { - return regeneratorRuntime.wrap(function gen$(_context35) { - while (1) switch (_context35.prev = _context35.next) { - case 0: - step = step || 1; - - case 1: - if (!true) { - _context35.next = 7; - break; - } - - _context35.next = 4; - return start; - - case 4: - start += step; - _context35.next = 1; - break; - - case 7: - case "end": - return _context35.stop(); - } - }, _marked28[0], this); - } - - function limit(g, stop) { - var info; - return regeneratorRuntime.wrap(function limit$(_context36) { - while (1) switch (_context36.prev = _context36.next) { - case 0: - if (!true) { - _context36.next = 14; - break; - } - - info = g.next(); - - if (!info.done) { - _context36.next = 6; - break; - } - - return _context36.abrupt("return"); - - case 6: - if (!(info.value < stop)) { - _context36.next = 11; - break; - } - - _context36.next = 9; - return info.value; - - case 9: - _context36.next = 12; - break; - - case 11: - return _context36.abrupt("return"); - - case 12: - _context36.next = 0; - break; - - case 14: - case "end": - return _context36.stop(); - } - }, _marked28[1], this); - } - - it("should generate a lot of plausible values", function () { - var g = gen(10, 2); - - assert.deepEqual(g.next(), { value: 10, done: false }); - assert.deepEqual(g.next(), { value: 12, done: false }); - assert.deepEqual(g.next(), { value: 14, done: false }); - assert.deepEqual(g.next(), { value: 16, done: false }); - - var sum = 10 + 12 + 14 + 16; - - for (var n = 0; n < 1000; ++n) { - var info = g.next(); - sum += info.value; - assert.strictEqual(info.done, false); - } - - assert.strictEqual(sum, 1017052); - }); - - it("should allow limiting", function () { - check(limit(gen(10, 3), 20), [10, 13, 16, 19]); - }); -}); - -describe("generator function expression", function () { - it("should behave just like a declared generator", function () { - check(regeneratorRuntime.mark(function _callee3(x, y) { - return regeneratorRuntime.wrap(function _callee3$(_context37) { - while (1) switch (_context37.prev = _context37.next) { - case 0: - _context37.next = 2; - return x; - - case 2: - _context37.next = 4; - return y; - - case 4: - _context37.next = 6; - return x + y; - - case 6: - return _context37.abrupt("return", x * y); - - case 7: - case "end": - return _context37.stop(); - } - }, _callee3, this); - })(3, 7), [3, 7, 10], 21); - }); -}); - -describe("generator reentry attempt", function () { - var _marked29 = [gen].map(regeneratorRuntime.mark); - - function gen(x) { - return regeneratorRuntime.wrap(function gen$(_context38) { - while (1) switch (_context38.prev = _context38.next) { - case 0: - _context38.prev = 0; - _context38.next = 3; - return x; - - case 3: - _context38.t0 = x; - - _context38.sent.next(_context38.t0); - - _context38.next = 11; - break; - - case 7: - _context38.prev = 7; - _context38.t1 = _context38["catch"](0); - _context38.next = 11; - return _context38.t1; - - case 11: - return _context38.abrupt("return", x + 1); - - case 12: - case "end": - return _context38.stop(); - } - }, _marked29[0], this, [[0, 7]]); - } - - it("should complain with a TypeError", function () { - var g = gen(3); - assert.deepEqual(g.next(), { value: 3, done: false }); - var complaint = g.next(g); // Sending the generator to itself. - assert.ok(complaint.value instanceof Error); - assert.strictEqual(complaint.value.message, "Generator is already running"); - assert.deepEqual(g.next(), { value: 4, done: true }); - }); -}); - -describe("completed generator", function () { - var _marked30 = [gen].map(regeneratorRuntime.mark); - - function gen() { - return regeneratorRuntime.wrap(function gen$(_context39) { - while (1) switch (_context39.prev = _context39.next) { - case 0: - return _context39.abrupt("return", "ALL DONE"); - - case 1: - case "end": - return _context39.stop(); - } - }, _marked30[0], this); - } - - (runningInTranslation ? it : xit)("should refuse to resume", function () { - var g = gen(); - - assert.deepEqual(g.next(), { - value: "ALL DONE", done: true - }); - - assertAlreadyFinished(g); - }); -}); - -describe("delegated yield", function () { - it("should delegate correctly", function () { - var _marked31 = [gen].map(regeneratorRuntime.mark); - - function gen(condition) { - return regeneratorRuntime.wrap(function gen$(_context40) { - while (1) switch (_context40.prev = _context40.next) { - case 0: - _context40.next = 2; - return 0; - - case 2: - if (!condition) { - _context40.next = 8; - break; - } - - _context40.next = 5; - return 1; - - case 5: - return _context40.delegateYield(gen(false), "t0", 6); - - case 6: - _context40.next = 8; - return 2; - - case 8: - _context40.next = 10; - return 3; - - case 10: - case "end": - return _context40.stop(); - } - }, _marked31[0], this); - } - - check(gen(true), [0, 1, 0, 3, 2, 3]); - check(gen(false), [0, 3]); - }); - - it("should cope with empty delegatees", function () { - var _marked32 = [gen].map(regeneratorRuntime.mark); - - function gen(condition) { - return regeneratorRuntime.wrap(function gen$(_context41) { - while (1) switch (_context41.prev = _context41.next) { - case 0: - if (!condition) { - _context41.next = 6; - break; - } - - _context41.next = 3; - return 0; - - case 3: - return _context41.delegateYield(gen(false), "t0", 4); - - case 4: - _context41.next = 6; - return 1; - - case 6: - case "end": - return _context41.stop(); - } - }, _marked32[0], this); - } - - check(gen(true), [0, 1]); - check(gen(false), []); - }); - - it("should support deeper nesting", function () { - var _marked33 = [outer, middle, inner].map(regeneratorRuntime.mark); - - function outer(n) { - return regeneratorRuntime.wrap(function outer$(_context42) { - while (1) switch (_context42.prev = _context42.next) { - case 0: - _context42.next = 2; - return n; - - case 2: - return _context42.delegateYield(middle(n - 1, inner(n + 10)), "t0", 3); - - case 3: - _context42.next = 5; - return n + 1; - - case 5: - case "end": - return _context42.stop(); - } - }, _marked33[0], this); - } - - function middle(n, plusTen) { - return regeneratorRuntime.wrap(function middle$(_context43) { - while (1) switch (_context43.prev = _context43.next) { - case 0: - _context43.next = 2; - return n; - - case 2: - return _context43.delegateYield(inner(n - 1), "t0", 3); - - case 3: - _context43.next = 5; - return n + 1; - - case 5: - return _context43.delegateYield(plusTen, "t1", 6); - - case 6: - case "end": - return _context43.stop(); - } - }, _marked33[1], this); - } - - function inner(n) { - return regeneratorRuntime.wrap(function inner$(_context44) { - while (1) switch (_context44.prev = _context44.next) { - case 0: - _context44.next = 2; - return n; - - case 2: - case "end": - return _context44.stop(); - } - }, _marked33[2], this); - } - - check(outer(5), [5, 4, 3, 5, 15, 6]); - }); - - it("should pass sent values through", function () { - var _marked34 = [outer, inner].map(regeneratorRuntime.mark); - - function outer(n) { - return regeneratorRuntime.wrap(function outer$(_context45) { - while (1) switch (_context45.prev = _context45.next) { - case 0: - return _context45.delegateYield(inner(n << 1), "t0", 1); - - case 1: - _context45.next = 3; - return "zxcv"; - - case 3: - case "end": - return _context45.stop(); - } - }, _marked34[0], this); - } - - function inner(n) { - return regeneratorRuntime.wrap(function inner$(_context46) { - while (1) switch (_context46.prev = _context46.next) { - case 0: - _context46.next = 2; - return n; - - case 2: - _context46.next = 4; - return _context46.sent; - - case 4: - _context46.next = 6; - return _context46.sent; - - case 6: - return _context46.abrupt("return", _context46.sent); - - case 7: - case "end": - return _context46.stop(); - } - }, _marked34[1], this); - } - - var g = outer(3); - assert.deepEqual(g.next(), { value: 6, done: false }); - assert.deepEqual(g.next(1), { value: 1, done: false }); - assert.deepEqual(g.next(2), { value: 2, done: false }); - assert.deepEqual(g.next(4), { value: "zxcv", done: false }); - assert.deepEqual(g.next(5), { value: void 0, done: true }); - }); - - it("should be governed by enclosing try statements", function () { - var _marked35 = [outer, inner].map(regeneratorRuntime.mark); - - var error = new Error("thrown"); - - function outer(n) { - return regeneratorRuntime.wrap(function outer$(_context47) { - while (1) switch (_context47.prev = _context47.next) { - case 0: - _context47.prev = 0; - _context47.next = 3; - return 0; - - case 3: - return _context47.delegateYield(inner(n), "t0", 4); - - case 4: - _context47.next = 6; - return 1; - - case 6: - _context47.next = 12; - break; - - case 8: - _context47.prev = 8; - _context47.t1 = _context47["catch"](0); - _context47.next = 12; - return _context47.t1.message; - - case 12: - _context47.next = 14; - return 4; - - case 14: - case "end": - return _context47.stop(); - } - }, _marked35[0], this, [[0, 8]]); - } - - function inner(n) { - return regeneratorRuntime.wrap(function inner$(_context48) { - while (1) switch (_context48.prev = _context48.next) { - case 0: - if (!(n-- > 0)) { - _context48.next = 9; - break; - } - - _context48.prev = 1; - - if (n === 3) { - raise(error); - } - - case 3: - _context48.prev = 3; - _context48.next = 6; - return n; - - case 6: - return _context48.finish(3); - - case 7: - _context48.next = 0; - break; - - case 9: - case "end": - return _context48.stop(); - } - }, _marked35[1], this, [[1,, 3, 7]]); - } - - check(outer(3), [0, 2, 1, 0, 1, 4]); - check(outer(5), [0, 4, 3, "thrown", 4]); - }); - - it("should dispatch .thrown exceptions correctly", function () { - var _marked36 = [gen, inner].map(regeneratorRuntime.mark); - - var count = 0; - - function gen() { - return regeneratorRuntime.wrap(function gen$(_context49) { - while (1) switch (_context49.prev = _context49.next) { - case 0: - return _context49.delegateYield(inner(), "t0", 1); - - case 1: - _context49.prev = 1; - return _context49.delegateYield(inner(), "t1", 3); - - case 3: - _context49.next = 7; - break; - - case 5: - _context49.prev = 5; - _context49.t2 = _context49["catch"](1); - - case 7: - return _context49.delegateYield(inner(), "t3", 8); - - case 8: - return _context49.abrupt("return", _context49.t3); - - case 9: - case "end": - return _context49.stop(); - } - }, _marked36[0], this, [[1, 5]]); - } - - function inner() { - return regeneratorRuntime.wrap(function inner$(_context50) { - while (1) switch (_context50.prev = _context50.next) { - case 0: - _context50.next = 2; - return count++; - - case 2: - return _context50.abrupt("return", _context50.sent); - - case 3: - case "end": - return _context50.stop(); - } - }, _marked36[1], this); - } - - var g = gen(); - - assert.deepEqual(g.next(), { - value: 0, - done: false - }); - - assert.deepEqual(g.next(), { - value: 1, - done: false - }); - - assert.deepEqual(g.throw(new Error("lol")), { - value: 2, - done: false - }); - - assert.deepEqual(g.next("sent"), { - value: "sent", - done: true - }); - }); - - it("should call .return methods of delegate iterators", function () { - var _marked37 = [gen].map(regeneratorRuntime.mark); - - var throwee = new Error("argument to gen.throw"); - var thrownFromThrow = new Error("thrown from throw method"); - var thrownFromReturn = new Error("thrown from return method"); - - function gen(delegate) { - return regeneratorRuntime.wrap(function gen$(_context51) { - while (1) switch (_context51.prev = _context51.next) { - case 0: - _context51.prev = 0; - return _context51.delegateYield(delegate, "t0", 2); - - case 2: - return _context51.abrupt("return", _context51.t0); - - case 5: - _context51.prev = 5; - _context51.t1 = _context51["catch"](0); - return _context51.abrupt("return", _context51.t1); - - case 8: - case "end": - return _context51.stop(); - } - }, _marked37[0], this, [[0, 5]]); - } - - function check(throwMethod, returnMethod) { - var throwCalled = false; - var returnCalled = false; - var count = 0; - var iterator = { - next: function () { - return { value: count++, done: false }; - } - }; - - iterator[iteratorSymbol] = function () { - return this; - }; - - if (throwMethod) { - iterator["throw"] = function () { - throwCalled = true; - return throwMethod.apply(this, arguments); - }; - } - - if (returnMethod) { - iterator["return"] = function () { - returnCalled = true; - return returnMethod.apply(this, arguments); - }; - } - - var g = gen(iterator); - - assert.deepEqual(g.next(), { value: 0, done: false }); - assert.deepEqual(g.next(), { value: 1, done: false }); - assert.deepEqual(g.next(), { value: 2, done: false }); - assert.deepEqual(g.next(), { value: 3, done: false }); - - assert.strictEqual(throwCalled, false); - assert.strictEqual(returnCalled, false); - - var result = {}; - - result.throwResult = g.throw(throwee); - result.throwCalled = throwCalled; - result.returnCalled = returnCalled; - - return result; - } - - var checkResult = check(undefined, function () { - throw thrownFromReturn; - }); - if (runningInTranslation) { - // BUG: Node v0.11 and v0.12 neglect to call .return here. - assert.strictEqual(checkResult.throwResult.value, thrownFromReturn); - } else { - // This is the TypeError that results from trying to call the - // undefined .throw method of the iterator. - assert.ok(checkResult.throwResult.value instanceof TypeError); - } - assert.strictEqual(checkResult.throwResult.done, true); - assert.strictEqual(checkResult.throwCalled, false); - // BUG: Node v0.11 and v0.12 neglect to call .return here. - assert.strictEqual(checkResult.returnCalled, runningInTranslation); - - checkResult = check(undefined, function () { - return { value: "from return", done: true }; - }); - assert.notStrictEqual(checkResult.throwResult.value, throwee); - // This is the TypeError that results from trying to call the - // undefined .throw method of the iterator. - assert.ok(checkResult.throwResult.value instanceof TypeError); - assert.strictEqual(checkResult.throwResult.done, true); - assert.strictEqual(checkResult.throwCalled, false); - // BUG: Node v0.11 and v0.12 neglect to call .return here. - assert.strictEqual(checkResult.returnCalled, runningInTranslation); - - var checkResult = check(function (thrown) { - return { value: "from throw", done: true }; - }, function () { - throw thrownFromReturn; - }); - assert.strictEqual(checkResult.throwResult.value, "from throw"); - assert.strictEqual(checkResult.throwResult.done, true); - assert.strictEqual(checkResult.throwCalled, true); - assert.strictEqual(checkResult.returnCalled, false); - - var checkResult = check(function (thrown) { - throw thrownFromThrow; - }, function () { - throw thrownFromReturn; - }); - assert.strictEqual(checkResult.throwResult.value, thrownFromThrow); - assert.strictEqual(checkResult.throwResult.done, true); - assert.strictEqual(checkResult.throwCalled, true); - assert.strictEqual(checkResult.returnCalled, false); - - var checkResult = check(undefined, undefined); - assert.notStrictEqual(checkResult.throwResult.value, throwee); - // This is the TypeError that results from trying to call the - // undefined .throw method of the iterator. - assert.ok(checkResult.throwResult.value instanceof TypeError); - assert.strictEqual(checkResult.throwResult.done, true); - assert.strictEqual(checkResult.throwCalled, false); - assert.strictEqual(checkResult.returnCalled, false); - }); - - it("should not be required to have a .return method", function () { - var _marked38 = [gen].map(regeneratorRuntime.mark); - - function gen(delegate) { - return regeneratorRuntime.wrap(function gen$(_context52) { - while (1) switch (_context52.prev = _context52.next) { - case 0: - return _context52.delegateYield(delegate, "t0", 1); - - case 1: - return _context52.abrupt("return", _context52.t0); - - case 2: - case "end": - return _context52.stop(); - } - }, _marked38[0], this); - } - - var inner = range(5); - var iterator = { next: inner.next.bind(inner) }; - iterator[iteratorSymbol] = function () { - return this; - }; - - var g = gen(iterator); - assert.deepEqual(g.next(), { value: 0, done: false }); - assert.deepEqual(g.next(), { value: 1, done: false }); - assert.deepEqual(g.next(), { value: 2, done: false }); - - if (typeof g.return === "function") { - assert.deepEqual(g.return(-1), { value: -1, done: true }); - assert.deepEqual(g.next(), { value: void 0, done: true }); - } - }); - - (runningInTranslation ? it : xit)("should support any iterable argument", function () { - var _marked39 = [gen, string].map(regeneratorRuntime.mark); - - function gen() { - return regeneratorRuntime.wrap(function gen$(_context53) { - while (1) switch (_context53.prev = _context53.next) { - case 0: - _context53.next = 2; - return 0; - - case 2: - _context53.next = 4; - return "one"; - - case 4: - _context53.t0 = _context53.sent; - _context53.next = 7; - return "two"; - - case 7: - _context53.t1 = _context53.sent; - _context53.next = 10; - return "three"; - - case 10: - _context53.t2 = _context53.sent; - return _context53.delegateYield([_context53.t0, _context53.t1, _context53.t2], "t3", 12); - - case 12: - _context53.next = 14; - return 5; - - case 14: - case "end": - return _context53.stop(); - } - }, _marked39[0], this); - } - - check(gen(), [0, "one", "two", "three", 2, 3, 4, 5]); - - function string() { - return regeneratorRuntime.wrap(function string$(_context54) { - while (1) switch (_context54.prev = _context54.next) { - case 0: - return _context54.delegateYield("asdf", "t0", 1); - - case 1: - return _context54.abrupt("return", _context54.t0); - - case 2: - case "end": - return _context54.stop(); - } - }, _marked39[1], this); - } - - check(string(), ["a", "s", "d", "f"]); - }); - - it("should evaluate to the return value of the delegate", function () { - var _marked40 = [inner, outer].map(regeneratorRuntime.mark); - - function inner() { - return regeneratorRuntime.wrap(function inner$(_context55) { - while (1) switch (_context55.prev = _context55.next) { - case 0: - _context55.next = 2; - return 1; - - case 2: - return _context55.abrupt("return", 2); - - case 3: - case "end": - return _context55.stop(); - } - }, _marked40[0], this); - } - - function outer(delegate) { - return regeneratorRuntime.wrap(function outer$(_context56) { - while (1) switch (_context56.prev = _context56.next) { - case 0: - return _context56.delegateYield(delegate, "t0", 1); - - case 1: - return _context56.abrupt("return", _context56.t0); - - case 2: - case "end": - return _context56.stop(); - } - }, _marked40[1], this); - } - - check(outer(inner()), [1], 2); - - var arrayDelegate = [3, 4]; - if (!runningInTranslation) { - // Node v0.11 doesn't know how to turn arrays into iterators over - // their elements without a little help. - arrayDelegate = regeneratorRuntime.values(arrayDelegate); - } - check(outer(arrayDelegate), [3, 4], void 0); // See issue #143. - - if (!runningInTranslation) { - return; - } - - check(outer({ - next: function () { - return { value: "oyez", done: true }; - } - }), [], "oyez"); - }); - - it("should work as a subexpression", function () { - var _marked41 = [inner, gen].map(regeneratorRuntime.mark); - - function inner(arg) { - return regeneratorRuntime.wrap(function inner$(_context57) { - while (1) switch (_context57.prev = _context57.next) { - case 0: - return _context57.abrupt("return", arg); - - case 1: - case "end": - return _context57.stop(); - } - }, _marked41[0], this); - } - - function gen(delegate) { - return regeneratorRuntime.wrap(function gen$(_context58) { - while (1) switch (_context58.prev = _context58.next) { - case 0: - return _context58.delegateYield(delegate, "t0", 1); - - case 1: - _context58.t1 = _context58.t0; - return _context58.abrupt("return", 1 + _context58.t1); - - case 3: - case "end": - return _context58.stop(); - } - }, _marked41[1], this); - } - - check(gen(inner(2)), [], 3); - check(gen(inner(3)), [], 4); - - if (!runningInTranslation) { - return; - } - - check(gen({ - next: function () { - return { value: "foo", done: true }; - } - }), [], "1foo"); - }); -}); - -describe("function declaration hoisting", function () { - it("should work even if the declarations are out of order", function () { - var _marked42 = [gen].map(regeneratorRuntime.mark); - - function gen(n) { - var increment, halve, decrement; - return regeneratorRuntime.wrap(function gen$(_context59) { - while (1) switch (_context59.prev = _context59.next) { - case 0: - increment = function increment(x) { - return x + 1; - }; - - _context59.next = 3; - return increment(n); - - case 3: - if (!(n % 2)) { - _context59.next = 10; - break; - } - - decrement = function decrement(x) { - return x - 1; - }; - - halve = function halve(x) { - return x >> 1; - }; - - _context59.next = 8; - return halve(decrement(n)); - - case 8: - _context59.next = 11; - break; - - case 10: - // The behavior of function declarations nested inside conditional - // blocks is notoriously underspecified, and in V8 it appears the - // halve function is still defined when we take this branch, so - // "undefine" it for consistency with regenerator semantics. - halve = void 0; - - case 11: - _context59.next = 13; - return typeof halve; - - case 13: - _context59.next = 15; - return increment(increment(n)); - - case 15: - case "end": - return _context59.stop(); - } - }, _marked42[0], this); - } - - check(gen(3), [4, 1, "function", 5]); - check(gen(4), [5, "undefined", 6]); - }); - - it("should work for nested generator function declarations", function () { - var _marked44 = [outer].map(regeneratorRuntime.mark); - - function outer(n) { - var _marked43, inner; - - return regeneratorRuntime.wrap(function outer$(_context61) { - while (1) switch (_context61.prev = _context61.next) { - case 0: - inner = function inner(n) { - return regeneratorRuntime.wrap(function inner$(_context60) { - while (1) switch (_context60.prev = _context60.next) { - case 0: - _context60.next = 2; - return n - 1; - - case 2: - _context60.next = 4; - return n; - - case 4: - _context60.next = 6; - return n + 1; - - case 6: - return _context60.abrupt("return", _context60.sent); - - case 7: - case "end": - return _context60.stop(); - } - }, _marked43[0], this); - }; - - _marked43 = [inner].map(regeneratorRuntime.mark); - _context61.next = 4; - return 0; - - case 4: - assert.ok(regeneratorRuntime.isGeneratorFunction(inner)); - return _context61.delegateYield(inner(n), "t0", 6); - - case 6: - return _context61.abrupt("return", _context61.t0); - - case 7: - case "end": - return _context61.stop(); - } - }, _marked44[0], this); - } - - check(outer(2), [0, 1, 2, 3], 4); - }); - - it("should not interfere with function rebinding", function () { - var _marked45 = [toBeRebound].map(regeneratorRuntime.mark); - - function rebindTo(value) { - var oldValue = toBeRebound; - toBeRebound = value; - return oldValue; - } - - function toBeRebound() { - var originalValue; - return regeneratorRuntime.wrap(function toBeRebound$(_context62) { - while (1) switch (_context62.prev = _context62.next) { - case 0: - originalValue = toBeRebound; - _context62.next = 3; - return toBeRebound; - - case 3: - assert.strictEqual(rebindTo(42), originalValue); - _context62.next = 6; - return toBeRebound; - - case 6: - assert.strictEqual(rebindTo("asdf"), 42); - _context62.next = 9; - return toBeRebound; - - case 9: - case "end": - return _context62.stop(); - } - }, _marked45[0], this); - } - - var original = toBeRebound; - check(toBeRebound(), [original, 42, "asdf"]); - - function attemptToRebind(value) { - var oldValue = safe; - safe = value; - return oldValue; - } - - var safe = regeneratorRuntime.mark(function safe() { - var originalValue; - return regeneratorRuntime.wrap(function safe$(_context63) { - while (1) switch (_context63.prev = _context63.next) { - case 0: - originalValue = safe; - _context63.next = 3; - return safe; - - case 3: - assert.strictEqual(attemptToRebind(42), originalValue); - _context63.next = 6; - return safe; - - case 6: - assert.strictEqual(attemptToRebind("asdf"), 42); - _context63.next = 9; - return safe; - - case 9: - case "end": - return _context63.stop(); - } - }, safe, this); - }); - - original = safe; - check(safe(), [safe, safe, safe]); - }); -}); - -describe("the arguments object", function () { - it("should work in simple variadic functions", function () { - var _marked46 = [sum].map(regeneratorRuntime.mark); - - function sum() { - var result, - i, - _args64 = arguments; - return regeneratorRuntime.wrap(function sum$(_context64) { - while (1) switch (_context64.prev = _context64.next) { - case 0: - result = 0; - i = 0; - - case 2: - if (!(i < _args64.length)) { - _context64.next = 8; - break; - } - - _context64.next = 5; - return result += _args64[i]; - - case 5: - ++i; - _context64.next = 2; - break; - - case 8: - return _context64.abrupt("return", result); - - case 9: - case "end": - return _context64.stop(); - } - }, _marked46[0], this); - } - - check(sum(1, 2, 3), [1, 3, 6], 6); - check(sum(9, -5, 3, 0, 2), [9, 4, 7, 7, 9], 9); - }); - - it("should alias function parameters", function () { - var _marked47 = [gen].map(regeneratorRuntime.mark); - - function gen(x, y) { - var temp, - _args65 = arguments; - return regeneratorRuntime.wrap(function gen$(_context65) { - while (1) switch (_context65.prev = _context65.next) { - case 0: - _context65.next = 2; - return x; - - case 2: - ++_args65[0]; - _context65.next = 5; - return x; - - case 5: - _context65.next = 7; - return y; - - case 7: - --_args65[1]; - _context65.next = 10; - return y; - - case 10: - temp = y; - - y = x; - x = temp; - - _context65.next = 15; - return x; - - case 15: - _context65.next = 17; - return y; - - case 17: - case "end": - return _context65.stop(); - } - }, _marked47[0], this); - } - - check(gen(3, 7), [3, 4, 7, 6, 6, 4]); - check(gen(10, -5), [10, 11, -5, -6, -6, 11]); - }); - - it("should be shadowable by explicit declarations", function () { - var _marked48 = [asParameter, asVariable].map(regeneratorRuntime.mark); - - function asParameter(x, arguments) { - var _args66 = arguments; - return regeneratorRuntime.wrap(function asParameter$(_context66) { - while (1) switch (_context66.prev = _context66.next) { - case 0: - _args66 = _args66 + 1; - _context66.next = 3; - return x + _args66; - - case 3: - case "end": - return _context66.stop(); - } - }, _marked48[0], this); - } - - check(asParameter(4, 5), [10]); - check(asParameter("asdf", "zxcv"), ["asdfzxcv1"]); - - function asVariable(x) { - var arguments, - _args67 = arguments; - return regeneratorRuntime.wrap(function asVariable$(_context67) { - while (1) switch (_context67.prev = _context67.next) { - case 0: - // TODO References to arguments before the variable declaration - // seem to see the object instead of the undefined value. - _args67 = x + 1; - _context67.next = 3; - return _args67; - - case 3: - case "end": - return _context67.stop(); - } - }, _marked48[1], this); - } - - check(asVariable(4), [5]); - check(asVariable("asdf"), ["asdf1"]); - }); - - it("should not get confused by properties", function () { - var _marked49 = [gen].map(regeneratorRuntime.mark); - - function gen(args) { - var obj; - return regeneratorRuntime.wrap(function gen$(_context68) { - while (1) switch (_context68.prev = _context68.next) { - case 0: - obj = { arguments: args }; - _context68.next = 3; - return obj.arguments; - - case 3: - obj.arguments = "oyez"; - _context68.next = 6; - return obj; - - case 6: - case "end": - return _context68.stop(); - } - }, _marked49[0], this); - } - - check(gen(42), [42, { arguments: "oyez" }]); - }); - - it("supports .callee", function () { - var _marked50 = [gen].map(regeneratorRuntime.mark); - - function gen(doYield) { - var _args69 = arguments; - return regeneratorRuntime.wrap(function gen$(_context69) { - while (1) switch (_context69.prev = _context69.next) { - case 0: - _context69.next = 2; - return 1; - - case 2: - if (!doYield) { - _context69.next = 7; - break; - } - - _context69.next = 5; - return 2; - - case 5: - _context69.next = 12; - break; - - case 7: - _context69.next = 9; - return 3; - - case 9: - return _context69.delegateYield(_args69.callee(true), "t0", 10); - - case 10: - _context69.next = 12; - return 4; - - case 12: - _context69.next = 14; - return 5; - - case 14: - case "end": - return _context69.stop(); - } - }, _marked50[0], this); - } - - check(gen(false), [1, 3, 1, 2, 5, 4, 5]); - }); -}); - -describe("catch parameter shadowing", function () { - it("should leave outer variables unmodified", function () { - var _marked51 = [gen].map(regeneratorRuntime.mark); - - function gen(x) { - var y; - return regeneratorRuntime.wrap(function gen$(_context70) { - while (1) switch (_context70.prev = _context70.next) { - case 0: - y = x + 1; - _context70.prev = 1; - throw x + 2; - - case 5: - _context70.prev = 5; - _context70.t0 = _context70["catch"](1); - _context70.next = 9; - return _context70.t0; - - case 9: - _context70.t0 += 1; - _context70.next = 12; - return _context70.t0; - - case 12: - _context70.next = 14; - return x; - - case 14: - _context70.prev = 14; - throw x + 3; - - case 18: - _context70.prev = 18; - _context70.t1 = _context70["catch"](14); - _context70.next = 22; - return _context70.t1; - - case 22: - _context70.t1 *= 2; - _context70.next = 25; - return _context70.t1; - - case 25: - _context70.next = 27; - return y; - - case 27: - case "end": - return _context70.stop(); - } - }, _marked51[0], this, [[1, 5], [14, 18]]); - } - - check(gen(1), [3, 4, 1, 4, 8, 2]); - check(gen(2), [4, 5, 2, 5, 10, 3]); - }); - - it("should not replace variables defined in inner scopes", function () { - var _marked52 = [gen].map(regeneratorRuntime.mark); - - function gen(x) { - return regeneratorRuntime.wrap(function gen$(_context71) { - while (1) switch (_context71.prev = _context71.next) { - case 0: - _context71.prev = 0; - throw x; - - case 4: - _context71.prev = 4; - _context71.t0 = _context71["catch"](0); - _context71.next = 8; - return _context71.t0; - - case 8: - _context71.next = 10; - return (function (x) { - return x += 1; - })(_context71.t0 + 1); - - case 10: - _context71.next = 12; - return (function () { - var x = arguments[0]; - return x * 2; - })(_context71.t0 + 2); - - case 12: - _context71.next = 14; - return (function () { - function notCalled(x) { - throw x; - } - - _context71.t0 >>= 1; - return _context71.t0; - })(); - - case 14: - _context71.next = 16; - return _context71.t0 -= 1; - - case 16: - _context71.next = 18; - return x; - - case 18: - case "end": - return _context71.stop(); - } - }, _marked52[0], this, [[0, 4]]); - } - - check(gen(10), [10, 12, 24, 5, 4, 10]); - check(gen(11), [11, 13, 26, 5, 4, 11]); - }); - - it("should allow nested catch parameters of the same name", function () { - var _marked53 = [gen].map(regeneratorRuntime.mark); - - function gen() { - return regeneratorRuntime.wrap(function gen$(_context72) { - while (1) switch (_context72.prev = _context72.next) { - case 0: - _context72.prev = 0; - - raise("e1"); - _context72.next = 18; - break; - - case 4: - _context72.prev = 4; - _context72.t0 = _context72["catch"](0); - _context72.next = 8; - return _context72.t0; - - case 8: - _context72.prev = 8; - - raise("e2"); - _context72.next = 16; - break; - - case 12: - _context72.prev = 12; - _context72.t1 = _context72["catch"](8); - _context72.next = 16; - return _context72.t1; - - case 16: - _context72.next = 18; - return _context72.t0; - - case 18: - case "end": - return _context72.stop(); - } - }, _marked53[0], this, [[0, 4], [8, 12]]); - } - - check(gen(), ["e1", "e2", "e1"]); - }); - - it("should not interfere with non-referential identifiers", function () { - var _marked54 = [gen].map(regeneratorRuntime.mark); - - function gen() { - return regeneratorRuntime.wrap(function gen$(_context73) { - while (1) switch (_context73.prev = _context73.next) { - case 0: - _context73.prev = 0; - _context73.next = 3; - return 1; - - case 3: - raise(new Error("oyez")); - _context73.next = 6; - return 2; - - case 6: - _context73.next = 15; - break; - - case 8: - _context73.prev = 8; - _context73.t0 = _context73["catch"](0); - _context73.next = 12; - return 3; - - case 12: - _context73.t0.e = "e.e"; - _context73.t0[_context73.t0.message] = "e.oyez"; - return _context73.abrupt("return", { - e: _context73.t0, - identity: function (x) { - var e = x; - return e; - } - }); - - case 15: - _context73.next = 17; - return 4; - - case 17: - case "end": - return _context73.stop(); - } - }, _marked54[0], this, [[0, 8]]); - } - - var g = gen(); - assert.deepEqual(g.next(), { value: 1, done: false }); - assert.deepEqual(g.next(), { value: 3, done: false }); - - var info = g.next(); - assert.strictEqual(info.done, true); - assert.strictEqual(info.value.e.message, "oyez"); - assert.strictEqual(info.value.e.e, "e.e"); - assert.strictEqual(info.value.e.oyez, "e.oyez"); - assert.strictEqual(info.value.identity("same"), "same"); - }); -}); - -describe("empty while loops", function () { - it("should be preserved in generated code", function () { - var _marked55 = [gen].map(regeneratorRuntime.mark); - - function gen(x) { - return regeneratorRuntime.wrap(function gen$(_context74) { - while (1) switch (_context74.prev = _context74.next) { - case 0: - while (x) { - // empty while loop - } - - do { - // empty do-while loop - } while (x); - - return _context74.abrupt("return", gen.toString()); - - case 3: - case "end": - return _context74.stop(); - } - }, _marked55[0], this); - } - - var info = gen(false).next(); - assert.strictEqual(info.done, true); - assert.ok(/empty while loop/.test(info.value)); - assert.ok(/empty do-while loop/.test(info.value)); - }); -}); - -describe("object literals with multiple yields", function () { - it("should receive different sent values", function () { - var _marked56 = [gen].map(regeneratorRuntime.mark); - - function gen(fn) { - return regeneratorRuntime.wrap(function gen$(_context75) { - while (1) switch (_context75.prev = _context75.next) { - case 0: - _context75.next = 2; - return "a"; - - case 2: - _context75.t0 = _context75.sent; - _context75.next = 5; - return "b"; - - case 5: - _context75.t1 = _context75.sent; - _context75.next = 8; - return "c"; - - case 8: - _context75.t2 = _context75.sent; - _context75.next = 11; - return "d"; - - case 11: - _context75.t3 = _context75.sent; - _context75.t4 = fn(_context75.t2, _context75.t3); - _context75.next = 15; - return "e"; - - case 15: - _context75.t5 = _context75.sent; - _context75.next = 18; - return "f"; - - case 18: - _context75.t6 = _context75.sent; - _context75.t7 = [_context75.t5, _context75.t6]; - return _context75.abrupt("return", { - a: _context75.t0, - b: _context75.t1, - c: _context75.t4, - d: _context75.t7 - }); - - case 21: - case "end": - return _context75.stop(); - } - }, _marked56[0], this); - } - - check(gen(function sum(x, y) { - return x + y; - }), ["a", "b", "c", "d", "e", "f"], { - a: 1, - b: 2, - c: 3 + 4, - d: [5, 6] - }); - }); -}); - -describe("generator .throw method", function () { - (runningInTranslation ? it : xit)("should complete generator", function () { - var _marked57 = [gen].map(regeneratorRuntime.mark); - - function gen(x) { - return regeneratorRuntime.wrap(function gen$(_context76) { - while (1) switch (_context76.prev = _context76.next) { - case 0: - _context76.next = 2; - return 2; - - case 2: - throw 1; - - case 3: - case "end": - return _context76.stop(); - } - }, _marked57[0], this); - } - - var u = gen(); - - u.next(); - - try { - u.throw(2); - } catch (err) { - assert.strictEqual(err, 2); - } - - assertAlreadyFinished(u); - }); - - it("should work after the final call to .next", function () { - var _marked58 = [gen].map(regeneratorRuntime.mark); - - function gen() { - return regeneratorRuntime.wrap(function gen$(_context77) { - while (1) switch (_context77.prev = _context77.next) { - case 0: - _context77.next = 2; - return 1; - - case 2: - case "end": - return _context77.stop(); - } - }, _marked58[0], this); - } - - var g = gen(); - assert.deepEqual(g.next(), { value: 1, done: false }); - - var exception = new Error("unhandled exception"); - try { - g.throw(exception); - assert.ok(false, "should have thrown an exception"); - } catch (err) { - assert.strictEqual(err, exception); - } - }); - - it("should immediately complete a new-born generator", function () { - var _marked59 = [gen].map(regeneratorRuntime.mark); - - var began = false; - - function gen() { - return regeneratorRuntime.wrap(function gen$(_context78) { - while (1) switch (_context78.prev = _context78.next) { - case 0: - began = true; - _context78.next = 3; - return 1; - - case 3: - case "end": - return _context78.stop(); - } - }, _marked59[0], this); - } - - var g = gen(); - var exception = new Error("unhandled exception"); - try { - g.throw(exception); - assert.ok(false, "should have thrown an exception"); - } catch (err) { - assert.strictEqual(err, exception); - assert.strictEqual(began, false); - } - }); - - it("should not propagate errors handled inside a delegate", function () { - var _marked60 = [outer, inner].map(regeneratorRuntime.mark); - - function outer() { - return regeneratorRuntime.wrap(function outer$(_context79) { - while (1) switch (_context79.prev = _context79.next) { - case 0: - _context79.prev = 0; - return _context79.delegateYield(inner(), "t0", 2); - - case 2: - _context79.next = 7; - break; - - case 4: - _context79.prev = 4; - _context79.t1 = _context79["catch"](0); - return _context79.abrupt("return", -1); - - case 7: - return _context79.abrupt("return", 1); - - case 8: - case "end": - return _context79.stop(); - } - }, _marked60[0], this, [[0, 4]]); - } - - function inner() { - return regeneratorRuntime.wrap(function inner$(_context80) { - while (1) switch (_context80.prev = _context80.next) { - case 0: - _context80.prev = 0; - _context80.next = 3; - return void 0; - - case 3: - _context80.next = 8; - break; - - case 5: - _context80.prev = 5; - _context80.t0 = _context80["catch"](0); - return _context80.abrupt("return"); - - case 8: - case "end": - return _context80.stop(); - } - }, _marked60[1], this, [[0, 5]]); - } - - var g = outer(); - g.next(); - assert.equal(g.throw(new Error('foo')).value, 1); - }); - - it("should propagate errors unhandled inside a delegate", function () { - var _marked61 = [outer, inner].map(regeneratorRuntime.mark); - - function outer() { - return regeneratorRuntime.wrap(function outer$(_context81) { - while (1) switch (_context81.prev = _context81.next) { - case 0: - _context81.prev = 0; - return _context81.delegateYield(inner(), "t0", 2); - - case 2: - _context81.next = 7; - break; - - case 4: - _context81.prev = 4; - _context81.t1 = _context81["catch"](0); - return _context81.abrupt("return", -1); - - case 7: - return _context81.abrupt("return", 1); - - case 8: - case "end": - return _context81.stop(); - } - }, _marked61[0], this, [[0, 4]]); - } - - function inner() { - return regeneratorRuntime.wrap(function inner$(_context82) { - while (1) switch (_context82.prev = _context82.next) { - case 0: - _context82.next = 2; - return void 0; - - case 2: - case "end": - return _context82.stop(); - } - }, _marked61[1], this); - } - - var g = outer(); - g.next(); - assert.equal(g.throw(new Error('foo')).value, -1); - }); -}); - -describe("unqualified function calls", function () { - it("should have a global `this` object", function () { - var _marked62 = [invoke].map(regeneratorRuntime.mark); - - function getThis() { - return this; - } - - // This is almost certainly the global object, but there's a chance it - // might be null or undefined (in strict mode). - var unqualifiedThis = getThis(); - - function invoke() { - return regeneratorRuntime.wrap(function invoke$(_context83) { - while (1) switch (_context83.prev = _context83.next) { - case 0: - _context83.next = 2; - return "dummy"; - - case 2: - return _context83.abrupt("return", (0, _context83.sent)()); - - case 3: - case "end": - return _context83.stop(); - } - }, _marked62[0], this); - } - - var g = invoke(); - var info = g.next(); - - assert.deepEqual(info, { value: "dummy", done: false }); - - info = g.next(getThis); - - // Avoid using assert.strictEqual when the arguments might equal the - // global object, since JSON.stringify chokes on circular structures. - assert.ok(info.value === unqualifiedThis); - - assert.strictEqual(info.done, true); - }); -}); - -describe("yield* expression results", function () { - it("have correct values", function () { - var _marked63 = [foo, bar].map(regeneratorRuntime.mark); - - function foo() { - return regeneratorRuntime.wrap(function foo$(_context84) { - while (1) switch (_context84.prev = _context84.next) { - case 0: - _context84.next = 2; - return 0; - - case 2: - return _context84.delegateYield(bar(), "t0", 3); - - case 3: - return _context84.abrupt("return", _context84.t0); - - case 4: - case "end": - return _context84.stop(); - } - }, _marked63[0], this); - } - - function bar() { - return regeneratorRuntime.wrap(function bar$(_context85) { - while (1) switch (_context85.prev = _context85.next) { - case 0: - _context85.next = 2; - return 1; - - case 2: - return _context85.abrupt("return", 2); - - case 3: - case "end": - return _context85.stop(); - } - }, _marked63[1], this); - } - - check(foo(), [0, 1], 2); - }); - - it("can be used in complex expressions", function () { - var _marked64 = [foo, bar].map(regeneratorRuntime.mark); - - function pumpNumber(gen) { - var n = 0; - - while (true) { - var res = n > 0 ? gen.next(n) : gen.next(); - n = res.value; - if (res.done) { - return n; - } - } - } - - function foo() { - return regeneratorRuntime.wrap(function foo$(_context86) { - while (1) switch (_context86.prev = _context86.next) { - case 0: - return _context86.delegateYield(bar(), "t0", 1); - - case 1: - _context86.t1 = _context86.t0; - return _context86.delegateYield(bar(), "t2", 3); - - case 3: - _context86.t3 = _context86.t2; - return _context86.abrupt("return", _context86.t1 + _context86.t3); - - case 5: - case "end": - return _context86.stop(); - } - }, _marked64[0], this); - } - - function bar() { - return regeneratorRuntime.wrap(function bar$(_context87) { - while (1) switch (_context87.prev = _context87.next) { - case 0: - _context87.next = 2; - return 2; - - case 2: - _context87.t0 = _context87.sent; - _context87.next = 5; - return 3; - - case 5: - _context87.t1 = _context87.sent; - return _context87.abrupt("return", _context87.t0 + _context87.t1); - - case 7: - case "end": - return _context87.stop(); - } - }, _marked64[1], this); - } - - assert.strictEqual(pumpNumber(bar()), 5); - assert.strictEqual(pumpNumber(foo()), 10); - }); -}); - -describe("isGeneratorFunction", function () { - it("should work for function declarations", function () { - var _marked65 = [genFun].map(regeneratorRuntime.mark); - - // Do the assertions up here to make sure the generator function is - // marked at the beginning of the block the function is declared in. - assert.strictEqual(regeneratorRuntime.isGeneratorFunction(genFun), true); - - assert.strictEqual(regeneratorRuntime.isGeneratorFunction(normalFun), false); - - function normalFun() { - return 0; - } - - function genFun() { - return regeneratorRuntime.wrap(function genFun$(_context88) { - while (1) switch (_context88.prev = _context88.next) { - case 0: - _context88.next = 2; - return 0; - - case 2: - case "end": - return _context88.stop(); - } - }, _marked65[0], this); - } - }); - - it("should work for function expressions", function () { - assert.strictEqual(regeneratorRuntime.isGeneratorFunction(regeneratorRuntime.mark(function genFun() { - return regeneratorRuntime.wrap(function genFun$(_context89) { - while (1) switch (_context89.prev = _context89.next) { - case 0: - _context89.next = 2; - return 0; - - case 2: - case "end": - return _context89.stop(); - } - }, genFun, this); - })), true); - - assert.strictEqual(regeneratorRuntime.isGeneratorFunction(function normalFun() { - return 0; - }), false); - }); -}); - -describe("new expressions", function () { - it("should be able to contain yield sub-expressions", function () { - var _marked66 = [gen].map(regeneratorRuntime.mark); - - function A(first, second) { - this.first = first; - this.second = second; - } - - function gen() { - return regeneratorRuntime.wrap(function gen$(_context90) { - while (1) switch (_context90.prev = _context90.next) { - case 0: - _context90.next = 2; - return 0; - - case 2: - _context90.t0 = _context90.sent; - _context90.next = 5; - return 1; - - case 5: - _context90.t1 = _context90.sent; - _context90.next = 8; - return 2; - - case 8: - _context90.t2 = _context90.sent; - _context90.next = 11; - return new _context90.t0(_context90.t1, _context90.t2); - - case 11: - return _context90.abrupt("return", _context90.sent); - - case 12: - case "end": - return _context90.stop(); - } - }, _marked66[0], this); - } - - var g = gen(); - - assert.deepEqual(g.next(), { value: 0, done: false }); - assert.deepEqual(g.next(A), { value: 1, done: false }); - assert.deepEqual(g.next("asdf"), { value: 2, done: false }); - - var info = g.next("zxcv"); - assert.strictEqual(info.done, false); - assert.ok(info.value instanceof A); - assert.strictEqual(info.value.first, "asdf"); - assert.strictEqual(info.value.second, "zxcv"); - - assert.deepEqual(g.next("qwer"), { value: "qwer", done: true }); - }); -}); - -describe("block binding", function () { - it("should translate block binding correctly", function () { - "use strict"; - - var _marked67 = [gen].map(regeneratorRuntime.mark); - - function gen() { - var a$0, a$1, a, _a, _a2; - - return regeneratorRuntime.wrap(function gen$(_context91) { - while (1) switch (_context91.prev = _context91.next) { - case 0: - a$0 = 0, a$1 = 1; - a = 3; - _a = 1; - _context91.next = 5; - return _a + a$0; - - case 5: - _a2 = 2; - _context91.next = 8; - return _a2 - 1 + a$1; - - case 8: - _context91.next = 10; - return a; - - case 10: - case "end": - return _context91.stop(); - } - }, _marked67[0], this); - } - - var g = gen(); - - assert.deepEqual(g.next(), { value: 1, done: false }); - assert.deepEqual(g.next(), { value: 2, done: false }); - assert.deepEqual(g.next(), { value: 3, done: false }); - assert.deepEqual(g.next(), { value: void 0, done: true }); - }); - - it("should translate block binding with iife correctly", function () { - "use strict"; - - var _marked68 = [gen].map(regeneratorRuntime.mark); - - function gen() { - var arr, _loop, x; - - return regeneratorRuntime.wrap(function gen$(_context92) { - while (1) switch (_context92.prev = _context92.next) { - case 0: - arr = []; - - _loop = function (x) { - var y = x; - arr.push(function () { - return y; - }); - }; - - for (x = 0; x < 3; x++) { - _loop(x); - } - - x = undefined; - - case 4: - if (!(x = arr.pop())) { - _context92.next = 9; - break; - } - - _context92.next = 7; - return x; - - case 7: - _context92.next = 4; - break; - - case 9: - case "end": - return _context92.stop(); - } - }, _marked68[0], this); - } - - var g = gen(); - - assert.equal(g.next().value(), 2); - assert.equal(g.next().value(), 1); - assert.equal(g.next().value(), 0); - assert.deepEqual(g.next(), { value: void 0, done: true }); - }); -}); - -describe("newborn generators", function () { - it("should be able to yield* non-newborn generators", function () { - var _marked69 = [inner, outer].map(regeneratorRuntime.mark); - - function inner() { - return regeneratorRuntime.wrap(function inner$(_context93) { - while (1) switch (_context93.prev = _context93.next) { - case 0: - _context93.next = 2; - return 1; - - case 2: - _context93.t0 = _context93.sent; - _context93.next = 5; - return 2; - - case 5: - _context93.t1 = _context93.sent; - return _context93.abrupt("return", [_context93.t0, _context93.t1]); - - case 7: - case "end": - return _context93.stop(); - } - }, _marked69[0], this); - } - - function outer(delegate) { - return regeneratorRuntime.wrap(function outer$(_context94) { - while (1) switch (_context94.prev = _context94.next) { - case 0: - return _context94.delegateYield(delegate, "t0", 1); - - case 1: - return _context94.abrupt("return", _context94.t0); - - case 2: - case "end": - return _context94.stop(); - } - }, _marked69[1], this); - } - - var n = inner(); - - assert.deepEqual(n.next(), { - value: 1, - done: false - }); - - var g = outer(n); - - // I would really like to be able to pass 3 to g.next here, but V8 - // ignores values sent to newborn generators, and SpiderMonkey throws - // a TypeError. - assert.deepEqual(g.next(), { - value: 2, - done: false - }); - - assert.deepEqual(g.next(4), { - value: [void 0, 4], - done: true - }); - }); - - it("should support the ignore-initial-yield wrapper idiom", function () { - var _marked70 = [inner].map(regeneratorRuntime.mark); - - var markers = []; - - function inner() { - var sent1, sent2; - return regeneratorRuntime.wrap(function inner$(_context95) { - while (1) switch (_context95.prev = _context95.next) { - case 0: - markers.push(0); - _context95.next = 3; - return 1; - - case 3: - sent1 = _context95.sent; - - markers.push(2); - _context95.next = 7; - return 2; - - case 7: - sent2 = _context95.sent; - - markers.push(3); - return _context95.abrupt("return", [sent1, sent2]); - - case 10: - case "end": - return _context95.stop(); - } - }, _marked70[0], this); - } - - function wrapper(delegate) { - var gen = regeneratorRuntime.mark(function _callee4() { - var sent, info; - return regeneratorRuntime.wrap(function _callee4$(_context96) { - while (1) switch (_context96.prev = _context96.next) { - case 0: - _context96.next = 2; - return "ignored"; - - case 2: - sent = _context96.sent; - - markers.push(1); - - case 4: - if ((info = delegate.next(sent)).done) { - _context96.next = 10; - break; - } - - _context96.next = 7; - return info.value; - - case 7: - sent = _context96.sent; - _context96.next = 4; - break; - - case 10: - - markers.push(4); - - return _context96.abrupt("return", info.value); - - case 12: - case "end": - return _context96.stop(); - } - }, _callee4, this); - })(); - - // Ensure that gen is not newborn and that the next invocation of - // gen.next(value) can send value to the initial yield expression. - gen.next(); - - return gen; - } - - var n = inner(); - - assert.deepEqual(n.next(), { - value: 1, - done: false - }); - - var g = wrapper(n); - - // Unlike in the previous spec, it's fine to pass 3 to g.next here, - // because g is not newborn, because g.next was already called once - // before g was returned from the wrapper function. - assert.deepEqual(g.next(3), { - value: 2, - done: false - }); - - assert.deepEqual(g.next(4), { - value: [3, 4], - done: true - }); - - // Ensure we encountered the marker points in the expected order. - assert.deepEqual(markers, [0, 1, 2, 3, 4]); - }); - - it("should allow chaining newborn and non-newborn generators", function () { - var _marked71 = [range, chain, y3, y5].map(regeneratorRuntime.mark); - - function range(n) { - var i; - return regeneratorRuntime.wrap(function range$(_context97) { - while (1) switch (_context97.prev = _context97.next) { - case 0: - i = 0; - - case 1: - if (!(i < n)) { - _context97.next = 7; - break; - } - - _context97.next = 4; - return i; - - case 4: - ++i; - _context97.next = 1; - break; - - case 7: - case "end": - return _context97.stop(); - } - }, _marked71[0], this); - } - - function chain(a, b) { - return regeneratorRuntime.wrap(function chain$(_context98) { - while (1) switch (_context98.prev = _context98.next) { - case 0: - return _context98.delegateYield(a, "t0", 1); - - case 1: - return _context98.delegateYield(b, "t1", 2); - - case 2: - case "end": - return _context98.stop(); - } - }, _marked71[1], this); - } - - check(chain(range(3), range(5)), [0, 1, 2, 0, 1, 2, 3, 4]); - - function y3(x) { - return regeneratorRuntime.wrap(function y3$(_context99) { - while (1) switch (_context99.prev = _context99.next) { - case 0: - _context99.next = 2; - return x; - - case 2: - _context99.next = 4; - return _context99.sent; - - case 4: - _context99.next = 6; - return _context99.sent; - - case 6: - return _context99.abrupt("return", _context99.sent); - - case 7: - case "end": - return _context99.stop(); - } - }, _marked71[2], this); - } - - function y5(x) { - return regeneratorRuntime.wrap(function y5$(_context100) { - while (1) switch (_context100.prev = _context100.next) { - case 0: - _context100.next = 2; - return x; - - case 2: - _context100.next = 4; - return _context100.sent; - - case 4: - _context100.next = 6; - return _context100.sent; - - case 6: - _context100.next = 8; - return _context100.sent; - - case 8: - _context100.next = 10; - return _context100.sent; - - case 10: - return _context100.abrupt("return", _context100.sent); - - case 11: - case "end": - return _context100.stop(); - } - }, _marked71[3], this); - } - - check(chain(y3("foo"), y5("bar")), ["foo", 1, 2, "bar", 4, 5, 6, 7]); - - var g3 = y3("three"); - assert.deepEqual(g3.next(), { - value: "three", - done: false - }); - - var g5 = y5("five"); - assert.deepEqual(g5.next(), { - value: "five", - done: false - }); - - var undef; // A little easier to read than void 0. - check(chain(g3, g5), [undef, 1, undef, 3, 4, 5]); - }); -}); - -describe("labeled break and continue statements", function () { - it("should be able to exit multiple try statements", function () { - var _marked72 = [gen].map(regeneratorRuntime.mark); - - var e1 = "first"; - var e2 = "second"; - var e3 = "third"; - var e4 = "fourth"; - - function gen(n, which) { - var i; - return regeneratorRuntime.wrap(function gen$(_context101) { - while (1) switch (_context101.prev = _context101.next) { - case 0: - _context101.prev = 0; - _context101.next = 3; - return 0; - - case 3: - raise(e1); - - case 4: - _context101.prev = 4; - _context101.next = 7; - return 1; - - case 7: - i = 0; - - case 8: - if (!(i < n)) { - _context101.next = 42; - break; - } - - _context101.next = 11; - return i; - - case 11: - _context101.prev = 11; - - raise(e2); - - case 13: - _context101.prev = 13; - _context101.next = 16; - return 2; - - case 16: - _context101.prev = 16; - - raise(e3); - - case 18: - _context101.prev = 18; - _context101.next = 21; - return 3; - - case 21: - _context101.prev = 21; - - raise(e4); - - case 23: - _context101.prev = 23; - _context101.next = 26; - return 4; - - case 26: - if (!(which === "break")) { - _context101.next = 30; - break; - } - - _context101.next = 29; - return "breaking"; - - case 29: - return _context101.abrupt("break", 42); - - case 30: - if (!(which === "continue")) { - _context101.next = 34; - break; - } - - _context101.next = 33; - return "continuing"; - - case 33: - return _context101.abrupt("continue", 39); - - case 34: - _context101.next = 36; - return 5; - - case 36: - return _context101.finish(23); - - case 37: - return _context101.finish(18); - - case 38: - return _context101.finish(13); - - case 39: - ++i; - _context101.next = 8; - break; - - case 42: - _context101.next = 44; - return 6; - - case 44: - return _context101.finish(4); - - case 45: - case "end": - return _context101.stop(); - } - }, _marked72[0], this, [[0,, 4, 45], [11,, 13, 39], [16,, 18, 38], [21,, 23, 37]]); - } - - try { - check(gen(1, "break"), [0, 1, 0, 2, 3, 4, "breaking", 6]); - assert.ok(false, "should have thrown an exception"); - } catch (err) { - assert.strictEqual(err, e1); - } - - try { - check(gen(3, "continue"), [0, 1, 0, 2, 3, 4, "continuing", 1, 2, 3, 4, "continuing", 2, 2, 3, 4, "continuing", 6 // Loop finished naturally. - ]); - assert.ok(false, "should have thrown an exception"); - } catch (err) { - assert.strictEqual(err, e1); - } - - try { - check(gen(3, "neither"), [0, 1, 0, 2, 3, 4, 5]); - assert.ok(false, "should have thrown an exception"); - } catch (err) { - assert.strictEqual(err, e4); - } - }); - - it("should allow breaking from any labeled statement", function () { - var _marked73 = [gen].map(regeneratorRuntime.mark); - - function gen(limit) { - var i; - return regeneratorRuntime.wrap(function gen$(_context102) { - while (1) switch (_context102.prev = _context102.next) { - case 0: - _context102.next = 2; - return 0; - - case 2: - i = 0; - - case 3: - if (!(i < limit)) { - _context102.next = 32; - break; - } - - _context102.next = 6; - return 1; - - case 6: - _context102.next = 8; - return 2; - - case 8: - return _context102.abrupt("break", 11); - - case 11: - if (!(limit === 3)) { - _context102.next = 26; - break; - } - - _context102.next = 14; - return 4; - - case 14: - if (!(i === 0)) { - _context102.next = 16; - break; - } - - return _context102.abrupt("break", 26); - - case 16: - _context102.next = 18; - return 5; - - case 18: - if (!(i === 1)) { - _context102.next = 20; - break; - } - - return _context102.abrupt("break", 26); - - case 20: - _context102.next = 22; - return 6; - - case 22: - if (!(i === 2)) { - _context102.next = 24; - break; - } - - return _context102.abrupt("break", 32); - - case 24: - _context102.next = 26; - return 7; - - case 26: - return _context102.abrupt("break", 27); - - case 27: - _context102.next = 29; - return 8; - - case 29: - ++i; - _context102.next = 3; - break; - - case 32: - _context102.next = 34; - return 9; - - case 34: - case "end": - return _context102.stop(); - } - }, _marked73[0], this); - } - - check(gen(0), [0, 9]); - check(gen(1), [0, 1, 2, 8, 9]); - check(gen(2), [0, 1, 2, 8, 1, 2, 8, 9]); - check(gen(3), [0, 1, 2, 4, 8, 1, 2, 4, 5, 8, 1, 2, 4, 5, 6, 9]); - }); -}); - -describe("for loop with var decl and no update expression", function () { - var _marked74 = [range].map(regeneratorRuntime.mark); - - // https://github.com/facebook/regenerator/issues/103 - function range() { - var i; - return regeneratorRuntime.wrap(function range$(_context103) { - while (1) switch (_context103.prev = _context103.next) { - case 0: - for (i = 0; false;) {} - - case 1: - case "end": - return _context103.stop(); - } - }, _marked74[0], this); - } - - it("should compile and run", function () { - check(range(), []); - }); -}); - -describe("generator function prototype", function () { - function getProto(obj) { - return Object.getPrototypeOf ? Object.getPrototypeOf(obj) : obj.__proto__; - } - - it("should follow the expected object model", function () { - var _marked75 = [f2, f, f].map(regeneratorRuntime.mark); - - var GeneratorFunctionPrototype = getProto(f); - var GeneratorFunction = GeneratorFunctionPrototype.constructor; - - assert.strictEqual(GeneratorFunction.name, 'GeneratorFunction'); - assert.strictEqual(GeneratorFunction.prototype, GeneratorFunctionPrototype); - assert.strictEqual(GeneratorFunctionPrototype.prototype.constructor, GeneratorFunctionPrototype); - assert.strictEqual(GeneratorFunctionPrototype.prototype, getProto(f.prototype)); - assert.strictEqual(getProto(GeneratorFunctionPrototype), Function.prototype); - - if (typeof process === "undefined" || process.version.slice(1, 3) === "0.") { - // Node version strings start with 0. - assert.strictEqual(GeneratorFunctionPrototype.name, "GeneratorFunctionPrototype"); - } else if (process.version.slice(1, 3) === "1.") { - // iojs version strings start with 1., and iojs gets this .name - // property wrong. TODO report this? - assert.strictEqual(GeneratorFunctionPrototype.name, ""); - } - - assert.strictEqual(typeof f2, "function"); - assert.strictEqual(f2.constructor, GeneratorFunction); - assert.ok(f2 instanceof GeneratorFunction); - assert.strictEqual(f2.name, "f2"); - - var g = f(); - assert.ok(g instanceof f); - assert.strictEqual(getProto(g), f.prototype); - - assert.deepEqual([], Object.getOwnPropertyNames(f.prototype)); - // assert.deepEqual([], Object.getOwnPropertyNames(g)); - - f.prototype.x = 42; - - var g2 = f(); - assert.strictEqual(g2.x, 42); - - var g3 = new f(); - assert.strictEqual(g3.x, 42); - - function f2() { - return regeneratorRuntime.wrap(function f2$(_context104) { - while (1) switch (_context104.prev = _context104.next) { - case 0: - _context104.next = 2; - return 1; - - case 2: - case "end": - return _context104.stop(); - } - }, _marked75[0], this); - } - - assert.strictEqual(getProto(f), getProto(f2)); - assert.strictEqual(f.hasOwnProperty('constructor'), false); - assert.strictEqual(getProto(f).constructor.name, 'GeneratorFunction'); - - // Intentionally at the end to test hoisting. - function f() { - return regeneratorRuntime.wrap(function f$(_context105) { - while (1) switch (_context105.prev = _context105.next) { - case 0: - _context105.next = 2; - return this; - - case 2: - case "end": - return _context105.stop(); - } - }, _marked75[1], this); - } - - function f() { - return regeneratorRuntime.wrap(function f$(_context106) { - while (1) switch (_context106.prev = _context106.next) { - case 0: - _context106.next = 2; - return 1; - - case 2: - case "end": - return _context106.stop(); - } - }, _marked75[2], this); - } - - var f2 = f; - f = 42; - var g = f2(); - - assert.deepEqual(g.next(), { value: 1, done: false }); - assert.deepEqual(g.next(), { value: void 0, done: true }); - assert.ok(g instanceof f2); - }); -}); - -describe("for-of loops", function () { - (runningInTranslation ? it : xit)("should work for Arrays", function () { - var sum = 0; - var _iteratorNormalCompletion = true; - var _didIteratorError = false; - var _iteratorError = undefined; - - try { - for (var _iterator = [1, 2].concat(3)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { - var x = _step.value; - - sum += x; - } - } catch (err) { - _didIteratorError = true; - _iteratorError = err; - } finally { - try { - if (!_iteratorNormalCompletion && _iterator.return) { - _iterator.return(); - } - } finally { - if (_didIteratorError) { - throw _iteratorError; - } - } - } - - assert.strictEqual(sum, 6); - }); - - it("should work for generators", function () { - var value, - values = []; - var _iteratorNormalCompletion2 = true; - var _didIteratorError2 = false; - var _iteratorError2 = undefined; - - try { - for (var _iterator2 = range(3)[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { - value = _step2.value; - - values.push(value); - } - } catch (err) { - _didIteratorError2 = true; - _iteratorError2 = err; - } finally { - try { - if (!_iteratorNormalCompletion2 && _iterator2.return) { - _iterator2.return(); - } - } finally { - if (_didIteratorError2) { - throw _iteratorError2; - } - } - } - - assert.deepEqual(values, [0, 1, 2]); - }); - - it("should work inside of generators", function () { - var _marked76 = [yieldPermutations].map(regeneratorRuntime.mark); - - function yieldPermutations(list) { - var count, first, genRest, _iteratorNormalCompletion3, _didIteratorError3, _iteratorError3, _iterator3, _step3, perm, i, prefix, suffix; - - return regeneratorRuntime.wrap(function yieldPermutations$(_context107) { - while (1) switch (_context107.prev = _context107.next) { - case 0: - if (!(list.length < 2)) { - _context107.next = 4; - break; - } - - _context107.next = 3; - return list; - - case 3: - return _context107.abrupt("return", 1); - - case 4: - count = 0; - first = list.slice(0, 1); - genRest = yieldPermutations(list.slice(1)); - _iteratorNormalCompletion3 = true; - _didIteratorError3 = false; - _iteratorError3 = undefined; - _context107.prev = 10; - _iterator3 = genRest[Symbol.iterator](); - - case 12: - if (_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done) { - _context107.next = 27; - break; - } - - perm = _step3.value; - i = 0; - - case 15: - if (!(i < list.length)) { - _context107.next = 23; - break; - } - - prefix = perm.slice(0, i); - suffix = perm.slice(i); - _context107.next = 20; - return prefix.concat(first, suffix); - - case 20: - ++i; - _context107.next = 15; - break; - - case 23: - - count += i; - - case 24: - _iteratorNormalCompletion3 = true; - _context107.next = 12; - break; - - case 27: - _context107.next = 33; - break; - - case 29: - _context107.prev = 29; - _context107.t0 = _context107["catch"](10); - _didIteratorError3 = true; - _iteratorError3 = _context107.t0; - - case 33: - _context107.prev = 33; - _context107.prev = 34; - - if (!_iteratorNormalCompletion3 && _iterator3.return) { - _iterator3.return(); - } - - case 36: - _context107.prev = 36; - - if (!_didIteratorError3) { - _context107.next = 39; - break; - } - - throw _iteratorError3; - - case 39: - return _context107.finish(36); - - case 40: - return _context107.finish(33); - - case 41: - return _context107.abrupt("return", count); - - case 42: - case "end": - return _context107.stop(); - } - }, _marked76[0], this, [[10, 29, 33, 41], [34,, 36, 40]]); - } - - var count = 0; - var _iteratorNormalCompletion4 = true; - var _didIteratorError4 = false; - var _iteratorError4 = undefined; - - try { - for (var _iterator4 = yieldPermutations([])[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { - var perm = _step4.value; - - assert.deepEqual(perm, []); - ++count; - } - } catch (err) { - _didIteratorError4 = true; - _iteratorError4 = err; - } finally { - try { - if (!_iteratorNormalCompletion4 && _iterator4.return) { - _iterator4.return(); - } - } finally { - if (_didIteratorError4) { - throw _iteratorError4; - } - } - } - - assert.strictEqual(count, 1); - - check(yieldPermutations([1]), [[1]], 1); - - check(yieldPermutations([2, 1]), [[2, 1], [1, 2]], 2); - - check(yieldPermutations([1, 3, 2]), [[1, 3, 2], [3, 1, 2], [3, 2, 1], [1, 2, 3], [2, 1, 3], [2, 3, 1]], 6); - }); -}); - -describe("generator return method", function () { - if (!runningInTranslation) { - // The return method has not been specified or implemented natively, - // yet, so these tests need only pass in translation. - return; - } - - it("should work with newborn generators", function () { - var _marked77 = [gen].map(regeneratorRuntime.mark); - - function gen() { - return regeneratorRuntime.wrap(function gen$(_context108) { - while (1) switch (_context108.prev = _context108.next) { - case 0: - _context108.next = 2; - return 0; - - case 2: - case "end": - return _context108.stop(); - } - }, _marked77[0], this); - } - - var g = gen(); - - assert.deepEqual(g.return("argument"), { - value: "argument", - done: true - }); - - assertAlreadyFinished(g); - }); - - it("should behave as if generator actually returned", function () { - var _marked78 = [gen].map(regeneratorRuntime.mark); - - var executedFinally = false; - - function gen() { - return regeneratorRuntime.wrap(function gen$(_context109) { - while (1) switch (_context109.prev = _context109.next) { - case 0: - _context109.prev = 0; - _context109.next = 3; - return 0; - - case 3: - _context109.next = 8; - break; - - case 5: - _context109.prev = 5; - _context109.t0 = _context109["catch"](0); - - assert.ok(false, "should not have executed the catch handler"); - - case 8: - _context109.prev = 8; - - executedFinally = true; - return _context109.finish(8); - - case 11: - case "end": - return _context109.stop(); - } - }, _marked78[0], this, [[0, 5, 8, 11]]); - } - - var g = gen(); - assert.deepEqual(g.next(), { value: 0, done: false }); - - assert.deepEqual(g.return("argument"), { - value: "argument", - done: true - }); - - assert.strictEqual(executedFinally, true); - assertAlreadyFinished(g); - }); - - it("should return both delegate and delegator", function () { - var _marked79 = [callee, caller].map(regeneratorRuntime.mark); - - var checkpoints = []; - - function callee(errorToThrow) { - return regeneratorRuntime.wrap(function callee$(_context110) { - while (1) switch (_context110.prev = _context110.next) { - case 0: - _context110.prev = 0; - _context110.next = 3; - return 1; - - case 3: - _context110.next = 5; - return 2; - - case 5: - _context110.prev = 5; - - checkpoints.push("callee finally"); - - if (!errorToThrow) { - _context110.next = 9; - break; - } - - throw errorToThrow; - - case 9: - return _context110.finish(5); - - case 10: - case "end": - return _context110.stop(); - } - }, _marked79[0], this, [[0,, 5, 10]]); - } - - function caller(errorToThrow) { - return regeneratorRuntime.wrap(function caller$(_context111) { - while (1) switch (_context111.prev = _context111.next) { - case 0: - _context111.prev = 0; - _context111.next = 3; - return 0; - - case 3: - return _context111.delegateYield(callee(errorToThrow), "t0", 4); - - case 4: - _context111.next = 6; - return 3; - - case 6: - _context111.prev = 6; - - checkpoints.push("caller finally"); - return _context111.finish(6); - - case 9: - case "end": - return _context111.stop(); - } - }, _marked79[1], this, [[0,, 6, 9]]); - } - - var g1 = caller(); - - assert.deepEqual(g1.next(), { value: 0, done: false }); - assert.deepEqual(g1.next(), { value: 1, done: false }); - assert.deepEqual(g1.return(-1), { value: -1, done: true }); - assert.deepEqual(checkpoints, ["callee finally", "caller finally"]); - - var error = new Error("thrown from callee"); - var g2 = caller(error); - - assert.deepEqual(g2.next(), { value: 0, done: false }); - assert.deepEqual(g2.next(), { value: 1, done: false }); - - try { - g2.return(-1); - assert.ok(false, "should have thrown an exception"); - } catch (thrown) { - assert.strictEqual(thrown, error); - } - - assert.deepEqual(checkpoints, ["callee finally", "caller finally", "callee finally", "caller finally"]); - }); -}); - -describe("expressions containing yield subexpressions", function () { - it("should evaluate all subexpressions before yielding", function () { - var _marked80 = [gen].map(regeneratorRuntime.mark); - - function gen(x) { - return regeneratorRuntime.wrap(function gen$(_context112) { - while (1) switch (_context112.prev = _context112.next) { - case 0: - _context112.t0 = x; - _context112.next = 3; - return function (y) { - x = y; - }; - - case 3: - _context112.t1 = _context112.sent; - return _context112.abrupt("return", _context112.t0 * _context112.t1); - - case 5: - case "end": - return _context112.stop(); - } - }, _marked80[0], this); - } - - var g = gen(2); - var result = g.next(); - assert.strictEqual(result.done, false); - - result.value(5); - - assert.deepEqual(g.next(5), { - value: 10, - done: true - }); - }); - - it("should work even with getter member expressions", function () { - var _marked81 = [gen].map(regeneratorRuntime.mark); - - function gen() { - return regeneratorRuntime.wrap(function gen$(_context113) { - while (1) switch (_context113.prev = _context113.next) { - case 0: - _context113.t0 = a.b; - _context113.next = 3; - return "asdf"; - - case 3: - _context113.t1 = _context113.sent; - return _context113.abrupt("return", _context113.t0 + _context113.t1); - - case 5: - case "end": - return _context113.stop(); - } - }, _marked81[0], this); - } - - var a = {}; - var b = 0; - - Object.defineProperty(a, "b", { - get: function () { - return ++b; - } - }); - - var g = gen(); - - assert.strictEqual(a.b, 1); - - assert.deepEqual(g.next(), { - value: "asdf", - done: false - }); - - assert.strictEqual(a.b, 3); - - assert.deepEqual(g.next(2), { - value: 4, - done: true - }); - }); - - it("should evaluate all array elements before yielding", function () { - var _marked82 = [gen].map(regeneratorRuntime.mark); - - function gen() { - return regeneratorRuntime.wrap(function gen$(_context114) { - while (1) switch (_context114.prev = _context114.next) { - case 0: - _context114.t0 = a; - _context114.next = 3; - return "asdf"; - - case 3: - _context114.t1 = _context114.sent; - _context114.t2 = a; - return _context114.abrupt("return", [_context114.t0, _context114.t1, _context114.t2]); - - case 6: - case "end": - return _context114.stop(); - } - }, _marked82[0], this); - } - - var a = 1; - var g = gen(); - - assert.deepEqual(g.next(), { - value: "asdf", - done: false - }); - - a = 3; - - assert.deepEqual(g.next(2), { - value: [1, 2, 3], - done: true - }); - }); - - it("should handle callee member expressions correctly", function () { - var _marked83 = [gen].map(regeneratorRuntime.mark); - - function gen() { - return regeneratorRuntime.wrap(function gen$(_context115) { - while (1) switch (_context115.prev = _context115.next) { - case 0: - _context115.t0 = a.slice(0); - _context115.next = 3; - return "asdf"; - - case 3: - _context115.t1 = _context115.sent; - a = _context115.t0.concat.call(_context115.t0, _context115.t1); - return _context115.abrupt("return", a); - - case 6: - case "end": - return _context115.stop(); - } - }, _marked83[0], this); - } - - var a = []; - var g = gen(); - - assert.deepEqual(g.next(), { - value: "asdf", - done: false - }); - - a.push(1); - - assert.deepEqual(g.next(2), { - value: [2], - done: true - }); - }); - - it("should handle implicit stringification correctly", function () { - var _marked84 = [gen].map(regeneratorRuntime.mark); - - function gen() { - return regeneratorRuntime.wrap(function gen$(_context116) { - while (1) switch (_context116.prev = _context116.next) { - case 0: - _context116.t0 = a; - _context116.next = 3; - return "asdf"; - - case 3: - _context116.t1 = _context116.sent; - return _context116.abrupt("return", _context116.t0 + _context116.t1); - - case 5: - case "end": - return _context116.stop(); - } - }, _marked84[0], this); - } - - var a = [1, 2]; - var g = gen(); - - assert.deepEqual(g.next(), { - value: "asdf", - done: false - }); - - a = [4, 5]; - - assert.deepEqual(g.next(",3"), { - value: "1,2,3", - done: true - }); - }); -}); \ No newline at end of file diff --git a/packages/babel-plugin-transform-regenerator/.test/tests.transform.js b/packages/babel-plugin-transform-regenerator/.test/tests.transform.js deleted file mode 100644 index e67e1d9569..0000000000 --- a/packages/babel-plugin-transform-regenerator/.test/tests.transform.js +++ /dev/null @@ -1,47 +0,0 @@ -var regenerator = require(".."); -var babylon = require("babylon"); -var assert = require("assert"); -var babel = require("babel-core"); -var t = require("babel-types"); - -describe("_blockHoist nodes", function() { - it("should be hoisted to the outer body", function() { - var foo; - var names = []; - var ast = babylon.parse([ - "function *foo(doNotHoistMe, hoistMe) {", - " var sent = yield doNotHoistMe();", - " hoistMe();", - " names.push(sent);", - " return 123;", - "}" - ].join("\n")); - - var hoistMeStmt = ast.program.body[0].body.body[1]; - t.assertExpressionStatement(hoistMeStmt); - t.assertCallExpression(hoistMeStmt.expression); - t.assertIdentifier(hoistMeStmt.expression.callee); - assert.strictEqual(hoistMeStmt.expression.callee.name, "hoistMe"); - - hoistMeStmt._blockHoist = 1; - - eval(babel.transformFromAst(ast, null, { plugins: [regenerator] }).code); - - assert.strictEqual(typeof foo, "function"); - assert.ok(regeneratorRuntime.isGeneratorFunction(foo)); - assert.strictEqual(names.length, 0); - - var g = foo(function doNotHoistMe() { - names.push("doNotHoistMe"); - return "yielded"; - }, function hoistMe() { - names.push("hoistMe"); - }); - - assert.deepEqual(names, ["hoistMe"]); - assert.deepEqual(g.next(), { value: "yielded", done: false }); - assert.deepEqual(names, ["hoistMe", "doNotHoistMe"]); - assert.deepEqual(g.next("oyez"), { value: 123, done: true }); - assert.deepEqual(names, ["hoistMe", "doNotHoistMe", "oyez"]); - }); -}); diff --git a/packages/babel-plugin-transform-regenerator/.travis.yml b/packages/babel-plugin-transform-regenerator/.travis.yml deleted file mode 100644 index 928d48bb5c..0000000000 --- a/packages/babel-plugin-transform-regenerator/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -language: node_js -node_js: - - "4.0" - - "iojs" - - "0.12" - - "0.11" - - "0.10" - - "0.8" -before_install: - - npm install -g npm@1.4.28 -sudo: false diff --git a/packages/babel-plugin-transform-regenerator/CONTRIBUTING.md b/packages/babel-plugin-transform-regenerator/CONTRIBUTING.md deleted file mode 100644 index a4ad349e65..0000000000 --- a/packages/babel-plugin-transform-regenerator/CONTRIBUTING.md +++ /dev/null @@ -1,80 +0,0 @@ -# Contributing to Regenerator - -Regenerator uses GitHub as its sole source of truth. Everything happens -here. Facebook employees who contribute to Regenerator are expected to do -so in the same way as everyone else. In other words, this document applies -equally to all contributors. - -### `master` is unsafe - -We will do our best to keep `master` in good shape, with tests passing at -all times. But in order to move fast, we will make API changes that your -application might not be compatible with. We will do our best to -communicate these changes and always version appropriately so you can lock -into a specific version if need be. - -### Pull Requests - -In case you've never submitted a pull request (PR) via GitHub before, -please read [this short -tutorial](https://help.github.com/articles/creating-a-pull-request). If -you've submitted a PR before, there should be nothing surprising about our -procedures for Regenerator. - -*Before* submitting a pull request, please make sure the following is done… - -1. Fork the repo and create your branch from `master`. -2. If you've added code that should be tested, add tests! -3. Ensure the test suite passes (`npm test`). -4. If you haven't already, complete the CLA. -5. Submit a pull request via GitHub. -6. Check that Travis CI tests pass (pull request turns green). - -### Contributor License Agreement ("CLA") - -In order to accept your pull request, we need you to submit a CLA. You -only need to do this once, so if you've done this for another Facebook -open source project, you're good to go. If you are submitting a pull -request for the first time, just let us know that you have completed the -CLA and we can cross-check with your GitHub username. - -Complete your CLA here: - -## Bugs - -### Where to Find Known Issues - -We will be using GitHub Issues for all bugs. Before filing a new issue, -please try to make sure your problem doesn't already exist. If you think -your issue is more general than one that already exists, our preference is -still to modify the original issue to reflect the underlying problem more -faithfully. - -### Reporting New Issues - -The best way to get a bug fixed is to provide a reduced test case, and the -easiest way to reduce a testcase is to edit it in [the -sandbox](http://facebook.github.io/regenerator/) until you're satisfied -and then click the "report a bug" link (the new issue will be populated -automatically with your code). - -### Security Bugs - -Facebook has a [bounty program](https://www.facebook.com/whitehat/) for -the safe disclosure of security bugs. With that in mind, please do not -file public issues and go through the process outlined on that page. - -## Coding Style - -* Use semicolons; -* Commas last, -* 2 spaces for indentation (no tabs). -* Prefer `"` over `'` -* 80 character line length -* Match surrounding coding style. -* Less code is better code. - -## License - -By contributing to Regenerator, you agree that your contributions will be -licensed under the [BSD License](LICENSE). diff --git a/packages/babel-plugin-transform-regenerator/README.md b/packages/babel-plugin-transform-regenerator/README.md index c220dba788..d22e2292e9 100644 --- a/packages/babel-plugin-transform-regenerator/README.md +++ b/packages/babel-plugin-transform-regenerator/README.md @@ -1,74 +1 @@ -regenerator [![Build Status](https://travis-ci.org/facebook/regenerator.png?branch=master)](https://travis-ci.org/facebook/regenerator) -=== - -This package implements a fully-functional source transformation that -takes the proposed syntax for generators/`yield` from future versions of -JS ([ECMAScript6 or ES6](http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts), experimentally implemented in Node.js v0.11) and -spits out efficient JS-of-today (ES5) that behaves the same way. - -A small runtime library (less than 1KB compressed) is required to provide the -`wrapGenerator` function. You can install it either as a CommonJS module -or as a standalone .js file, whichever you prefer. - -Installation ---- - -From NPM: -```sh -npm install -g regenerator -``` - -From GitHub: -```sh -cd path/to/node_modules -git clone git://github.com/facebook/regenerator.git -cd regenerator -npm install . -npm test -``` - -Usage ---- - -You have several options for using this module. - -Simplest usage: -```sh -regenerator es6.js > es5.js # Just the transform. -regenerator --include-runtime es6.js > es5.js # Add the runtime too. -regenerator src lib # Transform every .js file in src and output to lib. -``` - -Programmatic usage: -```js -var es5Source = require("regenerator").compile(es6Source).code; -var es5SourceWithRuntime = require("regenerator").compile(es6Source, { - includeRuntime: true -}).code; -``` - -Babel plugin: -```js -var babel = require("babel-core"); -var code = babel.transform(es6Source, { - plugins: [require("generator")] -}).code; -``` - -How can you get involved? ---- - -The easiest way to get involved is to look for buggy examples using [the -sandbox](http://facebook.github.io/regenerator/), and when you find -something strange just click the "report a bug" link (the new issue form -will be populated automatically with the problematic code). - -Alternatively, you can -[fork](https://github.com/facebook/regenerator/fork) the repository, -create some failing tests cases in [test/tests.es6.js](test/tests.es6.js), -and send pull requests for me to fix. - -If you're feeling especially brave, you are more than welcome to dive into -the transformer code and fix the bug(s) yourself, but I must warn you that -the code could really benefit from [better implementation -comments](https://github.com/facebook/regenerator/issues/7). +# babel-plugin-transform-regenerator diff --git a/packages/babel-plugin-transform-regenerator/bin/regenerator b/packages/babel-plugin-transform-regenerator/bin/regenerator deleted file mode 100755 index 88a4e27c12..0000000000 --- a/packages/babel-plugin-transform-regenerator/bin/regenerator +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env node -// -*- mode: js -*- - -var compile = require("../main").compile; - -require("commoner").version( - require("../package.json").version -).resolve(function(id) { - return this.readModuleP(id); -}).option( - "-r, --include-runtime", - "Prepend the runtime to the output." -).process(function(id, source) { - return compile(source, { - includeRuntime: this.options.includeRuntime - }).code; -}); diff --git a/packages/babel-plugin-transform-regenerator/lib/emit.js b/packages/babel-plugin-transform-regenerator/lib/emit.js index 078a8c0dfd..d435cd2e0a 100644 --- a/packages/babel-plugin-transform-regenerator/lib/emit.js +++ b/packages/babel-plugin-transform-regenerator/lib/emit.js @@ -8,54 +8,66 @@ * the same directory. */ -var traverse = require("babel-traverse"); -var assert = require("assert"); -var t = require("babel-types"); -var leap = require("./leap"); -var meta = require("./meta"); -var util = require("./util"); -var runtimeProperty = util.runtimeProperty; +"use strict"; + +var _interopRequireDefault = require("babel-runtime/helpers/interop-require-default")["default"]; + +var _interopRequireWildcard = require("babel-runtime/helpers/interop-require-wildcard")["default"]; + +var _assert = require("assert"); + +var _assert2 = _interopRequireDefault(_assert); + +var _babelTypes = require("babel-types"); + +var t = _interopRequireWildcard(_babelTypes); + +var _leap = require("./leap"); + +var leap = _interopRequireWildcard(_leap); + +var _meta = require("./meta"); + +var meta = _interopRequireWildcard(_meta); + +var _util = require("./util"); + +var util = _interopRequireWildcard(_util); + var hasOwn = Object.prototype.hasOwnProperty; function Emitter(contextId) { - assert.ok(this instanceof Emitter); + _assert2["default"].ok(this instanceof Emitter); t.assertIdentifier(contextId); // Used to generate unique temporary names. this.nextTempId = 0; - Object.defineProperties(this, { - // In order to make sure the context object does not collide with - // anything in the local scope, we might have to rename it, so we - // refer to it symbolically instead of just assuming that it will be - // called "context". - contextId: { value: contextId }, + // In order to make sure the context object does not collide with + // anything in the local scope, we might have to rename it, so we + // refer to it symbolically instead of just assuming that it will be + // called "context". + this.contextId = contextId; - // An append-only list of Statements that grows each time this.emit is - // called. - listing: { value: [] }, + // An append-only list of Statements that grows each time this.emit is + // called. + this.listing = []; - // A sparse array whose keys correspond to locations in this.listing - // that have been marked as branch/jump targets. - marked: { value: [true] }, + // A sparse array whose keys correspond to locations in this.listing + // that have been marked as branch/jump targets. + this.marked = [true]; - // The last location will be marked when this.getDispatchLoop is - // called. - finalLoc: { value: loc() }, + // The last location will be marked when this.getDispatchLoop is + // called. + this.finalLoc = loc(); - // A list of all leap.TryEntry statements emitted. - tryEntries: { value: [] } - }); + // A list of all leap.TryEntry statements emitted. + this.tryEntries = []; - // The .leapManager property needs to be defined by a separate - // defineProperties call so that .finalLoc will be visible to the - // leap.LeapManager constructor. - Object.defineProperties(this, { - // Each time we evaluate the body of a loop, we tell this.leapManager - // to enter a nested loop context that determines the meaning of break - // and continue statements therein. - leapManager: { value: new leap.LeapManager(this) } - }); + // Each time we evaluate the body of a loop, we tell this.leapManager + // to enter a nested loop context that determines the meaning of break + // and continue statements therein. + this.leapManager = new leap.LeapManager(this); } var Ep = Emitter.prototype; @@ -72,7 +84,7 @@ function loc() { // Sets the exact value of the given location to the offset of the next // Statement emitted. -Ep.mark = function(loc) { +Ep.mark = function (loc) { t.assertLiteral(loc); var index = this.listing.length; if (loc.value === -1) { @@ -80,44 +92,38 @@ Ep.mark = function(loc) { } else { // Locations can be marked redundantly, but their values cannot change // once set the first time. - assert.strictEqual(loc.value, index); + _assert2["default"].strictEqual(loc.value, index); } this.marked[index] = true; return loc; }; -Ep.emit = function(node) { - if (t.isExpression(node)) - node = t.expressionStatement(node); +Ep.emit = function (node) { + if (t.isExpression(node)) node = t.expressionStatement(node); t.assertStatement(node); this.listing.push(node); }; // Shorthand for emitting assignment statements. This will come in handy // for assignments to temporary variables. -Ep.emitAssign = function(lhs, rhs) { +Ep.emitAssign = function (lhs, rhs) { this.emit(this.assign(lhs, rhs)); return lhs; }; // Shorthand for an assignment statement. -Ep.assign = function(lhs, rhs) { - return t.expressionStatement( - t.assignmentExpression("=", lhs, rhs)); +Ep.assign = function (lhs, rhs) { + return t.expressionStatement(t.assignmentExpression("=", lhs, rhs)); }; // Convenience function for generating expressions like context.next, // context.sent, and context.rval. -Ep.contextProperty = function(name, computed) { - return t.memberExpression( - this.contextId, - computed ? t.stringLiteral(name) : t.identifier(name), - !!computed - ); +Ep.contextProperty = function (name, computed) { + return t.memberExpression(this.contextId, computed ? t.stringLiteral(name) : t.identifier(name), !!computed); }; // Shorthand for setting context.rval and jumping to `context.stop()`. -Ep.stop = function(rval) { +Ep.stop = function (rval) { if (rval) { this.setReturnValue(rval); } @@ -125,22 +131,16 @@ Ep.stop = function(rval) { this.jump(this.finalLoc); }; -Ep.setReturnValue = function(valuePath) { +Ep.setReturnValue = function (valuePath) { t.assertExpression(valuePath.value); - this.emitAssign( - this.contextProperty("rval"), - this.explodeExpression(valuePath) - ); + this.emitAssign(this.contextProperty("rval"), this.explodeExpression(valuePath)); }; -Ep.clearPendingException = function(tryLoc, assignee) { +Ep.clearPendingException = function (tryLoc, assignee) { t.assertLiteral(tryLoc); - var catchCall = t.callExpression( - this.contextProperty("catch", true), - [tryLoc] - ); + var catchCall = t.callExpression(this.contextProperty("catch", true), [tryLoc]); if (assignee) { this.emitAssign(assignee, catchCall); @@ -151,46 +151,33 @@ Ep.clearPendingException = function(tryLoc, assignee) { // Emits code for an unconditional jump to the given location, even if the // exact value of the location is not yet known. -Ep.jump = function(toLoc) { +Ep.jump = function (toLoc) { this.emitAssign(this.contextProperty("next"), toLoc); this.emit(t.breakStatement()); }; // Conditional jump. -Ep.jumpIf = function(test, toLoc) { +Ep.jumpIf = function (test, toLoc) { t.assertExpression(test); t.assertLiteral(toLoc); - this.emit(t.ifStatement( - test, - t.blockStatement([ - this.assign(this.contextProperty("next"), toLoc), - t.breakStatement() - ]) - )); + this.emit(t.ifStatement(test, t.blockStatement([this.assign(this.contextProperty("next"), toLoc), t.breakStatement()]))); }; // Conditional jump, with the condition negated. -Ep.jumpIfNot = function(test, toLoc) { +Ep.jumpIfNot = function (test, toLoc) { t.assertExpression(test); t.assertLiteral(toLoc); - var negatedTest; - if (t.isUnaryExpression(test) && - test.operator === "!") { + var negatedTest = undefined; + if (t.isUnaryExpression(test) && test.operator === "!") { // Avoid double negation. negatedTest = test.argument; } else { negatedTest = t.unaryExpression("!", test); } - this.emit(t.ifStatement( - negatedTest, - t.blockStatement([ - this.assign(this.contextProperty("next"), toLoc), - t.breakStatement() - ]) - )); + this.emit(t.ifStatement(negatedTest, t.blockStatement([this.assign(this.contextProperty("next"), toLoc), t.breakStatement()]))); }; // Returns a unique MemberExpression that can be used to store and @@ -198,17 +185,14 @@ Ep.jumpIfNot = function(test, toLoc) { // the context object, which is presumed to coexist peacefully with all // other local variables, and since we just increment `nextTempId` // monotonically, uniqueness is assured. -Ep.makeTempVar = function() { +Ep.makeTempVar = function () { return this.contextProperty("t" + this.nextTempId++); }; -Ep.getContextFunction = function(id) { - return t.functionExpression( - id || null/*Anonymous*/, - [this.contextId], - t.blockStatement([this.getDispatchLoop()]), - false, // Not a generator anymore! - false // Nor an expression. +Ep.getContextFunction = function (id) { + return t.functionExpression(id || null, /*Anonymous*/ + [this.contextId], t.blockStatement([this.getDispatchLoop()]), false, // Not a generator anymore! + false // Nor an expression. ); }; @@ -223,27 +207,24 @@ Ep.getContextFunction = function(id) { // // Each marked location in this.listing will correspond to one generated // case statement. -Ep.getDispatchLoop = function() { +Ep.getDispatchLoop = function () { var self = this; var cases = []; - var current; + var current = undefined; // If we encounter a break, continue, or return statement in a switch // case, we can skip the rest of the statements until the next case. var alreadyEnded = false; - self.listing.forEach(function(stmt, i) { + self.listing.forEach(function (stmt, i) { if (self.marked.hasOwnProperty(i)) { - cases.push(t.switchCase( - t.numericLiteral(i), - current = [])); + cases.push(t.switchCase(t.numericLiteral(i), current = [])); alreadyEnded = false; } if (!alreadyEnded) { current.push(stmt); - if (t.isCompletionStatement(stmt)) - alreadyEnded = true; + if (t.isCompletionStatement(stmt)) alreadyEnded = true; } }); @@ -251,35 +232,20 @@ Ep.getDispatchLoop = function() { // we can finally resolve this.finalLoc.value. this.finalLoc.value = this.listing.length; - cases.push( - t.switchCase(this.finalLoc, [ - // Intentionally fall through to the "end" case... - ]), + cases.push(t.switchCase(this.finalLoc, [ + // Intentionally fall through to the "end" case... + ]), - // So that the runtime can jump to the final location without having - // to know its offset, we provide the "end" case as a synonym. - t.switchCase(t.stringLiteral("end"), [ - // This will check/clear both context.thrown and context.rval. - t.returnStatement( - t.callExpression(this.contextProperty("stop"), []) - ) - ]) - ); + // So that the runtime can jump to the final location without having + // to know its offset, we provide the "end" case as a synonym. + t.switchCase(t.stringLiteral("end"), [ + // This will check/clear both context.thrown and context.rval. + t.returnStatement(t.callExpression(this.contextProperty("stop"), []))])); - return t.whileStatement( - t.numericLiteral(1), - t.switchStatement( - t.assignmentExpression( - "=", - this.contextProperty("prev"), - this.contextProperty("next") - ), - cases - ) - ); + return t.whileStatement(t.numericLiteral(1), t.switchStatement(t.assignmentExpression("=", this.contextProperty("prev"), this.contextProperty("next")), cases)); }; -Ep.getTryLocsList = function() { +Ep.getTryLocsList = function () { if (this.tryEntries.length === 0) { // To avoid adding a needless [] to the majority of runtime.wrap // argument lists, force the caller to handle this case specially. @@ -288,29 +254,25 @@ Ep.getTryLocsList = function() { var lastLocValue = 0; - return t.arrayExpression( - this.tryEntries.map(function(tryEntry) { - var thisLocValue = tryEntry.firstLoc.value; - assert.ok(thisLocValue >= lastLocValue, "try entries out of order"); - lastLocValue = thisLocValue; + return t.arrayExpression(this.tryEntries.map(function (tryEntry) { + var thisLocValue = tryEntry.firstLoc.value; + _assert2["default"].ok(thisLocValue >= lastLocValue, "try entries out of order"); + lastLocValue = thisLocValue; - var ce = tryEntry.catchEntry; - var fe = tryEntry.finallyEntry; + var ce = tryEntry.catchEntry; + var fe = tryEntry.finallyEntry; - var locs = [ - tryEntry.firstLoc, - // The null here makes a hole in the array. - ce ? ce.firstLoc : null - ]; + var locs = [tryEntry.firstLoc, + // The null here makes a hole in the array. + ce ? ce.firstLoc : null]; - if (fe) { - locs[2] = fe.firstLoc; - locs[3] = fe.afterLoc; - } + if (fe) { + locs[2] = fe.firstLoc; + locs[3] = fe.afterLoc; + } - return t.arrayExpression(locs); - }) - ); + return t.arrayExpression(locs); + })); }; // All side effects must be realized in order. @@ -320,56 +282,47 @@ Ep.getTryLocsList = function() { // No destructive modification of AST nodes. -Ep.explode = function(path, ignoreResult) { +Ep.explode = function (path, ignoreResult) { var node = path.node; var self = this; t.assertNode(node); - if (t.isDeclaration(node)) - throw getDeclError(node); + if (t.isDeclaration(node)) throw getDeclError(node); - if (t.isStatement(node)) - return self.explodeStatement(path); + if (t.isStatement(node)) return self.explodeStatement(path); - if (t.isExpression(node)) - return self.explodeExpression(path, ignoreResult); + if (t.isExpression(node)) return self.explodeExpression(path, ignoreResult); switch (node.type) { - case "Program": - return path.get("body").map( - self.explodeStatement, - self - ); + case "Program": + return path.get("body").map(self.explodeStatement, self); - case "VariableDeclarator": - throw getDeclError(node); + case "VariableDeclarator": + throw getDeclError(node); - // These node types should be handled by their parent nodes - // (ObjectExpression, SwitchStatement, and TryStatement, respectively). - case "Property": - case "SwitchCase": - case "CatchClause": - throw new Error( - node.type + " nodes should be handled by their parents"); + // These node types should be handled by their parent nodes + // (ObjectExpression, SwitchStatement, and TryStatement, respectively). + case "Property": + case "SwitchCase": + case "CatchClause": + throw new Error(node.type + " nodes should be handled by their parents"); - default: - throw new Error( - "unknown Node of type " + - JSON.stringify(node.type)); + default: + throw new Error("unknown Node of type " + JSON.stringify(node.type)); } }; function getDeclError(node) { - return new Error( - "all declarations should have been transformed into " + - "assignments before the Exploder began its work: " + - JSON.stringify(node)); + return new Error("all declarations should have been transformed into " + "assignments before the Exploder began its work: " + JSON.stringify(node)); } -Ep.explodeStatement = function(path, labelId) { +Ep.explodeStatement = function (path, labelId) { var stmt = path.node; var self = this; + var before = undefined, + after = undefined, + head = undefined; t.assertStatement(stmt); @@ -399,373 +352,308 @@ Ep.explodeStatement = function(path, labelId) { } switch (stmt.type) { - case "ExpressionStatement": - self.explodeExpression(path.get("expression"), true); - break; + case "ExpressionStatement": + self.explodeExpression(path.get("expression"), true); + break; - case "LabeledStatement": - var after = loc(); + case "LabeledStatement": + after = loc(); - // Did you know you can break from any labeled block statement or - // control structure? Well, you can! Note: when a labeled loop is - // encountered, the leap.LabeledEntry created here will immediately - // enclose a leap.LoopEntry on the leap manager's stack, and both - // entries will have the same label. Though this works just fine, it - // may seem a bit redundant. In theory, we could check here to - // determine if stmt knows how to handle its own label; for example, - // stmt happens to be a WhileStatement and so we know it's going to - // establish its own LoopEntry when we explode it (below). Then this - // LabeledEntry would be unnecessary. Alternatively, we might be - // tempted not to pass stmt.label down into self.explodeStatement, - // because we've handled the label here, but that's a mistake because - // labeled loops may contain labeled continue statements, which is not - // something we can handle in this generic case. All in all, I think a - // little redundancy greatly simplifies the logic of this case, since - // it's clear that we handle all possible LabeledStatements correctly - // here, regardless of whether they interact with the leap manager - // themselves. Also remember that labels and break/continue-to-label - // statements are rare, and all of this logic happens at transform - // time, so it has no additional runtime cost. - self.leapManager.withEntry( - new leap.LabeledEntry(after, stmt.label), - function() { + // Did you know you can break from any labeled block statement or + // control structure? Well, you can! Note: when a labeled loop is + // encountered, the leap.LabeledEntry created here will immediately + // enclose a leap.LoopEntry on the leap manager's stack, and both + // entries will have the same label. Though this works just fine, it + // may seem a bit redundant. In theory, we could check here to + // determine if stmt knows how to handle its own label; for example, + // stmt happens to be a WhileStatement and so we know it's going to + // establish its own LoopEntry when we explode it (below). Then this + // LabeledEntry would be unnecessary. Alternatively, we might be + // tempted not to pass stmt.label down into self.explodeStatement, + // because we've handled the label here, but that's a mistake because + // labeled loops may contain labeled continue statements, which is not + // something we can handle in this generic case. All in all, I think a + // little redundancy greatly simplifies the logic of this case, since + // it's clear that we handle all possible LabeledStatements correctly + // here, regardless of whether they interact with the leap manager + // themselves. Also remember that labels and break/continue-to-label + // statements are rare, and all of this logic happens at transform + // time, so it has no additional runtime cost. + self.leapManager.withEntry(new leap.LabeledEntry(after, stmt.label), function () { self.explodeStatement(path.get("body"), stmt.label); - } - ); + }); - self.mark(after); + self.mark(after); - break; + break; - case "WhileStatement": - var before = loc(); - var after = loc(); + case "WhileStatement": + before = loc(); + after = loc(); - self.mark(before); - self.jumpIfNot(self.explodeExpression(path.get("test")), after); - self.leapManager.withEntry( - new leap.LoopEntry(after, before, labelId), - function() { self.explodeStatement(path.get("body")); } - ); - self.jump(before); - self.mark(after); - - break; - - case "DoWhileStatement": - var first = loc(); - var test = loc(); - var after = loc(); - - self.mark(first); - self.leapManager.withEntry( - new leap.LoopEntry(after, test, labelId), - function() { self.explode(path.get("body")); } - ); - self.mark(test); - self.jumpIf(self.explodeExpression(path.get("test")), first); - self.mark(after); - - break; - - case "ForStatement": - var head = loc(); - var update = loc(); - var after = loc(); - - if (stmt.init) { - // We pass true here to indicate that if stmt.init is an expression - // then we do not care about its result. - self.explode(path.get("init"), true); - } - - self.mark(head); - - if (stmt.test) { + self.mark(before); self.jumpIfNot(self.explodeExpression(path.get("test")), after); - } else { - // No test means continue unconditionally. - } + self.leapManager.withEntry(new leap.LoopEntry(after, before, labelId), function () { + self.explodeStatement(path.get("body")); + }); + self.jump(before); + self.mark(after); - self.leapManager.withEntry( - new leap.LoopEntry(after, update, labelId), - function() { self.explodeStatement(path.get("body")); } - ); + break; - self.mark(update); + case "DoWhileStatement": + var first = loc(); + var test = loc(); + after = loc(); - if (stmt.update) { - // We pass true here to indicate that if stmt.update is an - // expression then we do not care about its result. - self.explode(path.get("update"), true); - } + self.mark(first); + self.leapManager.withEntry(new leap.LoopEntry(after, test, labelId), function () { + self.explode(path.get("body")); + }); + self.mark(test); + self.jumpIf(self.explodeExpression(path.get("test")), first); + self.mark(after); - self.jump(head); + break; - self.mark(after); + case "ForStatement": + head = loc(); + var update = loc(); + after = loc(); - break; - - case "TypeCastExpression": - return self.explodeExpression(path.get("expression")); - - case "ForInStatement": - var head = loc(); - var after = loc(); - - var keyIterNextFn = self.makeTempVar(); - self.emitAssign( - keyIterNextFn, - t.callExpression( - runtimeProperty("keys"), - [self.explodeExpression(path.get("right"))] - ) - ); - - self.mark(head); - - var keyInfoTmpVar = self.makeTempVar(); - self.jumpIf( - t.memberExpression( - t.assignmentExpression( - "=", - keyInfoTmpVar, - t.callExpression(keyIterNextFn, []) - ), - t.identifier("done"), - false - ), - after - ); - - self.emitAssign( - stmt.left, - t.memberExpression( - keyInfoTmpVar, - t.identifier("value"), - false - ) - ); - - self.leapManager.withEntry( - new leap.LoopEntry(after, head, labelId), - function() { self.explodeStatement(path.get("body")); } - ); - - self.jump(head); - - self.mark(after); - - break; - - case "BreakStatement": - self.emitAbruptCompletion({ - type: "break", - target: self.leapManager.getBreakLoc(stmt.label) - }); - - break; - - case "ContinueStatement": - self.emitAbruptCompletion({ - type: "continue", - target: self.leapManager.getContinueLoc(stmt.label) - }); - - break; - - case "SwitchStatement": - // Always save the discriminant into a temporary variable in case the - // test expressions overwrite values like context.sent. - var disc = self.emitAssign( - self.makeTempVar(), - self.explodeExpression(path.get("discriminant")) - ); - - var after = loc(); - var defaultLoc = loc(); - var condition = defaultLoc; - var caseLocs = []; - - // If there are no cases, .cases might be undefined. - var cases = stmt.cases || []; - - for (var i = cases.length - 1; i >= 0; --i) { - var c = cases[i]; - t.assertSwitchCase(c); - - if (c.test) { - condition = t.conditionalExpression( - t.binaryExpression("===", disc, c.test), - caseLocs[i] = loc(), - condition - ); - } else { - caseLocs[i] = defaultLoc; + if (stmt.init) { + // We pass true here to indicate that if stmt.init is an expression + // then we do not care about its result. + self.explode(path.get("init"), true); } - } - var discriminant = path.get("discriminant"); - discriminant.replaceWith(condition); - self.jump(self.explodeExpression(discriminant)); + self.mark(head); - self.leapManager.withEntry( - new leap.SwitchEntry(after), - function() { - path.get("cases").forEach(function(casePath) { - var c = casePath.node; + if (stmt.test) { + self.jumpIfNot(self.explodeExpression(path.get("test")), after); + } else { + // No test means continue unconditionally. + } + + self.leapManager.withEntry(new leap.LoopEntry(after, update, labelId), function () { + self.explodeStatement(path.get("body")); + }); + + self.mark(update); + + if (stmt.update) { + // We pass true here to indicate that if stmt.update is an + // expression then we do not care about its result. + self.explode(path.get("update"), true); + } + + self.jump(head); + + self.mark(after); + + break; + + case "TypeCastExpression": + return self.explodeExpression(path.get("expression")); + + case "ForInStatement": + head = loc(); + after = loc(); + + var keyIterNextFn = self.makeTempVar(); + self.emitAssign(keyIterNextFn, t.callExpression(util.runtimeProperty("keys"), [self.explodeExpression(path.get("right"))])); + + self.mark(head); + + var keyInfoTmpVar = self.makeTempVar(); + self.jumpIf(t.memberExpression(t.assignmentExpression("=", keyInfoTmpVar, t.callExpression(keyIterNextFn, [])), t.identifier("done"), false), after); + + self.emitAssign(stmt.left, t.memberExpression(keyInfoTmpVar, t.identifier("value"), false)); + + self.leapManager.withEntry(new leap.LoopEntry(after, head, labelId), function () { + self.explodeStatement(path.get("body")); + }); + + self.jump(head); + + self.mark(after); + + break; + + case "BreakStatement": + self.emitAbruptCompletion({ + type: "break", + target: self.leapManager.getBreakLoc(stmt.label) + }); + + break; + + case "ContinueStatement": + self.emitAbruptCompletion({ + type: "continue", + target: self.leapManager.getContinueLoc(stmt.label) + }); + + break; + + case "SwitchStatement": + // Always save the discriminant into a temporary variable in case the + // test expressions overwrite values like context.sent. + var disc = self.emitAssign(self.makeTempVar(), self.explodeExpression(path.get("discriminant"))); + + after = loc(); + var defaultLoc = loc(); + var condition = defaultLoc; + var caseLocs = []; + + // If there are no cases, .cases might be undefined. + var cases = stmt.cases || []; + + for (var i = cases.length - 1; i >= 0; --i) { + var c = cases[i]; + t.assertSwitchCase(c); + + if (c.test) { + condition = t.conditionalExpression(t.binaryExpression("===", disc, c.test), caseLocs[i] = loc(), condition); + } else { + caseLocs[i] = defaultLoc; + } + } + + var discriminant = path.get("discriminant"); + discriminant.replaceWith(condition); + self.jump(self.explodeExpression(discriminant)); + + self.leapManager.withEntry(new leap.SwitchEntry(after), function () { + path.get("cases").forEach(function (casePath) { var i = casePath.key; - self.mark(caseLocs[i]); casePath.get("consequent").forEach(function (path) { self.explodeStatement(path); }); }); + }); + + self.mark(after); + if (defaultLoc.value === -1) { + self.mark(defaultLoc); + _assert2["default"].strictEqual(after.value, defaultLoc.value); } - ); - self.mark(after); - if (defaultLoc.value === -1) { - self.mark(defaultLoc); - assert.strictEqual(after.value, defaultLoc.value); - } + break; - break; + case "IfStatement": + var elseLoc = stmt.alternate && loc(); + after = loc(); - case "IfStatement": - var elseLoc = stmt.alternate && loc(); - var after = loc(); + self.jumpIfNot(self.explodeExpression(path.get("test")), elseLoc || after); - self.jumpIfNot( - self.explodeExpression(path.get("test")), - elseLoc || after - ); + self.explodeStatement(path.get("consequent")); - self.explodeStatement(path.get("consequent")); + if (elseLoc) { + self.jump(after); + self.mark(elseLoc); + self.explodeStatement(path.get("alternate")); + } - if (elseLoc) { - self.jump(after); - self.mark(elseLoc); - self.explodeStatement(path.get("alternate")); - } + self.mark(after); - self.mark(after); + break; - break; + case "ReturnStatement": + self.emitAbruptCompletion({ + type: "return", + value: self.explodeExpression(path.get("argument")) + }); - case "ReturnStatement": - self.emitAbruptCompletion({ - type: "return", - value: self.explodeExpression(path.get("argument")) - }); + break; - break; + case "WithStatement": + throw new Error("WithStatement not supported in generator functions."); - case "WithStatement": - throw new Error( - node.type + " not supported in generator functions."); + case "TryStatement": + after = loc(); - case "TryStatement": - var after = loc(); + var handler = stmt.handler; - var handler = stmt.handler; + var catchLoc = handler && loc(); + var catchEntry = catchLoc && new leap.CatchEntry(catchLoc, handler.param); - var catchLoc = handler && loc(); - var catchEntry = catchLoc && new leap.CatchEntry( - catchLoc, - handler.param - ); + var finallyLoc = stmt.finalizer && loc(); + var finallyEntry = finallyLoc && new leap.FinallyEntry(finallyLoc, after); - var finallyLoc = stmt.finalizer && loc(); - var finallyEntry = finallyLoc && - new leap.FinallyEntry(finallyLoc, after); + var tryEntry = new leap.TryEntry(self.getUnmarkedCurrentLoc(), catchEntry, finallyEntry); - var tryEntry = new leap.TryEntry( - self.getUnmarkedCurrentLoc(), - catchEntry, - finallyEntry - ); + self.tryEntries.push(tryEntry); + self.updateContextPrevLoc(tryEntry.firstLoc); - self.tryEntries.push(tryEntry); - self.updateContextPrevLoc(tryEntry.firstLoc); + self.leapManager.withEntry(tryEntry, function () { + self.explodeStatement(path.get("block")); - self.leapManager.withEntry(tryEntry, function() { - self.explodeStatement(path.get("block")); + if (catchLoc) { + (function () { + if (finallyLoc) { + // If we have both a catch block and a finally block, then + // because we emit the catch block first, we need to jump over + // it to the finally block. + self.jump(finallyLoc); + } else { + // If there is no finally block, then we need to jump over the + // catch block to the fall-through location. + self.jump(after); + } - if (catchLoc) { - if (finallyLoc) { - // If we have both a catch block and a finally block, then - // because we emit the catch block first, we need to jump over - // it to the finally block. - self.jump(finallyLoc); + self.updateContextPrevLoc(self.mark(catchLoc)); - } else { - // If there is no finally block, then we need to jump over the - // catch block to the fall-through location. - self.jump(after); + var bodyPath = path.get("handler.body"); + var safeParam = self.makeTempVar(); + self.clearPendingException(tryEntry.firstLoc, safeParam); + + bodyPath.traverse(catchParamVisitor, { + safeParam: safeParam, + catchParamName: handler.param.name + }); + + self.leapManager.withEntry(catchEntry, function () { + self.explodeStatement(bodyPath); + }); + })(); } - self.updateContextPrevLoc(self.mark(catchLoc)); + if (finallyLoc) { + self.updateContextPrevLoc(self.mark(finallyLoc)); - var bodyPath = path.get("handler.body"); - var safeParam = self.makeTempVar(); - self.clearPendingException(tryEntry.firstLoc, safeParam); + self.leapManager.withEntry(finallyEntry, function () { + self.explodeStatement(path.get("finalizer")); + }); - var catchScope = bodyPath.scope; - // TODO: t.assertCatchClause(catchScope.block); - // TODO: assert.strictEqual(catchScope.lookup(catchParamName), catchScope); + self.emit(t.returnStatement(t.callExpression(self.contextProperty("finish"), [finallyEntry.firstLoc]))); + } + }); - bodyPath.traverse(catchParamVisitor, { - safeParam: safeParam, - catchParamName: handler.param.name - }); + self.mark(after); - self.leapManager.withEntry(catchEntry, function() { - self.explodeStatement(bodyPath); - }); - } + break; - if (finallyLoc) { - self.updateContextPrevLoc(self.mark(finallyLoc)); + case "ThrowStatement": + self.emit(t.throwStatement(self.explodeExpression(path.get("argument")))); - self.leapManager.withEntry(finallyEntry, function() { - self.explodeStatement(path.get("finalizer")); - }); + break; - self.emit(t.returnStatement(t.callExpression( - self.contextProperty("finish"), - [finallyEntry.firstLoc] - ))); - } - }); - - self.mark(after); - - break; - - case "ThrowStatement": - self.emit(t.throwStatement( - self.explodeExpression(path.get("argument")) - )); - - break; - - default: - throw new Error( - "unknown Statement of type " + - JSON.stringify(stmt.type)); + default: + throw new Error("unknown Statement of type " + JSON.stringify(stmt.type)); } }; var catchParamVisitor = { - Identifier: function(path, state) { + Identifier: function Identifier(path, state) { if (path.node.name === state.catchParamName && util.isReference(path)) { path.replaceWith(state.safeParam); } }, - Scope: function(path, state) { + Scope: function Scope(path, state) { if (path.scope.hasOwnBinding(state.catchParamName)) { // Don't descend into nested scopes that shadow the catch // parameter with their own declarations. @@ -774,42 +662,26 @@ var catchParamVisitor = { } }; -Ep.emitAbruptCompletion = function(record) { +Ep.emitAbruptCompletion = function (record) { if (!isValidCompletion(record)) { - assert.ok( - false, - "invalid completion record: " + - JSON.stringify(record) - ); + _assert2["default"].ok(false, "invalid completion record: " + JSON.stringify(record)); } - assert.notStrictEqual( - record.type, "normal", - "normal completions are not abrupt" - ); + _assert2["default"].notStrictEqual(record.type, "normal", "normal completions are not abrupt"); var abruptArgs = [t.stringLiteral(record.type)]; - if (record.type === "break" || - record.type === "continue") { + if (record.type === "break" || record.type === "continue") { t.assertLiteral(record.target); abruptArgs[1] = record.target; - } else if (record.type === "return" || - record.type === "throw") { + } else if (record.type === "return" || record.type === "throw") { if (record.value) { t.assertExpression(record.value); abruptArgs[1] = record.value; } } - this.emit( - t.returnStatement( - t.callExpression( - this.contextProperty("abrupt"), - abruptArgs - ) - ) - ); + this.emit(t.returnStatement(t.callExpression(this.contextProperty("abrupt"), abruptArgs))); }; function isValidCompletion(record) { @@ -819,22 +691,17 @@ function isValidCompletion(record) { return !hasOwn.call(record, "target"); } - if (type === "break" || - type === "continue") { - return !hasOwn.call(record, "value") - && t.isLiteral(record.target); + if (type === "break" || type === "continue") { + return !hasOwn.call(record, "value") && t.isLiteral(record.target); } - if (type === "return" || - type === "throw") { - return hasOwn.call(record, "value") - && !hasOwn.call(record, "target"); + if (type === "return" || type === "throw") { + return hasOwn.call(record, "value") && !hasOwn.call(record, "target"); } return false; } - // Not all offsets into emitter.listing are potential jump targets. For // example, execution typically falls into the beginning of a try block // without jumping directly there. This method returns the current offset @@ -844,7 +711,7 @@ function isValidCompletion(record) { // statements). There's no logical harm in marking such locations as jump // targets, but minimizing the number of switch cases keeps the generated // code shorter. -Ep.getUnmarkedCurrentLoc = function() { +Ep.getUnmarkedCurrentLoc = function () { return t.numericLiteral(this.listing.length); }; @@ -858,7 +725,7 @@ Ep.getUnmarkedCurrentLoc = function() { // would know the location of the current instruction with complete // precision at all times, but we don't have that luxury here, as it would // be costly and verbose to set context.prev before every statement. -Ep.updateContextPrevLoc = function(loc) { +Ep.updateContextPrevLoc = function (loc) { if (loc) { t.assertLiteral(loc); @@ -868,9 +735,8 @@ Ep.updateContextPrevLoc = function(loc) { loc.value = this.listing.length; } else { // Otherwise assert that the location matches the current offset. - assert.strictEqual(loc.value, this.listing.length); + _assert2["default"].strictEqual(loc.value, this.listing.length); } - } else { loc = this.getUnmarkedCurrentLoc(); } @@ -881,7 +747,7 @@ Ep.updateContextPrevLoc = function(loc) { this.emitAssign(this.contextProperty("prev"), loc); }; -Ep.explodeExpression = function(path, ignoreResult) { +Ep.explodeExpression = function (path, ignoreResult) { var expr = path.node; if (expr) { t.assertExpression(expr); @@ -890,7 +756,7 @@ Ep.explodeExpression = function(path, ignoreResult) { } var self = this; - var result; // Used optionally by several cases below. + var result = undefined; // Used optionally by several cases below. function finish(expr) { t.assertExpression(expr); @@ -923,35 +789,27 @@ Ep.explodeExpression = function(path, ignoreResult) { // control the precise order in which the generated code realizes the // side effects of those subexpressions. function explodeViaTempVar(tempVar, childPath, ignoreChildResult) { - assert.ok( - !ignoreChildResult || !tempVar, - "Ignoring the result of a child expression but forcing it to " + - "be assigned to a temporary variable?" - ); + _assert2["default"].ok(!ignoreChildResult || !tempVar, "Ignoring the result of a child expression but forcing it to " + "be assigned to a temporary variable?"); var result = self.explodeExpression(childPath, ignoreChildResult); if (ignoreChildResult) { // Side effects already emitted above. - } else if (tempVar || (hasLeapingChildren && - !t.isLiteral(result))) { - // If tempVar was provided, then the result will always be assigned - // to it, even if the result does not otherwise need to be assigned - // to a temporary variable. When no tempVar is provided, we have - // the flexibility to decide whether a temporary variable is really - // necessary. Unfortunately, in general, a temporary variable is - // required whenever any child contains a yield expression, since it - // is difficult to prove (at all, let alone efficiently) whether - // this result would evaluate to the same value before and after the - // yield (see #206). One narrow case where we can prove it doesn't - // matter (and thus we do not need a temporary variable) is when the - // result in question is a Literal value. - result = self.emitAssign( - tempVar || self.makeTempVar(), - result - ); - } + } else if (tempVar || hasLeapingChildren && !t.isLiteral(result)) { + // If tempVar was provided, then the result will always be assigned + // to it, even if the result does not otherwise need to be assigned + // to a temporary variable. When no tempVar is provided, we have + // the flexibility to decide whether a temporary variable is really + // necessary. Unfortunately, in general, a temporary variable is + // required whenever any child contains a yield expression, since it + // is difficult to prove (at all, let alone efficiently) whether + // this result would evaluate to the same value before and after the + // yield (see #206). One narrow case where we can prove it doesn't + // matter (and thus we do not need a temporary variable) is when the + // result in question is a Literal value. + result = self.emitAssign(tempVar || self.makeTempVar(), result); + } return result; } @@ -960,236 +818,175 @@ Ep.explodeExpression = function(path, ignoreResult) { // return a result. switch (expr.type) { - case "MemberExpression": - return finish(t.memberExpression( - self.explodeExpression(path.get("object")), - expr.computed - ? explodeViaTempVar(null, path.get("property")) - : expr.property, - expr.computed - )); + case "MemberExpression": + return finish(t.memberExpression(self.explodeExpression(path.get("object")), expr.computed ? explodeViaTempVar(null, path.get("property")) : expr.property, expr.computed)); - case "CallExpression": - var calleePath = path.get("callee"); - var argsPath = path.get("arguments"); + case "CallExpression": + var calleePath = path.get("callee"); + var argsPath = path.get("arguments"); - var newCallee; - var newArgs = []; + var newCallee = undefined; + var newArgs = []; - var hasLeapingArgs = false; - argsPath.forEach(function(argPath) { - hasLeapingArgs = hasLeapingArgs || - meta.containsLeap(argPath.node); - }); + var hasLeapingArgs = false; + argsPath.forEach(function (argPath) { + hasLeapingArgs = hasLeapingArgs || meta.containsLeap(argPath.node); + }); - if (t.isMemberExpression(calleePath.node)) { - if (hasLeapingArgs) { - // If the arguments of the CallExpression contained any yield - // expressions, then we need to be sure to evaluate the callee - // before evaluating the arguments, but if the callee was a member - // expression, then we must be careful that the object of the - // member expression still gets bound to `this` for the call. + if (t.isMemberExpression(calleePath.node)) { + if (hasLeapingArgs) { + // If the arguments of the CallExpression contained any yield + // expressions, then we need to be sure to evaluate the callee + // before evaluating the arguments, but if the callee was a member + // expression, then we must be careful that the object of the + // member expression still gets bound to `this` for the call. - var newObject = explodeViaTempVar( + var newObject = explodeViaTempVar( // Assign the exploded callee.object expression to a temporary // variable so that we can use it twice without reevaluating it. - self.makeTempVar(), - calleePath.get("object") - ); + self.makeTempVar(), calleePath.get("object")); - var newProperty = calleePath.node.computed - ? explodeViaTempVar(null, calleePath.get("property")) - : calleePath.node.property; + var newProperty = calleePath.node.computed ? explodeViaTempVar(null, calleePath.get("property")) : calleePath.node.property; - newArgs.unshift(newObject); - - newCallee = t.memberExpression( - t.memberExpression( - newObject, - newProperty, - calleePath.node.computed - ), - t.identifier("call"), - false - ); + newArgs.unshift(newObject); + newCallee = t.memberExpression(t.memberExpression(newObject, newProperty, calleePath.node.computed), t.identifier("call"), false); + } else { + newCallee = self.explodeExpression(calleePath); + } } else { newCallee = self.explodeExpression(calleePath); + + if (t.isMemberExpression(newCallee)) { + // If the callee was not previously a MemberExpression, then the + // CallExpression was "unqualified," meaning its `this` object + // should be the global object. If the exploded expression has + // become a MemberExpression (e.g. a context property, probably a + // temporary variable), then we need to force it to be unqualified + // by using the (0, object.property)(...) trick; otherwise, it + // will receive the object of the MemberExpression as its `this` + // object. + newCallee = t.sequenceExpression([t.numericLiteral(0), newCallee]); + } } - } else { - newCallee = self.explodeExpression(calleePath); + argsPath.forEach(function (argPath) { + newArgs.push(explodeViaTempVar(null, argPath)); + }); - if (t.isMemberExpression(newCallee)) { - // If the callee was not previously a MemberExpression, then the - // CallExpression was "unqualified," meaning its `this` object - // should be the global object. If the exploded expression has - // become a MemberExpression (e.g. a context property, probably a - // temporary variable), then we need to force it to be unqualified - // by using the (0, object.property)(...) trick; otherwise, it - // will receive the object of the MemberExpression as its `this` - // object. - newCallee = t.sequenceExpression([ - t.numericLiteral(0), - newCallee - ]); - } - } + return finish(t.callExpression(newCallee, newArgs)); - argsPath.forEach(function(argPath) { - newArgs.push(explodeViaTempVar(null, argPath)); - }); - - return finish(t.callExpression( - newCallee, - newArgs - )); - - case "NewExpression": - return finish(t.newExpression( - explodeViaTempVar(null, path.get("callee")), - path.get("arguments").map(function(argPath) { + case "NewExpression": + return finish(t.newExpression(explodeViaTempVar(null, path.get("callee")), path.get("arguments").map(function (argPath) { return explodeViaTempVar(null, argPath); - }) - )); + }))); - case "ObjectExpression": - return finish(t.objectExpression( - path.get("properties").map(function(propPath) { + case "ObjectExpression": + return finish(t.objectExpression(path.get("properties").map(function (propPath) { if (propPath.isObjectProperty()) { - return t.objectProperty( - propPath.node.key, - explodeViaTempVar(null, propPath.get("value")), - propPath.node.computed - ); + return t.objectProperty(propPath.node.key, explodeViaTempVar(null, propPath.get("value")), propPath.node.computed); } else { return propPath.node; } - }) - )); + }))); - case "ArrayExpression": - return finish(t.arrayExpression( - path.get("elements").map(function(elemPath) { + case "ArrayExpression": + return finish(t.arrayExpression(path.get("elements").map(function (elemPath) { return explodeViaTempVar(null, elemPath); - }) - )); + }))); - case "SequenceExpression": - var lastIndex = expr.expressions.length - 1; + case "SequenceExpression": + var lastIndex = expr.expressions.length - 1; - path.get("expressions").forEach(function(exprPath) { - if (exprPath.key === lastIndex) { - result = self.explodeExpression(exprPath, ignoreResult); - } else { - self.explodeExpression(exprPath, true); + path.get("expressions").forEach(function (exprPath) { + if (exprPath.key === lastIndex) { + result = self.explodeExpression(exprPath, ignoreResult); + } else { + self.explodeExpression(exprPath, true); + } + }); + + return result; + + case "LogicalExpression": + after = loc(); + + if (!ignoreResult) { + result = self.makeTempVar(); } - }); - return result; + var left = explodeViaTempVar(result, path.get("left")); - case "LogicalExpression": - var after = loc(); + if (expr.operator === "&&") { + self.jumpIfNot(left, after); + } else { + _assert2["default"].strictEqual(expr.operator, "||"); + self.jumpIf(left, after); + } - if (!ignoreResult) { - result = self.makeTempVar(); - } - - var left = explodeViaTempVar(result, path.get("left")); - - if (expr.operator === "&&") { - self.jumpIfNot(left, after); - } else { - assert.strictEqual(expr.operator, "||"); - self.jumpIf(left, after); - } - - explodeViaTempVar(result, path.get("right"), ignoreResult); - - self.mark(after); - - return result; - - case "ConditionalExpression": - var elseLoc = loc(); - var after = loc(); - var test = self.explodeExpression(path.get("test")); - - self.jumpIfNot(test, elseLoc); - - if (!ignoreResult) { - result = self.makeTempVar(); - } - - explodeViaTempVar(result, path.get("consequent"), ignoreResult); - self.jump(after); - - self.mark(elseLoc); - explodeViaTempVar(result, path.get("alternate"), ignoreResult); - - self.mark(after); - - return result; - - case "UnaryExpression": - return finish(t.unaryExpression( - expr.operator, - // Can't (and don't need to) break up the syntax of the argument. - // Think about delete a[b]. - self.explodeExpression(path.get("argument")), - !!expr.prefix - )); - - case "BinaryExpression": - return finish(t.binaryExpression( - expr.operator, - explodeViaTempVar(null, path.get("left")), - explodeViaTempVar(null, path.get("right")) - )); - - case "AssignmentExpression": - return finish(t.assignmentExpression( - expr.operator, - self.explodeExpression(path.get("left")), - self.explodeExpression(path.get("right")) - )); - - case "UpdateExpression": - return finish(t.updateExpression( - expr.operator, - self.explodeExpression(path.get("argument")), - expr.prefix - )); - - case "YieldExpression": - var after = loc(); - var arg = expr.argument && self.explodeExpression(path.get("argument")); - - if (arg && expr.delegate) { - var result = self.makeTempVar(); - - self.emit(t.returnStatement(t.callExpression( - self.contextProperty("delegateYield"), [ - arg, - t.stringLiteral(result.property.name), - after - ] - ))); + explodeViaTempVar(result, path.get("right"), ignoreResult); self.mark(after); return result; - } - self.emitAssign(self.contextProperty("next"), after); - self.emit(t.returnStatement(arg || null)); - self.mark(after); + case "ConditionalExpression": + var elseLoc = loc(); + after = loc(); + var test = self.explodeExpression(path.get("test")); - return self.contextProperty("sent"); + self.jumpIfNot(test, elseLoc); - default: - throw new Error( - "unknown Expression of type " + - JSON.stringify(expr.type)); + if (!ignoreResult) { + result = self.makeTempVar(); + } + + explodeViaTempVar(result, path.get("consequent"), ignoreResult); + self.jump(after); + + self.mark(elseLoc); + explodeViaTempVar(result, path.get("alternate"), ignoreResult); + + self.mark(after); + + return result; + + case "UnaryExpression": + return finish(t.unaryExpression(expr.operator, + // Can't (and don't need to) break up the syntax of the argument. + // Think about delete a[b]. + self.explodeExpression(path.get("argument")), !!expr.prefix)); + + case "BinaryExpression": + return finish(t.binaryExpression(expr.operator, explodeViaTempVar(null, path.get("left")), explodeViaTempVar(null, path.get("right")))); + + case "AssignmentExpression": + return finish(t.assignmentExpression(expr.operator, self.explodeExpression(path.get("left")), self.explodeExpression(path.get("right")))); + + case "UpdateExpression": + return finish(t.updateExpression(expr.operator, self.explodeExpression(path.get("argument")), expr.prefix)); + + case "YieldExpression": + after = loc(); + var arg = expr.argument && self.explodeExpression(path.get("argument")); + + if (arg && expr.delegate) { + var _result = self.makeTempVar(); + + self.emit(t.returnStatement(t.callExpression(self.contextProperty("delegateYield"), [arg, t.stringLiteral(_result.property.name), after]))); + + self.mark(after); + + return _result; + } + + self.emitAssign(self.contextProperty("next"), after); + self.emit(t.returnStatement(arg || null)); + self.mark(after); + + return self.contextProperty("sent"); + + default: + throw new Error("unknown Expression of type " + JSON.stringify(expr.type)); } -}; +}; \ No newline at end of file diff --git a/packages/babel-plugin-transform-regenerator/lib/hoist.js b/packages/babel-plugin-transform-regenerator/lib/hoist.js index 9ca822485b..d05db03455 100644 --- a/packages/babel-plugin-transform-regenerator/lib/hoist.js +++ b/packages/babel-plugin-transform-regenerator/lib/hoist.js @@ -8,16 +8,23 @@ * the same directory. */ -var traverse = require("babel-traverse"); -var assert = require("assert"); -var t = require("babel-types"); +"use strict"; + +var _Object$keys = require("babel-runtime/core-js/object/keys")["default"]; + +var _interopRequireWildcard = require("babel-runtime/helpers/interop-require-wildcard")["default"]; + +var _babelTypes = require("babel-types"); + +var t = _interopRequireWildcard(_babelTypes); + var hasOwn = Object.prototype.hasOwnProperty; // The hoist function takes a FunctionExpression or FunctionDeclaration // and replaces any Declaration nodes in its body with assignments, then // returns a VariableDeclaration containing just the names of the removed // declarations. -exports.hoist = function(funPath) { +exports.hoist = function (funPath) { t.assertFunction(funPath.node); var vars = {}; @@ -27,30 +34,26 @@ exports.hoist = function(funPath) { // TODO assert.equal(vdec.kind, "var"); var exprs = []; - vdec.declarations.forEach(function(dec) { + vdec.declarations.forEach(function (dec) { vars[dec.id.name] = dec.id; if (dec.init) { - exprs.push(t.assignmentExpression( - "=", dec.id, dec.init - )); + exprs.push(t.assignmentExpression("=", dec.id, dec.init)); } else if (includeIdentifiers) { exprs.push(dec.id); } }); - if (exprs.length === 0) - return null; + if (exprs.length === 0) return null; - if (exprs.length === 1) - return exprs[0]; + if (exprs.length === 1) return exprs[0]; return t.sequenceExpression(exprs); } funPath.get("body").traverse({ VariableDeclaration: { - exit: function(path) { + exit: function exit(path) { var expr = varDeclToExpr(path.node, false); if (expr === null) { path.remove(); @@ -66,38 +69,25 @@ exports.hoist = function(funPath) { } }, - ForStatement: function(path) { + ForStatement: function ForStatement(path) { var init = path.node.init; if (t.isVariableDeclaration(init)) { path.get("init").replaceWith(varDeclToExpr(init, false)); } }, - ForXStatement: function(path) { + ForXStatement: function ForXStatement(path) { var left = path.get("left"); if (left.isVariableDeclaration()) { left.replaceWith(varDeclToExpr(left.node, true)); } }, - FunctionDeclaration: function(path) { + FunctionDeclaration: function FunctionDeclaration(path) { var node = path.node; vars[node.id.name] = node.id; - var parentNode = path.parent.node; - var assignment = t.expressionStatement( - t.assignmentExpression( - "=", - node.id, - t.functionExpression( - node.id, - node.params, - node.body, - node.generator, - node.expression - ) - ) - ); + var assignment = t.expressionStatement(t.assignmentExpression("=", node.id, t.functionExpression(node.id, node.params, node.body, node.generator, node.expression))); if (path.parentPath.isBlockStatement()) { // Insert the assignment form before the first statement in the @@ -118,14 +108,14 @@ exports.hoist = function(funPath) { path.skip(); }, - FunctionExpression: function(path) { + FunctionExpression: function FunctionExpression(path) { // Don't descend into nested function expressions. path.skip(); } }); var paramNames = {}; - funPath.get("params").forEach(function(paramPath) { + funPath.get("params").forEach(function (paramPath) { var param = paramPath.node; if (t.isIdentifier(param)) { paramNames[param.name] = param; @@ -137,7 +127,7 @@ exports.hoist = function(funPath) { var declarations = []; - Object.keys(vars).forEach(function(name) { + _Object$keys(vars).forEach(function (name) { if (!hasOwn.call(paramNames, name)) { declarations.push(t.variableDeclarator(vars[name], null)); } @@ -148,4 +138,4 @@ exports.hoist = function(funPath) { } return t.variableDeclaration("var", declarations); -}; +}; \ No newline at end of file diff --git a/packages/babel-plugin-transform-regenerator/lib/leap.js b/packages/babel-plugin-transform-regenerator/lib/leap.js index 7f06103d5b..011e9a9ec9 100644 --- a/packages/babel-plugin-transform-regenerator/lib/leap.js +++ b/packages/babel-plugin-transform-regenerator/lib/leap.js @@ -8,13 +8,24 @@ * the same directory. */ -var assert = require("assert"); -var t = require("babel-types"); -var inherits = require("util").inherits; -var hasOwn = Object.prototype.hasOwnProperty; +"use strict"; + +var _interopRequireDefault = require("babel-runtime/helpers/interop-require-default")["default"]; + +var _interopRequireWildcard = require("babel-runtime/helpers/interop-require-wildcard")["default"]; + +var _assert = require("assert"); + +var _assert2 = _interopRequireDefault(_assert); + +var _babelTypes = require("babel-types"); + +var t = _interopRequireWildcard(_babelTypes); + +var _util = require("util"); function Entry() { - assert.ok(this instanceof Entry); + _assert2["default"].ok(this instanceof Entry); } function FunctionEntry(returnLoc) { @@ -23,7 +34,7 @@ function FunctionEntry(returnLoc) { this.returnLoc = returnLoc; } -inherits(FunctionEntry, Entry); +_util.inherits(FunctionEntry, Entry); exports.FunctionEntry = FunctionEntry; function LoopEntry(breakLoc, continueLoc, label) { @@ -43,7 +54,7 @@ function LoopEntry(breakLoc, continueLoc, label) { this.label = label; } -inherits(LoopEntry, Entry); +_util.inherits(LoopEntry, Entry); exports.LoopEntry = LoopEntry; function SwitchEntry(breakLoc) { @@ -52,7 +63,7 @@ function SwitchEntry(breakLoc) { this.breakLoc = breakLoc; } -inherits(SwitchEntry, Entry); +_util.inherits(SwitchEntry, Entry); exports.SwitchEntry = SwitchEntry; function TryEntry(firstLoc, catchEntry, finallyEntry) { @@ -61,26 +72,26 @@ function TryEntry(firstLoc, catchEntry, finallyEntry) { t.assertLiteral(firstLoc); if (catchEntry) { - assert.ok(catchEntry instanceof CatchEntry); + _assert2["default"].ok(catchEntry instanceof CatchEntry); } else { catchEntry = null; } if (finallyEntry) { - assert.ok(finallyEntry instanceof FinallyEntry); + _assert2["default"].ok(finallyEntry instanceof FinallyEntry); } else { finallyEntry = null; } // Have to have one or the other (or both). - assert.ok(catchEntry || finallyEntry); + _assert2["default"].ok(catchEntry || finallyEntry); this.firstLoc = firstLoc; this.catchEntry = catchEntry; this.finallyEntry = finallyEntry; } -inherits(TryEntry, Entry); +_util.inherits(TryEntry, Entry); exports.TryEntry = TryEntry; function CatchEntry(firstLoc, paramId) { @@ -93,7 +104,7 @@ function CatchEntry(firstLoc, paramId) { this.paramId = paramId; } -inherits(CatchEntry, Entry); +_util.inherits(CatchEntry, Entry); exports.CatchEntry = CatchEntry; function FinallyEntry(firstLoc, afterLoc) { @@ -104,7 +115,7 @@ function FinallyEntry(firstLoc, afterLoc) { this.afterLoc = afterLoc; } -inherits(FinallyEntry, Entry); +_util.inherits(FinallyEntry, Entry); exports.FinallyEntry = FinallyEntry; function LabeledEntry(breakLoc, label) { @@ -117,14 +128,14 @@ function LabeledEntry(breakLoc, label) { this.label = label; } -inherits(LabeledEntry, Entry); +_util.inherits(LabeledEntry, Entry); exports.LabeledEntry = LabeledEntry; function LeapManager(emitter) { - assert.ok(this instanceof LeapManager); + _assert2["default"].ok(this instanceof LeapManager); var Emitter = require("./emit").Emitter; - assert.ok(emitter instanceof Emitter); + _assert2["default"].ok(emitter instanceof Emitter); this.emitter = emitter; this.entryStack = [new FunctionEntry(emitter.finalLoc)]; @@ -133,43 +144,42 @@ function LeapManager(emitter) { var LMp = LeapManager.prototype; exports.LeapManager = LeapManager; -LMp.withEntry = function(entry, callback) { - assert.ok(entry instanceof Entry); +LMp.withEntry = function (entry, callback) { + _assert2["default"].ok(entry instanceof Entry); this.entryStack.push(entry); try { callback.call(this.emitter); } finally { var popped = this.entryStack.pop(); - assert.strictEqual(popped, entry); + _assert2["default"].strictEqual(popped, entry); } }; -LMp._findLeapLocation = function(property, label) { +LMp._findLeapLocation = function (property, label) { for (var i = this.entryStack.length - 1; i >= 0; --i) { var entry = this.entryStack[i]; var loc = entry[property]; if (loc) { if (label) { - if (entry.label && - entry.label.name === label.name) { + if (entry.label && entry.label.name === label.name) { return loc; } } else if (entry instanceof LabeledEntry) { // Ignore LabeledEntry entries unless we are actually breaking to // a label. } else { - return loc; - } + return loc; + } } } return null; }; -LMp.getBreakLoc = function(label) { +LMp.getBreakLoc = function (label) { return this._findLeapLocation("breakLoc", label); }; -LMp.getContinueLoc = function(label) { +LMp.getContinueLoc = function (label) { return this._findLeapLocation("continueLoc", label); -}; +}; \ No newline at end of file diff --git a/packages/babel-plugin-transform-regenerator/lib/meta.js b/packages/babel-plugin-transform-regenerator/lib/meta.js index 0d354b8607..3412dd58b4 100644 --- a/packages/babel-plugin-transform-regenerator/lib/meta.js +++ b/packages/babel-plugin-transform-regenerator/lib/meta.js @@ -8,9 +8,22 @@ * the same directory. */ -var assert = require("assert"); +"use strict"; + +var _interopRequireDefault = require("babel-runtime/helpers/interop-require-default")["default"]; + +var _interopRequireWildcard = require("babel-runtime/helpers/interop-require-wildcard")["default"]; + +var _assert = require("assert"); + +var _assert2 = _interopRequireDefault(_assert); + +var _babelTypes = require("babel-types"); + +var t = _interopRequireWildcard(_babelTypes); + var m = require("private").makeAccessor(); -var t = require("babel-types"); + var hasOwn = Object.prototype.hasOwnProperty; function makePredicate(propertyName, knownTypes) { @@ -24,11 +37,11 @@ function makePredicate(propertyName, knownTypes) { if (result) { // Do nothing. } else if (Array.isArray(child)) { - child.some(check); - } else if (t.isNode(child)) { - assert.strictEqual(result, false); - result = predicate(child); - } + child.some(check); + } else if (t.isNode(child)) { + _assert2["default"].strictEqual(result, false); + result = predicate(child); + } return result; } @@ -48,16 +61,13 @@ function makePredicate(propertyName, knownTypes) { t.assertNode(node); var meta = m(node); - if (hasOwn.call(meta, propertyName)) - return meta[propertyName]; + if (hasOwn.call(meta, propertyName)) return meta[propertyName]; // Certain types are "opaque," which means they have no side // effects or leaps and we don't care about their subexpressions. - if (hasOwn.call(opaqueTypes, node.type)) - return meta[propertyName] = false; + if (hasOwn.call(opaqueTypes, node.type)) return meta[propertyName] = false; - if (hasOwn.call(knownTypes, node.type)) - return meta[propertyName] = true; + if (hasOwn.call(knownTypes, node.type)) return meta[propertyName] = true; return meta[propertyName] = onlyChildren(node); } @@ -100,4 +110,4 @@ for (var type in leapTypes) { } exports.hasSideEffects = makePredicate("hasSideEffects", sideEffectTypes); -exports.containsLeap = makePredicate("containsLeap", leapTypes); +exports.containsLeap = makePredicate("containsLeap", leapTypes); \ No newline at end of file diff --git a/packages/babel-plugin-transform-regenerator/lib/util.js b/packages/babel-plugin-transform-regenerator/lib/util.js index ba3adccbfc..e5f709ab64 100644 --- a/packages/babel-plugin-transform-regenerator/lib/util.js +++ b/packages/babel-plugin-transform-regenerator/lib/util.js @@ -8,16 +8,22 @@ * the same directory. */ -var t = require("babel-types"); +"use strict"; -exports.runtimeProperty = function(name) { - return t.memberExpression( - t.identifier("regeneratorRuntime"), - t.identifier(name), - false - ); -}; +var _interopRequireWildcard = require("babel-runtime/helpers/interop-require-wildcard")["default"]; -exports.isReference = function(path) { +exports.__esModule = true; +exports.runtimeProperty = runtimeProperty; +exports.isReference = isReference; + +var _babelTypes = require("babel-types"); + +var t = _interopRequireWildcard(_babelTypes); + +function runtimeProperty(name) { + return t.memberExpression(t.identifier("regeneratorRuntime"), t.identifier(name), false); +} + +function isReference(path) { return path.isReferenced() || path.parentPath.isAssignmentExpression({ left: path.node }); -}; +} \ No newline at end of file diff --git a/packages/babel-plugin-transform-regenerator/lib/visit.js b/packages/babel-plugin-transform-regenerator/lib/visit.js index 0f68ffc686..73118bcdef 100644 --- a/packages/babel-plugin-transform-regenerator/lib/visit.js +++ b/packages/babel-plugin-transform-regenerator/lib/visit.js @@ -8,20 +8,33 @@ * the same directory. */ -var traverse = require("babel-traverse"); -var babylon = require("babylon"); -var assert = require("assert"); -var fs = require("fs"); -var t = require("babel-types"); -var hoist = require("./hoist").hoist; -var Emitter = require("./emit").Emitter; -var util = require("./util"); -var runtimeProperty = util.runtimeProperty; +"use strict"; + +var _interopRequireDefault = require("babel-runtime/helpers/interop-require-default")["default"]; + +var _interopRequireWildcard = require("babel-runtime/helpers/interop-require-wildcard")["default"]; + +var _assert = require("assert"); + +var _assert2 = _interopRequireDefault(_assert); + +var _babelTypes = require("babel-types"); + +var t = _interopRequireWildcard(_babelTypes); + +var _hoist = require("./hoist"); + +var _emit = require("./emit"); + +var _util = require("./util"); + +var util = _interopRequireWildcard(_util); + var getMarkInfo = require("private").makeAccessor(); exports.visitor = { Function: { - exit: function(path, state) { + exit: function exit(path, state) { var node = path.node; if (node.generator) { @@ -43,9 +56,7 @@ exports.visitor = { if (node.expression) { // Transform expression lambdas into normal functions. node.expression = false; - node.body = t.blockStatement([ - t.returnStatement(node.body) - ]); + node.body = t.blockStatement([t.returnStatement(node.body)]); } if (node.async) { @@ -56,7 +67,7 @@ exports.visitor = { var outerBody = []; var innerBody = []; - bodyBlockPath.get("body").forEach(function(childPath) { + bodyBlockPath.get("body").forEach(function (childPath) { var node = childPath.node; if (node && node._blockHoist != null) { outerBody.push(node); @@ -82,41 +93,33 @@ exports.visitor = { // Turn all declarations into vars, and replace the original // declarations with equivalent assignment expressions. - var vars = hoist(path); + var vars = _hoist.hoist(path); var didRenameArguments = renameArguments(path, argsId); if (didRenameArguments) { vars = vars || t.variableDeclaration("var", []); - vars.declarations.push(t.variableDeclarator( - argsId, t.identifier("arguments") - )); + vars.declarations.push(t.variableDeclarator(argsId, t.identifier("arguments"))); } - var emitter = new Emitter(contextId); + var emitter = new _emit.Emitter(contextId); emitter.explode(path.get("body")); if (vars && vars.declarations.length > 0) { outerBody.push(vars); } - var wrapArgs = [ - emitter.getContextFunction(innerFnId), - // Async functions that are not generators don't care about the - // outer function because they don't need it to be marked and don't - // inherit from its .prototype. - node.generator ? outerFnExpr : t.nullLiteral(), - t.thisExpression() - ]; + var wrapArgs = [emitter.getContextFunction(innerFnId), + // Async functions that are not generators don't care about the + // outer function because they don't need it to be marked and don't + // inherit from its .prototype. + node.generator ? outerFnExpr : t.nullLiteral(), t.thisExpression()]; var tryLocsList = emitter.getTryLocsList(); if (tryLocsList) { wrapArgs.push(tryLocsList); } - var wrapCall = t.callExpression( - runtimeProperty(node.async ? "async" : "wrap"), - wrapArgs - ); + var wrapCall = t.callExpression(util.runtimeProperty(node.async ? "async" : "wrap"), wrapArgs); outerBody.push(t.returnStatement(wrapCall)); node.body = t.blockStatement(outerBody); @@ -130,9 +133,8 @@ exports.visitor = { node.async = false; } - if (wasGeneratorFunction && - t.isExpression(node)) { - path.replaceWith(t.callExpression(runtimeProperty("mark"), [node])); + if (wasGeneratorFunction && t.isExpression(node)) { + path.replaceWith(t.callExpression(util.runtimeProperty("mark"), [node])); } } } @@ -147,7 +149,7 @@ function getOuterFnExpr(funPath) { t.assertFunction(node); if (node.generator && // Non-generator functions don't need to be marked. - t.isFunctionDeclaration(node)) { + t.isFunctionDeclaration(node)) { var pp = funPath.findParent(function (path) { return path.isProgram() || path.isBlockStatement(); }); @@ -164,40 +166,22 @@ function getOuterFnExpr(funPath) { var index = funDeclIdArray.elements.length; funDeclIdArray.elements.push(node.id); - return t.memberExpression( - markedArray, - t.numericLiteral(index), - true - ); + return t.memberExpression(markedArray, t.numericLiteral(index), true); } - return node.id || ( - node.id = funPath.scope.parent.generateUidIdentifier("callee") - ); + return node.id || (node.id = funPath.scope.parent.generateUidIdentifier("callee")); } function getRuntimeMarkDecl(blockPath) { var block = blockPath.node; - assert.ok(Array.isArray(block.body)); + _assert2["default"].ok(Array.isArray(block.body)); var info = getMarkInfo(block); if (info.decl) { return info.decl; } - info.decl = t.variableDeclaration("var", [ - t.variableDeclarator( - blockPath.scope.generateUidIdentifier("marked"), - t.callExpression( - t.memberExpression( - t.arrayExpression([]), - t.identifier("map"), - false - ), - [runtimeProperty("mark")] - ) - ) - ]); + info.decl = t.variableDeclaration("var", [t.variableDeclarator(blockPath.scope.generateUidIdentifier("marked"), t.callExpression(t.memberExpression(t.arrayExpression([]), t.identifier("map"), false), [util.runtimeProperty("mark")]))]); blockPath.unshiftContainer("body", info.decl); @@ -220,11 +204,11 @@ function renameArguments(funcPath, argsId) { } var argumentsVisitor = { - "FunctionExpression|FunctionDeclaration": function(path) { + "FunctionExpression|FunctionDeclaration": function FunctionExpressionFunctionDeclaration(path) { path.skip(); }, - Identifier: function(path, state) { + Identifier: function Identifier(path, state) { if (path.node.name === "arguments" && util.isReference(path)) { path.replaceWith(state.argsId); state.didRenameArguments = true; @@ -233,23 +217,17 @@ var argumentsVisitor = { }; var awaitVisitor = { - Function: function(path) { + Function: function Function(path) { path.skip(); // Don't descend into nested function scopes. }, - AwaitExpression: function(path) { + AwaitExpression: function AwaitExpression(path) { // Convert await and await* expressions to yield expressions. var argument = path.node.argument; // Transforming `await x` to `yield regeneratorRuntime.awrap(x)` // causes the argument to be wrapped in such a way that the runtime // can distinguish between awaited and merely yielded values. - path.replaceWith(t.yieldExpression( - t.callExpression( - runtimeProperty("awrap"), - [argument] - ), - false - )); + path.replaceWith(t.yieldExpression(t.callExpression(util.runtimeProperty("awrap"), [argument]), false)); } -}; +}; \ No newline at end of file diff --git a/packages/babel-plugin-transform-regenerator/main.js b/packages/babel-plugin-transform-regenerator/main.js deleted file mode 100644 index 2272f35859..0000000000 --- a/packages/babel-plugin-transform-regenerator/main.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * 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 asyncFunctionSyntax = require("babel-plugin-syntax-async-functions"); -var blockScopingPlugin = require("babel-plugin-transform-es2015-block-scoping"); -var forOfPlugin = require("babel-plugin-transform-es2015-for-of"); -var babel = require("babel-core"); - -var regenerator = module.exports = function() { - return require("./lib/visit"); -}; - -regenerator.compile = function(code, opts) { - // todo: includeRuntime - return babel.transform(code, buildBabelOptions(opts)); -}; - -regenerator.transform = function (ast, opts) { - return babel.transformFromAst(ast, null, buildBabelOptions(opts)); -}; - -function buildBabelOptions(opts) { - return { - plugins: [regenerator, blockScopingPlugin, asyncFunctionSyntax, forOfPlugin], - sourceType: "script" - }; -} diff --git a/packages/babel-plugin-transform-regenerator/package.json b/packages/babel-plugin-transform-regenerator/package.json index a534c0c641..a9bacb0fb3 100644 --- a/packages/babel-plugin-transform-regenerator/package.json +++ b/packages/babel-plugin-transform-regenerator/package.json @@ -1,32 +1,10 @@ { - "author": "Ben Newman ", "name": "babel-plugin-transform-regenerator", - "description": "Source transformer enabling ECMAScript 6 generator functions (yield) in JavaScript-of-today (ES5)", - "keywords": [ - "generator", - "yield", - "coroutine", - "rewriting", - "transformation", - "syntax", - "codegen", - "rewriting", - "refactoring", - "transpiler", - "desugaring", - "ES6" - ], + "author": "Ben Newman ", + "description": "", "version": "6.0.18", "homepage": "https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-regenerator", - "repository": { - "type": "git", - "url": "git://github.com/facebook/regenerator.git" - }, - "main": "main.js", - "bin": "bin/regenerator", - "scripts": { - "test": "node test/run.js" - }, + "main": "lib/index.js", "dependencies": { "commoner": "~0.10.3", "babel-plugin-transform-es2015-block-scoping": "^6.0.18", @@ -39,13 +17,5 @@ "private": "~0.1.5", "through": "~2.3.8" }, - "devDependencies": { - "mocha": "~2.3.3", - "promise": "~7.0.4", - "semver": "~5.0.3" - }, - "license": "BSD", - "engines": { - "node": ">= 0.6" - } + "license": "BSD" } diff --git a/packages/babel-plugin-transform-regenerator/src/emit.js b/packages/babel-plugin-transform-regenerator/src/emit.js new file mode 100644 index 0000000000..bf24a6349c --- /dev/null +++ b/packages/babel-plugin-transform-regenerator/src/emit.js @@ -0,0 +1,1181 @@ +/** + * 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. + */ + +import assert from "assert"; +import * as t from "babel-types"; +import * as leap from "./leap"; +import * as meta from "./meta"; +import * as util from "./util"; + +let hasOwn = Object.prototype.hasOwnProperty; + +function Emitter(contextId) { + assert.ok(this instanceof Emitter); + t.assertIdentifier(contextId); + + // Used to generate unique temporary names. + this.nextTempId = 0; + + // In order to make sure the context object does not collide with + // anything in the local scope, we might have to rename it, so we + // refer to it symbolically instead of just assuming that it will be + // called "context". + this.contextId = contextId; + + // An append-only list of Statements that grows each time this.emit is + // called. + this.listing = []; + + // A sparse array whose keys correspond to locations in this.listing + // that have been marked as branch/jump targets. + this.marked = [true]; + + // The last location will be marked when this.getDispatchLoop is + // called. + this.finalLoc = loc(); + + // A list of all leap.TryEntry statements emitted. + this.tryEntries = []; + + // Each time we evaluate the body of a loop, we tell this.leapManager + // to enter a nested loop context that determines the meaning of break + // and continue statements therein. + this.leapManager = new leap.LeapManager(this); +} + +let Ep = Emitter.prototype; +exports.Emitter = Emitter; + +// Offsets into this.listing that could be used as targets for branches or +// jumps are represented as numeric Literal nodes. This representation has +// the amazingly convenient benefit of allowing the exact value of the +// location to be determined at any time, even after generating code that +// refers to the location. +function loc() { + return t.numericLiteral(-1); +} + +// Sets the exact value of the given location to the offset of the next +// Statement emitted. +Ep.mark = function(loc) { + t.assertLiteral(loc); + let index = this.listing.length; + if (loc.value === -1) { + loc.value = index; + } else { + // Locations can be marked redundantly, but their values cannot change + // once set the first time. + assert.strictEqual(loc.value, index); + } + this.marked[index] = true; + return loc; +}; + +Ep.emit = function(node) { + if (t.isExpression(node)) + node = t.expressionStatement(node); + t.assertStatement(node); + this.listing.push(node); +}; + +// Shorthand for emitting assignment statements. This will come in handy +// for assignments to temporary variables. +Ep.emitAssign = function(lhs, rhs) { + this.emit(this.assign(lhs, rhs)); + return lhs; +}; + +// Shorthand for an assignment statement. +Ep.assign = function(lhs, rhs) { + return t.expressionStatement( + t.assignmentExpression("=", lhs, rhs)); +}; + +// Convenience function for generating expressions like context.next, +// context.sent, and context.rval. +Ep.contextProperty = function(name, computed) { + return t.memberExpression( + this.contextId, + computed ? t.stringLiteral(name) : t.identifier(name), + !!computed + ); +}; + +// Shorthand for setting context.rval and jumping to `context.stop()`. +Ep.stop = function(rval) { + if (rval) { + this.setReturnValue(rval); + } + + this.jump(this.finalLoc); +}; + +Ep.setReturnValue = function(valuePath) { + t.assertExpression(valuePath.value); + + this.emitAssign( + this.contextProperty("rval"), + this.explodeExpression(valuePath) + ); +}; + +Ep.clearPendingException = function(tryLoc, assignee) { + t.assertLiteral(tryLoc); + + let catchCall = t.callExpression( + this.contextProperty("catch", true), + [tryLoc] + ); + + if (assignee) { + this.emitAssign(assignee, catchCall); + } else { + this.emit(catchCall); + } +}; + +// Emits code for an unconditional jump to the given location, even if the +// exact value of the location is not yet known. +Ep.jump = function(toLoc) { + this.emitAssign(this.contextProperty("next"), toLoc); + this.emit(t.breakStatement()); +}; + +// Conditional jump. +Ep.jumpIf = function(test, toLoc) { + t.assertExpression(test); + t.assertLiteral(toLoc); + + this.emit(t.ifStatement( + test, + t.blockStatement([ + this.assign(this.contextProperty("next"), toLoc), + t.breakStatement() + ]) + )); +}; + +// Conditional jump, with the condition negated. +Ep.jumpIfNot = function(test, toLoc) { + t.assertExpression(test); + t.assertLiteral(toLoc); + + let negatedTest; + if (t.isUnaryExpression(test) && + test.operator === "!") { + // Avoid double negation. + negatedTest = test.argument; + } else { + negatedTest = t.unaryExpression("!", test); + } + + this.emit(t.ifStatement( + negatedTest, + t.blockStatement([ + this.assign(this.contextProperty("next"), toLoc), + t.breakStatement() + ]) + )); +}; + +// Returns a unique MemberExpression that can be used to store and +// retrieve temporary values. Since the object of the member expression is +// the context object, which is presumed to coexist peacefully with all +// other local variables, and since we just increment `nextTempId` +// monotonically, uniqueness is assured. +Ep.makeTempVar = function() { + return this.contextProperty("t" + this.nextTempId++); +}; + +Ep.getContextFunction = function(id) { + return t.functionExpression( + id || null/*Anonymous*/, + [this.contextId], + t.blockStatement([this.getDispatchLoop()]), + false, // Not a generator anymore! + false // Nor an expression. + ); +}; + +// Turns this.listing into a loop of the form +// +// while (1) switch (context.next) { +// case 0: +// ... +// case n: +// return context.stop(); +// } +// +// Each marked location in this.listing will correspond to one generated +// case statement. +Ep.getDispatchLoop = function() { + let self = this; + let cases = []; + let current; + + // If we encounter a break, continue, or return statement in a switch + // case, we can skip the rest of the statements until the next case. + let alreadyEnded = false; + + self.listing.forEach(function(stmt, i) { + if (self.marked.hasOwnProperty(i)) { + cases.push(t.switchCase( + t.numericLiteral(i), + current = [])); + alreadyEnded = false; + } + + if (!alreadyEnded) { + current.push(stmt); + if (t.isCompletionStatement(stmt)) + alreadyEnded = true; + } + }); + + // Now that we know how many statements there will be in this.listing, + // we can finally resolve this.finalLoc.value. + this.finalLoc.value = this.listing.length; + + cases.push( + t.switchCase(this.finalLoc, [ + // Intentionally fall through to the "end" case... + ]), + + // So that the runtime can jump to the final location without having + // to know its offset, we provide the "end" case as a synonym. + t.switchCase(t.stringLiteral("end"), [ + // This will check/clear both context.thrown and context.rval. + t.returnStatement( + t.callExpression(this.contextProperty("stop"), []) + ) + ]) + ); + + return t.whileStatement( + t.numericLiteral(1), + t.switchStatement( + t.assignmentExpression( + "=", + this.contextProperty("prev"), + this.contextProperty("next") + ), + cases + ) + ); +}; + +Ep.getTryLocsList = function() { + if (this.tryEntries.length === 0) { + // To avoid adding a needless [] to the majority of runtime.wrap + // argument lists, force the caller to handle this case specially. + return null; + } + + let lastLocValue = 0; + + return t.arrayExpression( + this.tryEntries.map(function(tryEntry) { + let thisLocValue = tryEntry.firstLoc.value; + assert.ok(thisLocValue >= lastLocValue, "try entries out of order"); + lastLocValue = thisLocValue; + + let ce = tryEntry.catchEntry; + let fe = tryEntry.finallyEntry; + + let locs = [ + tryEntry.firstLoc, + // The null here makes a hole in the array. + ce ? ce.firstLoc : null + ]; + + if (fe) { + locs[2] = fe.firstLoc; + locs[3] = fe.afterLoc; + } + + return t.arrayExpression(locs); + }) + ); +}; + +// All side effects must be realized in order. + +// If any subexpression harbors a leap, all subexpressions must be +// neutered of side effects. + +// No destructive modification of AST nodes. + +Ep.explode = function(path, ignoreResult) { + let node = path.node; + let self = this; + + t.assertNode(node); + + if (t.isDeclaration(node)) + throw getDeclError(node); + + if (t.isStatement(node)) + return self.explodeStatement(path); + + if (t.isExpression(node)) + return self.explodeExpression(path, ignoreResult); + + switch (node.type) { + case "Program": + return path.get("body").map( + self.explodeStatement, + self + ); + + case "VariableDeclarator": + throw getDeclError(node); + + // These node types should be handled by their parent nodes + // (ObjectExpression, SwitchStatement, and TryStatement, respectively). + case "Property": + case "SwitchCase": + case "CatchClause": + throw new Error( + node.type + " nodes should be handled by their parents"); + + default: + throw new Error( + "unknown Node of type " + + JSON.stringify(node.type)); + } +}; + +function getDeclError(node) { + return new Error( + "all declarations should have been transformed into " + + "assignments before the Exploder began its work: " + + JSON.stringify(node)); +} + +Ep.explodeStatement = function(path, labelId) { + let stmt = path.node; + let self = this; + let before, after, head; + + t.assertStatement(stmt); + + if (labelId) { + t.assertIdentifier(labelId); + } else { + labelId = null; + } + + // Explode BlockStatement nodes even if they do not contain a yield, + // because we don't want or need the curly braces. + if (t.isBlockStatement(stmt)) { + path.get("body").forEach(function (path) { + self.explodeStatement(path); + }); + return; + } + + if (!meta.containsLeap(stmt)) { + // Technically we should be able to avoid emitting the statement + // altogether if !meta.hasSideEffects(stmt), but that leads to + // confusing generated code (for instance, `while (true) {}` just + // disappears) and is probably a more appropriate job for a dedicated + // dead code elimination pass. + self.emit(stmt); + return; + } + + switch (stmt.type) { + case "ExpressionStatement": + self.explodeExpression(path.get("expression"), true); + break; + + case "LabeledStatement": + after = loc(); + + // Did you know you can break from any labeled block statement or + // control structure? Well, you can! Note: when a labeled loop is + // encountered, the leap.LabeledEntry created here will immediately + // enclose a leap.LoopEntry on the leap manager's stack, and both + // entries will have the same label. Though this works just fine, it + // may seem a bit redundant. In theory, we could check here to + // determine if stmt knows how to handle its own label; for example, + // stmt happens to be a WhileStatement and so we know it's going to + // establish its own LoopEntry when we explode it (below). Then this + // LabeledEntry would be unnecessary. Alternatively, we might be + // tempted not to pass stmt.label down into self.explodeStatement, + // because we've handled the label here, but that's a mistake because + // labeled loops may contain labeled continue statements, which is not + // something we can handle in this generic case. All in all, I think a + // little redundancy greatly simplifies the logic of this case, since + // it's clear that we handle all possible LabeledStatements correctly + // here, regardless of whether they interact with the leap manager + // themselves. Also remember that labels and break/continue-to-label + // statements are rare, and all of this logic happens at transform + // time, so it has no additional runtime cost. + self.leapManager.withEntry( + new leap.LabeledEntry(after, stmt.label), + function() { + self.explodeStatement(path.get("body"), stmt.label); + } + ); + + self.mark(after); + + break; + + case "WhileStatement": + before = loc(); + after = loc(); + + self.mark(before); + self.jumpIfNot(self.explodeExpression(path.get("test")), after); + self.leapManager.withEntry( + new leap.LoopEntry(after, before, labelId), + function() { self.explodeStatement(path.get("body")); } + ); + self.jump(before); + self.mark(after); + + break; + + case "DoWhileStatement": + let first = loc(); + let test = loc(); + after = loc(); + + self.mark(first); + self.leapManager.withEntry( + new leap.LoopEntry(after, test, labelId), + function() { self.explode(path.get("body")); } + ); + self.mark(test); + self.jumpIf(self.explodeExpression(path.get("test")), first); + self.mark(after); + + break; + + case "ForStatement": + head = loc(); + let update = loc(); + after = loc(); + + if (stmt.init) { + // We pass true here to indicate that if stmt.init is an expression + // then we do not care about its result. + self.explode(path.get("init"), true); + } + + self.mark(head); + + if (stmt.test) { + self.jumpIfNot(self.explodeExpression(path.get("test")), after); + } else { + // No test means continue unconditionally. + } + + self.leapManager.withEntry( + new leap.LoopEntry(after, update, labelId), + function() { self.explodeStatement(path.get("body")); } + ); + + self.mark(update); + + if (stmt.update) { + // We pass true here to indicate that if stmt.update is an + // expression then we do not care about its result. + self.explode(path.get("update"), true); + } + + self.jump(head); + + self.mark(after); + + break; + + case "TypeCastExpression": + return self.explodeExpression(path.get("expression")); + + case "ForInStatement": + head = loc(); + after = loc(); + + let keyIterNextFn = self.makeTempVar(); + self.emitAssign( + keyIterNextFn, + t.callExpression( + util.runtimeProperty("keys"), + [self.explodeExpression(path.get("right"))] + ) + ); + + self.mark(head); + + let keyInfoTmpVar = self.makeTempVar(); + self.jumpIf( + t.memberExpression( + t.assignmentExpression( + "=", + keyInfoTmpVar, + t.callExpression(keyIterNextFn, []) + ), + t.identifier("done"), + false + ), + after + ); + + self.emitAssign( + stmt.left, + t.memberExpression( + keyInfoTmpVar, + t.identifier("value"), + false + ) + ); + + self.leapManager.withEntry( + new leap.LoopEntry(after, head, labelId), + function() { self.explodeStatement(path.get("body")); } + ); + + self.jump(head); + + self.mark(after); + + break; + + case "BreakStatement": + self.emitAbruptCompletion({ + type: "break", + target: self.leapManager.getBreakLoc(stmt.label) + }); + + break; + + case "ContinueStatement": + self.emitAbruptCompletion({ + type: "continue", + target: self.leapManager.getContinueLoc(stmt.label) + }); + + break; + + case "SwitchStatement": + // Always save the discriminant into a temporary variable in case the + // test expressions overwrite values like context.sent. + let disc = self.emitAssign( + self.makeTempVar(), + self.explodeExpression(path.get("discriminant")) + ); + + after = loc(); + let defaultLoc = loc(); + let condition = defaultLoc; + let caseLocs = []; + + // If there are no cases, .cases might be undefined. + let cases = stmt.cases || []; + + for (let i = cases.length - 1; i >= 0; --i) { + let c = cases[i]; + t.assertSwitchCase(c); + + if (c.test) { + condition = t.conditionalExpression( + t.binaryExpression("===", disc, c.test), + caseLocs[i] = loc(), + condition + ); + } else { + caseLocs[i] = defaultLoc; + } + } + + let discriminant = path.get("discriminant"); + discriminant.replaceWith(condition); + self.jump(self.explodeExpression(discriminant)); + + self.leapManager.withEntry( + new leap.SwitchEntry(after), + function() { + path.get("cases").forEach(function(casePath) { + let i = casePath.key; + self.mark(caseLocs[i]); + + casePath.get("consequent").forEach(function (path) { + self.explodeStatement(path); + }); + }); + } + ); + + self.mark(after); + if (defaultLoc.value === -1) { + self.mark(defaultLoc); + assert.strictEqual(after.value, defaultLoc.value); + } + + break; + + case "IfStatement": + let elseLoc = stmt.alternate && loc(); + after = loc(); + + self.jumpIfNot( + self.explodeExpression(path.get("test")), + elseLoc || after + ); + + self.explodeStatement(path.get("consequent")); + + if (elseLoc) { + self.jump(after); + self.mark(elseLoc); + self.explodeStatement(path.get("alternate")); + } + + self.mark(after); + + break; + + case "ReturnStatement": + self.emitAbruptCompletion({ + type: "return", + value: self.explodeExpression(path.get("argument")) + }); + + break; + + case "WithStatement": + throw new Error("WithStatement not supported in generator functions."); + + case "TryStatement": + after = loc(); + + let handler = stmt.handler; + + let catchLoc = handler && loc(); + let catchEntry = catchLoc && new leap.CatchEntry( + catchLoc, + handler.param + ); + + let finallyLoc = stmt.finalizer && loc(); + let finallyEntry = finallyLoc && + new leap.FinallyEntry(finallyLoc, after); + + let tryEntry = new leap.TryEntry( + self.getUnmarkedCurrentLoc(), + catchEntry, + finallyEntry + ); + + self.tryEntries.push(tryEntry); + self.updateContextPrevLoc(tryEntry.firstLoc); + + self.leapManager.withEntry(tryEntry, function() { + self.explodeStatement(path.get("block")); + + if (catchLoc) { + if (finallyLoc) { + // If we have both a catch block and a finally block, then + // because we emit the catch block first, we need to jump over + // it to the finally block. + self.jump(finallyLoc); + + } else { + // If there is no finally block, then we need to jump over the + // catch block to the fall-through location. + self.jump(after); + } + + self.updateContextPrevLoc(self.mark(catchLoc)); + + let bodyPath = path.get("handler.body"); + let safeParam = self.makeTempVar(); + self.clearPendingException(tryEntry.firstLoc, safeParam); + + bodyPath.traverse(catchParamVisitor, { + safeParam: safeParam, + catchParamName: handler.param.name + }); + + self.leapManager.withEntry(catchEntry, function() { + self.explodeStatement(bodyPath); + }); + } + + if (finallyLoc) { + self.updateContextPrevLoc(self.mark(finallyLoc)); + + self.leapManager.withEntry(finallyEntry, function() { + self.explodeStatement(path.get("finalizer")); + }); + + self.emit(t.returnStatement(t.callExpression( + self.contextProperty("finish"), + [finallyEntry.firstLoc] + ))); + } + }); + + self.mark(after); + + break; + + case "ThrowStatement": + self.emit(t.throwStatement( + self.explodeExpression(path.get("argument")) + )); + + break; + + default: + throw new Error( + "unknown Statement of type " + + JSON.stringify(stmt.type)); + } +}; + +let catchParamVisitor = { + Identifier: function(path, state) { + if (path.node.name === state.catchParamName && util.isReference(path)) { + path.replaceWith(state.safeParam); + } + }, + + Scope: function(path, state) { + if (path.scope.hasOwnBinding(state.catchParamName)) { + // Don't descend into nested scopes that shadow the catch + // parameter with their own declarations. + path.skip(); + } + } +}; + +Ep.emitAbruptCompletion = function(record) { + if (!isValidCompletion(record)) { + assert.ok( + false, + "invalid completion record: " + + JSON.stringify(record) + ); + } + + assert.notStrictEqual( + record.type, "normal", + "normal completions are not abrupt" + ); + + let abruptArgs = [t.stringLiteral(record.type)]; + + if (record.type === "break" || + record.type === "continue") { + t.assertLiteral(record.target); + abruptArgs[1] = record.target; + } else if (record.type === "return" || + record.type === "throw") { + if (record.value) { + t.assertExpression(record.value); + abruptArgs[1] = record.value; + } + } + + this.emit( + t.returnStatement( + t.callExpression( + this.contextProperty("abrupt"), + abruptArgs + ) + ) + ); +}; + +function isValidCompletion(record) { + let type = record.type; + + if (type === "normal") { + return !hasOwn.call(record, "target"); + } + + if (type === "break" || + type === "continue") { + return !hasOwn.call(record, "value") + && t.isLiteral(record.target); + } + + if (type === "return" || + type === "throw") { + return hasOwn.call(record, "value") + && !hasOwn.call(record, "target"); + } + + return false; +} + + +// Not all offsets into emitter.listing are potential jump targets. For +// example, execution typically falls into the beginning of a try block +// without jumping directly there. This method returns the current offset +// without marking it, so that a switch case will not necessarily be +// generated for this offset (I say "not necessarily" because the same +// location might end up being marked in the process of emitting other +// statements). There's no logical harm in marking such locations as jump +// targets, but minimizing the number of switch cases keeps the generated +// code shorter. +Ep.getUnmarkedCurrentLoc = function() { + return t.numericLiteral(this.listing.length); +}; + +// The context.prev property takes the value of context.next whenever we +// evaluate the switch statement discriminant, which is generally good +// enough for tracking the last location we jumped to, but sometimes +// context.prev needs to be more precise, such as when we fall +// successfully out of a try block and into a finally block without +// jumping. This method exists to update context.prev to the freshest +// available location. If we were implementing a full interpreter, we +// would know the location of the current instruction with complete +// precision at all times, but we don't have that luxury here, as it would +// be costly and verbose to set context.prev before every statement. +Ep.updateContextPrevLoc = function(loc) { + if (loc) { + t.assertLiteral(loc); + + if (loc.value === -1) { + // If an uninitialized location literal was passed in, set its value + // to the current this.listing.length. + loc.value = this.listing.length; + } else { + // Otherwise assert that the location matches the current offset. + assert.strictEqual(loc.value, this.listing.length); + } + + } else { + loc = this.getUnmarkedCurrentLoc(); + } + + // Make sure context.prev is up to date in case we fell into this try + // statement without jumping to it. TODO Consider avoiding this + // assignment when we know control must have jumped here. + this.emitAssign(this.contextProperty("prev"), loc); +}; + +Ep.explodeExpression = function(path, ignoreResult) { + let expr = path.node; + if (expr) { + t.assertExpression(expr); + } else { + return expr; + } + + let self = this; + let result; // Used optionally by several cases below. + + function finish(expr) { + t.assertExpression(expr); + if (ignoreResult) { + self.emit(expr); + } else { + return expr; + } + } + + // If the expression does not contain a leap, then we either emit the + // expression as a standalone statement or return it whole. + if (!meta.containsLeap(expr)) { + return finish(expr); + } + + // If any child contains a leap (such as a yield or labeled continue or + // break statement), then any sibling subexpressions will almost + // certainly have to be exploded in order to maintain the order of their + // side effects relative to the leaping child(ren). + let hasLeapingChildren = meta.containsLeap.onlyChildren(expr); + + // In order to save the rest of explodeExpression from a combinatorial + // trainwreck of special cases, explodeViaTempVar is responsible for + // deciding when a subexpression needs to be "exploded," which is my + // very technical term for emitting the subexpression as an assignment + // to a temporary variable and the substituting the temporary variable + // for the original subexpression. Think of exploded view diagrams, not + // Michael Bay movies. The point of exploding subexpressions is to + // control the precise order in which the generated code realizes the + // side effects of those subexpressions. + function explodeViaTempVar(tempVar, childPath, ignoreChildResult) { + assert.ok( + !ignoreChildResult || !tempVar, + "Ignoring the result of a child expression but forcing it to " + + "be assigned to a temporary variable?" + ); + + let result = self.explodeExpression(childPath, ignoreChildResult); + + if (ignoreChildResult) { + // Side effects already emitted above. + + } else if (tempVar || (hasLeapingChildren && + !t.isLiteral(result))) { + // If tempVar was provided, then the result will always be assigned + // to it, even if the result does not otherwise need to be assigned + // to a temporary variable. When no tempVar is provided, we have + // the flexibility to decide whether a temporary variable is really + // necessary. Unfortunately, in general, a temporary variable is + // required whenever any child contains a yield expression, since it + // is difficult to prove (at all, let alone efficiently) whether + // this result would evaluate to the same value before and after the + // yield (see #206). One narrow case where we can prove it doesn't + // matter (and thus we do not need a temporary variable) is when the + // result in question is a Literal value. + result = self.emitAssign( + tempVar || self.makeTempVar(), + result + ); + } + return result; + } + + // If ignoreResult is true, then we must take full responsibility for + // emitting the expression with all its side effects, and we should not + // return a result. + + switch (expr.type) { + case "MemberExpression": + return finish(t.memberExpression( + self.explodeExpression(path.get("object")), + expr.computed + ? explodeViaTempVar(null, path.get("property")) + : expr.property, + expr.computed + )); + + case "CallExpression": + let calleePath = path.get("callee"); + let argsPath = path.get("arguments"); + + let newCallee; + let newArgs = []; + + let hasLeapingArgs = false; + argsPath.forEach(function(argPath) { + hasLeapingArgs = hasLeapingArgs || + meta.containsLeap(argPath.node); + }); + + if (t.isMemberExpression(calleePath.node)) { + if (hasLeapingArgs) { + // If the arguments of the CallExpression contained any yield + // expressions, then we need to be sure to evaluate the callee + // before evaluating the arguments, but if the callee was a member + // expression, then we must be careful that the object of the + // member expression still gets bound to `this` for the call. + + let newObject = explodeViaTempVar( + // Assign the exploded callee.object expression to a temporary + // variable so that we can use it twice without reevaluating it. + self.makeTempVar(), + calleePath.get("object") + ); + + let newProperty = calleePath.node.computed + ? explodeViaTempVar(null, calleePath.get("property")) + : calleePath.node.property; + + newArgs.unshift(newObject); + + newCallee = t.memberExpression( + t.memberExpression( + newObject, + newProperty, + calleePath.node.computed + ), + t.identifier("call"), + false + ); + + } else { + newCallee = self.explodeExpression(calleePath); + } + + } else { + newCallee = self.explodeExpression(calleePath); + + if (t.isMemberExpression(newCallee)) { + // If the callee was not previously a MemberExpression, then the + // CallExpression was "unqualified," meaning its `this` object + // should be the global object. If the exploded expression has + // become a MemberExpression (e.g. a context property, probably a + // temporary variable), then we need to force it to be unqualified + // by using the (0, object.property)(...) trick; otherwise, it + // will receive the object of the MemberExpression as its `this` + // object. + newCallee = t.sequenceExpression([ + t.numericLiteral(0), + newCallee + ]); + } + } + + argsPath.forEach(function(argPath) { + newArgs.push(explodeViaTempVar(null, argPath)); + }); + + return finish(t.callExpression( + newCallee, + newArgs + )); + + case "NewExpression": + return finish(t.newExpression( + explodeViaTempVar(null, path.get("callee")), + path.get("arguments").map(function(argPath) { + return explodeViaTempVar(null, argPath); + }) + )); + + case "ObjectExpression": + return finish(t.objectExpression( + path.get("properties").map(function(propPath) { + if (propPath.isObjectProperty()) { + return t.objectProperty( + propPath.node.key, + explodeViaTempVar(null, propPath.get("value")), + propPath.node.computed + ); + } else { + return propPath.node; + } + }) + )); + + case "ArrayExpression": + return finish(t.arrayExpression( + path.get("elements").map(function(elemPath) { + return explodeViaTempVar(null, elemPath); + }) + )); + + case "SequenceExpression": + let lastIndex = expr.expressions.length - 1; + + path.get("expressions").forEach(function(exprPath) { + if (exprPath.key === lastIndex) { + result = self.explodeExpression(exprPath, ignoreResult); + } else { + self.explodeExpression(exprPath, true); + } + }); + + return result; + + case "LogicalExpression": + after = loc(); + + if (!ignoreResult) { + result = self.makeTempVar(); + } + + let left = explodeViaTempVar(result, path.get("left")); + + if (expr.operator === "&&") { + self.jumpIfNot(left, after); + } else { + assert.strictEqual(expr.operator, "||"); + self.jumpIf(left, after); + } + + explodeViaTempVar(result, path.get("right"), ignoreResult); + + self.mark(after); + + return result; + + case "ConditionalExpression": + let elseLoc = loc(); + after = loc(); + let test = self.explodeExpression(path.get("test")); + + self.jumpIfNot(test, elseLoc); + + if (!ignoreResult) { + result = self.makeTempVar(); + } + + explodeViaTempVar(result, path.get("consequent"), ignoreResult); + self.jump(after); + + self.mark(elseLoc); + explodeViaTempVar(result, path.get("alternate"), ignoreResult); + + self.mark(after); + + return result; + + case "UnaryExpression": + return finish(t.unaryExpression( + expr.operator, + // Can't (and don't need to) break up the syntax of the argument. + // Think about delete a[b]. + self.explodeExpression(path.get("argument")), + !!expr.prefix + )); + + case "BinaryExpression": + return finish(t.binaryExpression( + expr.operator, + explodeViaTempVar(null, path.get("left")), + explodeViaTempVar(null, path.get("right")) + )); + + case "AssignmentExpression": + return finish(t.assignmentExpression( + expr.operator, + self.explodeExpression(path.get("left")), + self.explodeExpression(path.get("right")) + )); + + case "UpdateExpression": + return finish(t.updateExpression( + expr.operator, + self.explodeExpression(path.get("argument")), + expr.prefix + )); + + case "YieldExpression": + after = loc(); + let arg = expr.argument && self.explodeExpression(path.get("argument")); + + if (arg && expr.delegate) { + let result = self.makeTempVar(); + + self.emit(t.returnStatement(t.callExpression( + self.contextProperty("delegateYield"), [ + arg, + t.stringLiteral(result.property.name), + after + ] + ))); + + self.mark(after); + + return result; + } + + self.emitAssign(self.contextProperty("next"), after); + self.emit(t.returnStatement(arg || null)); + self.mark(after); + + return self.contextProperty("sent"); + + default: + throw new Error( + "unknown Expression of type " + + JSON.stringify(expr.type)); + } +}; diff --git a/packages/babel-plugin-transform-regenerator/src/hoist.js b/packages/babel-plugin-transform-regenerator/src/hoist.js new file mode 100644 index 0000000000..222b0c651d --- /dev/null +++ b/packages/babel-plugin-transform-regenerator/src/hoist.js @@ -0,0 +1,148 @@ +/** + * 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. + */ + +import * as t from "babel-types"; +let hasOwn = Object.prototype.hasOwnProperty; + +// The hoist function takes a FunctionExpression or FunctionDeclaration +// and replaces any Declaration nodes in its body with assignments, then +// returns a VariableDeclaration containing just the names of the removed +// declarations. +exports.hoist = function(funPath) { + t.assertFunction(funPath.node); + + let vars = {}; + + function varDeclToExpr(vdec, includeIdentifiers) { + t.assertVariableDeclaration(vdec); + // TODO assert.equal(vdec.kind, "var"); + let exprs = []; + + vdec.declarations.forEach(function(dec) { + vars[dec.id.name] = dec.id; + + if (dec.init) { + exprs.push(t.assignmentExpression( + "=", dec.id, dec.init + )); + } else if (includeIdentifiers) { + exprs.push(dec.id); + } + }); + + if (exprs.length === 0) + return null; + + if (exprs.length === 1) + return exprs[0]; + + return t.sequenceExpression(exprs); + } + + funPath.get("body").traverse({ + VariableDeclaration: { + exit: function(path) { + let expr = varDeclToExpr(path.node, false); + if (expr === null) { + path.remove(); + } else { + // We don't need to traverse this expression any further because + // there can't be any new declarations inside an expression. + path.replaceWith(t.expressionStatement(expr)); + } + + // Since the original node has been either removed or replaced, + // avoid traversing it any further. + path.skip(); + } + }, + + ForStatement: function(path) { + let init = path.node.init; + if (t.isVariableDeclaration(init)) { + path.get("init").replaceWith(varDeclToExpr(init, false)); + } + }, + + ForXStatement: function(path) { + let left = path.get("left"); + if (left.isVariableDeclaration()) { + left.replaceWith(varDeclToExpr(left.node, true)); + } + }, + + FunctionDeclaration: function(path) { + let node = path.node; + vars[node.id.name] = node.id; + + let assignment = t.expressionStatement( + t.assignmentExpression( + "=", + node.id, + t.functionExpression( + node.id, + node.params, + node.body, + node.generator, + node.expression + ) + ) + ); + + if (path.parentPath.isBlockStatement()) { + // Insert the assignment form before the first statement in the + // enclosing block. + path.parentPath.unshiftContainer("body", assignment); + + // Remove the function declaration now that we've inserted the + // equivalent assignment form at the beginning of the block. + path.remove(); + } else { + // If the parent node is not a block statement, then we can just + // replace the declaration with the equivalent assignment form + // without worrying about hoisting it. + path.replaceWith(assignment); + } + + // Don't hoist variables out of inner functions. + path.skip(); + }, + + FunctionExpression: function(path) { + // Don't descend into nested function expressions. + path.skip(); + } + }); + + let paramNames = {}; + funPath.get("params").forEach(function(paramPath) { + let param = paramPath.node; + if (t.isIdentifier(param)) { + paramNames[param.name] = param; + } else { + // Variables declared by destructuring parameter patterns will be + // harmlessly re-declared. + } + }); + + let declarations = []; + + Object.keys(vars).forEach(function(name) { + if (!hasOwn.call(paramNames, name)) { + declarations.push(t.variableDeclarator(vars[name], null)); + } + }); + + if (declarations.length === 0) { + return null; // Be sure to handle this case! + } + + return t.variableDeclaration("var", declarations); +}; diff --git a/packages/babel-plugin-transform-regenerator/src/index.js b/packages/babel-plugin-transform-regenerator/src/index.js new file mode 100644 index 0000000000..34fea7a15a --- /dev/null +++ b/packages/babel-plugin-transform-regenerator/src/index.js @@ -0,0 +1,13 @@ +/** + * 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. + */ + +export default function () { + return require("./visit"); +} diff --git a/packages/babel-plugin-transform-regenerator/src/leap.js b/packages/babel-plugin-transform-regenerator/src/leap.js new file mode 100644 index 0000000000..047a2bf263 --- /dev/null +++ b/packages/babel-plugin-transform-regenerator/src/leap.js @@ -0,0 +1,174 @@ +/** + * 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. + */ + +import assert from "assert"; +import * as t from "babel-types"; +import { inherits } from "util"; + +function Entry() { + assert.ok(this instanceof Entry); +} + +function FunctionEntry(returnLoc) { + Entry.call(this); + t.assertLiteral(returnLoc); + this.returnLoc = returnLoc; +} + +inherits(FunctionEntry, Entry); +exports.FunctionEntry = FunctionEntry; + +function LoopEntry(breakLoc, continueLoc, label) { + Entry.call(this); + + t.assertLiteral(breakLoc); + t.assertLiteral(continueLoc); + + if (label) { + t.assertIdentifier(label); + } else { + label = null; + } + + this.breakLoc = breakLoc; + this.continueLoc = continueLoc; + this.label = label; +} + +inherits(LoopEntry, Entry); +exports.LoopEntry = LoopEntry; + +function SwitchEntry(breakLoc) { + Entry.call(this); + t.assertLiteral(breakLoc); + this.breakLoc = breakLoc; +} + +inherits(SwitchEntry, Entry); +exports.SwitchEntry = SwitchEntry; + +function TryEntry(firstLoc, catchEntry, finallyEntry) { + Entry.call(this); + + t.assertLiteral(firstLoc); + + if (catchEntry) { + assert.ok(catchEntry instanceof CatchEntry); + } else { + catchEntry = null; + } + + if (finallyEntry) { + assert.ok(finallyEntry instanceof FinallyEntry); + } else { + finallyEntry = null; + } + + // Have to have one or the other (or both). + assert.ok(catchEntry || finallyEntry); + + this.firstLoc = firstLoc; + this.catchEntry = catchEntry; + this.finallyEntry = finallyEntry; +} + +inherits(TryEntry, Entry); +exports.TryEntry = TryEntry; + +function CatchEntry(firstLoc, paramId) { + Entry.call(this); + + t.assertLiteral(firstLoc); + t.assertIdentifier(paramId); + + this.firstLoc = firstLoc; + this.paramId = paramId; +} + +inherits(CatchEntry, Entry); +exports.CatchEntry = CatchEntry; + +function FinallyEntry(firstLoc, afterLoc) { + Entry.call(this); + t.assertLiteral(firstLoc); + t.assertLiteral(afterLoc); + this.firstLoc = firstLoc; + this.afterLoc = afterLoc; +} + +inherits(FinallyEntry, Entry); +exports.FinallyEntry = FinallyEntry; + +function LabeledEntry(breakLoc, label) { + Entry.call(this); + + t.assertLiteral(breakLoc); + t.assertIdentifier(label); + + this.breakLoc = breakLoc; + this.label = label; +} + +inherits(LabeledEntry, Entry); +exports.LabeledEntry = LabeledEntry; + +function LeapManager(emitter) { + assert.ok(this instanceof LeapManager); + + let Emitter = require("./emit").Emitter; + assert.ok(emitter instanceof Emitter); + + this.emitter = emitter; + this.entryStack = [new FunctionEntry(emitter.finalLoc)]; +} + +let LMp = LeapManager.prototype; +exports.LeapManager = LeapManager; + +LMp.withEntry = function(entry, callback) { + assert.ok(entry instanceof Entry); + this.entryStack.push(entry); + try { + callback.call(this.emitter); + } finally { + let popped = this.entryStack.pop(); + assert.strictEqual(popped, entry); + } +}; + +LMp._findLeapLocation = function(property, label) { + for (let i = this.entryStack.length - 1; i >= 0; --i) { + let entry = this.entryStack[i]; + let loc = entry[property]; + if (loc) { + if (label) { + if (entry.label && + entry.label.name === label.name) { + return loc; + } + } else if (entry instanceof LabeledEntry) { + // Ignore LabeledEntry entries unless we are actually breaking to + // a label. + } else { + return loc; + } + } + } + + return null; +}; + +LMp.getBreakLoc = function(label) { + return this._findLeapLocation("breakLoc", label); +}; + +LMp.getContinueLoc = function(label) { + return this._findLeapLocation("continueLoc", label); +}; diff --git a/packages/babel-plugin-transform-regenerator/src/meta.js b/packages/babel-plugin-transform-regenerator/src/meta.js new file mode 100644 index 0000000000..dc7ffcdd45 --- /dev/null +++ b/packages/babel-plugin-transform-regenerator/src/meta.js @@ -0,0 +1,103 @@ +/** + * 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. + */ + +import assert from "assert"; +let m = require("private").makeAccessor(); +import * as t from "babel-types"; +let hasOwn = Object.prototype.hasOwnProperty; + +function makePredicate(propertyName, knownTypes) { + function onlyChildren(node) { + t.assertNode(node); + + // Assume no side effects until we find out otherwise. + let result = false; + + function check(child) { + if (result) { + // Do nothing. + } else if (Array.isArray(child)) { + child.some(check); + } else if (t.isNode(child)) { + assert.strictEqual(result, false); + result = predicate(child); + } + return result; + } + + let keys = t.VISITOR_KEYS[node.type]; + if (keys) { + for (let i = 0; i < keys.length; i++) { + let key = keys[i]; + let child = node[key]; + check(child); + } + } + + return result; + } + + function predicate(node) { + t.assertNode(node); + + let meta = m(node); + if (hasOwn.call(meta, propertyName)) + return meta[propertyName]; + + // Certain types are "opaque," which means they have no side + // effects or leaps and we don't care about their subexpressions. + if (hasOwn.call(opaqueTypes, node.type)) + return meta[propertyName] = false; + + if (hasOwn.call(knownTypes, node.type)) + return meta[propertyName] = true; + + return meta[propertyName] = onlyChildren(node); + } + + predicate.onlyChildren = onlyChildren; + + return predicate; +} + +let opaqueTypes = { + FunctionExpression: true +}; + +// These types potentially have side effects regardless of what side +// effects their subexpressions have. +let sideEffectTypes = { + CallExpression: true, // Anything could happen! + ForInStatement: true, // Modifies the key variable. + UnaryExpression: true, // Think delete. + BinaryExpression: true, // Might invoke .toString() or .valueOf(). + AssignmentExpression: true, // Side-effecting by definition. + UpdateExpression: true, // Updates are essentially assignments. + NewExpression: true // Similar to CallExpression. +}; + +// These types are the direct cause of all leaps in control flow. +let leapTypes = { + YieldExpression: true, + BreakStatement: true, + ContinueStatement: true, + ReturnStatement: true, + ThrowStatement: true +}; + +// All leap types are also side effect types. +for (let type in leapTypes) { + if (hasOwn.call(leapTypes, type)) { + sideEffectTypes[type] = leapTypes[type]; + } +} + +exports.hasSideEffects = makePredicate("hasSideEffects", sideEffectTypes); +exports.containsLeap = makePredicate("containsLeap", leapTypes); diff --git a/packages/babel-plugin-transform-regenerator/src/util.js b/packages/babel-plugin-transform-regenerator/src/util.js new file mode 100644 index 0000000000..78bfa0f28b --- /dev/null +++ b/packages/babel-plugin-transform-regenerator/src/util.js @@ -0,0 +1,23 @@ +/** + * 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. + */ + +import * as t from "babel-types"; + +export function runtimeProperty(name) { + return t.memberExpression( + t.identifier("regeneratorRuntime"), + t.identifier(name), + false + ); +} + +export function isReference(path) { + return path.isReferenced() || path.parentPath.isAssignmentExpression({ left: path.node }); +} diff --git a/packages/babel-plugin-transform-regenerator/src/visit.js b/packages/babel-plugin-transform-regenerator/src/visit.js new file mode 100644 index 0000000000..ad22fe3c76 --- /dev/null +++ b/packages/babel-plugin-transform-regenerator/src/visit.js @@ -0,0 +1,252 @@ +/** + * 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. + */ + +import assert from "assert"; +import * as t from "babel-types"; +import { hoist } from "./hoist"; +import { Emitter } from "./emit"; +import * as util from "./util"; + +let getMarkInfo = require("private").makeAccessor(); + +exports.visitor = { + Function: { + exit: function(path, state) { + let node = path.node; + + if (node.generator) { + if (node.async) { + // Async generator + if (state.opts.asyncGenerators === false) return; + } else { + // Plain generator + if (state.opts.generators === false) return; + } + } else if (node.async) { + // Async function + if (state.opts.async === false) return; + } else { + // Not a generator or async function. + return; + } + + if (node.expression) { + // Transform expression lambdas into normal functions. + node.expression = false; + node.body = t.blockStatement([ + t.returnStatement(node.body) + ]); + } + + if (node.async) { + path.get("body").traverse(awaitVisitor); + } + + let bodyBlockPath = path.get("body"); + let outerBody = []; + let innerBody = []; + + bodyBlockPath.get("body").forEach(function(childPath) { + let node = childPath.node; + if (node && node._blockHoist != null) { + outerBody.push(node); + } else { + innerBody.push(node); + } + }); + + if (outerBody.length > 0) { + // Only replace the inner body if we actually hoisted any statements + // to the outer body. + bodyBlockPath.node.body = innerBody; + } + + let outerFnExpr = getOuterFnExpr(path); + // Note that getOuterFnExpr has the side-effect of ensuring that the + // function has a name (so node.id will always be an Identifier), even + // if a temporary name has to be synthesized. + t.assertIdentifier(node.id); + let innerFnId = t.identifier(node.id.name + "$"); + let contextId = path.scope.generateUidIdentifier("context"); + let argsId = path.scope.generateUidIdentifier("args"); + + // Turn all declarations into vars, and replace the original + // declarations with equivalent assignment expressions. + let vars = hoist(path); + + let didRenameArguments = renameArguments(path, argsId); + if (didRenameArguments) { + vars = vars || t.variableDeclaration("var", []); + vars.declarations.push(t.variableDeclarator( + argsId, t.identifier("arguments") + )); + } + + let emitter = new Emitter(contextId); + emitter.explode(path.get("body")); + + if (vars && vars.declarations.length > 0) { + outerBody.push(vars); + } + + let wrapArgs = [ + emitter.getContextFunction(innerFnId), + // Async functions that are not generators don't care about the + // outer function because they don't need it to be marked and don't + // inherit from its .prototype. + node.generator ? outerFnExpr : t.nullLiteral(), + t.thisExpression() + ]; + + let tryLocsList = emitter.getTryLocsList(); + if (tryLocsList) { + wrapArgs.push(tryLocsList); + } + + let wrapCall = t.callExpression( + util.runtimeProperty(node.async ? "async" : "wrap"), + wrapArgs + ); + + outerBody.push(t.returnStatement(wrapCall)); + node.body = t.blockStatement(outerBody); + + let wasGeneratorFunction = node.generator; + if (wasGeneratorFunction) { + node.generator = false; + } + + if (node.async) { + node.async = false; + } + + if (wasGeneratorFunction && + t.isExpression(node)) { + path.replaceWith(t.callExpression(util.runtimeProperty("mark"), [node])); + } + } + } +}; + +// Given a NodePath for a Function, return an Expression node that can be +// used to refer reliably to the function object from inside the function. +// This expression is essentially a replacement for arguments.callee, with +// the key advantage that it works in strict mode. +function getOuterFnExpr(funPath) { + let node = funPath.node; + t.assertFunction(node); + + if (node.generator && // Non-generator functions don't need to be marked. + t.isFunctionDeclaration(node)) { + let pp = funPath.findParent(function (path) { + return path.isProgram() || path.isBlockStatement(); + }); + + if (!pp) { + return node.id; + } + + let markDecl = getRuntimeMarkDecl(pp); + let markedArray = markDecl.declarations[0].id; + let funDeclIdArray = markDecl.declarations[0].init.callee.object; + t.assertArrayExpression(funDeclIdArray); + + let index = funDeclIdArray.elements.length; + funDeclIdArray.elements.push(node.id); + + return t.memberExpression( + markedArray, + t.numericLiteral(index), + true + ); + } + + return node.id || ( + node.id = funPath.scope.parent.generateUidIdentifier("callee") + ); +} + +function getRuntimeMarkDecl(blockPath) { + let block = blockPath.node; + assert.ok(Array.isArray(block.body)); + + let info = getMarkInfo(block); + if (info.decl) { + return info.decl; + } + + info.decl = t.variableDeclaration("var", [ + t.variableDeclarator( + blockPath.scope.generateUidIdentifier("marked"), + t.callExpression( + t.memberExpression( + t.arrayExpression([]), + t.identifier("map"), + false + ), + [util.runtimeProperty("mark")] + ) + ) + ]); + + blockPath.unshiftContainer("body", info.decl); + + return info.decl; +} + +function renameArguments(funcPath, argsId) { + let state = { + didRenameArguments: false, + argsId: argsId + }; + + funcPath.traverse(argumentsVisitor, state); + + // If the traversal replaced any arguments references, then we need to + // alias the outer function's arguments binding (be it the implicit + // arguments object or some other parameter or variable) to the variable + // named by argsId. + return state.didRenameArguments; +} + +let argumentsVisitor = { + "FunctionExpression|FunctionDeclaration": function(path) { + path.skip(); + }, + + Identifier: function(path, state) { + if (path.node.name === "arguments" && util.isReference(path)) { + path.replaceWith(state.argsId); + state.didRenameArguments = true; + } + } +}; + +let awaitVisitor = { + Function: function(path) { + path.skip(); // Don't descend into nested function scopes. + }, + + AwaitExpression: function(path) { + // Convert await and await* expressions to yield expressions. + let argument = path.node.argument; + + // Transforming `await x` to `yield regeneratorRuntime.awrap(x)` + // causes the argument to be wrapped in such a way that the runtime + // can distinguish between awaited and merely yielded values. + path.replaceWith(t.yieldExpression( + t.callExpression( + util.runtimeProperty("awrap"), + [argument] + ), + false + )); + } +};