Skip to content

Commit

Permalink
Add block binding (let/const) support
Browse files Browse the repository at this point in the history
fixes #65
+ tests
  • Loading branch information
termi committed Dec 1, 2013
1 parent 73897dc commit 911a282
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 12 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Expand Up @@ -6,3 +6,5 @@ test/mocha.css

test/tests.es5.js
test/tests.browser.js

.idea
19 changes: 19 additions & 0 deletions lib/util.js
Expand Up @@ -33,3 +33,22 @@ exports.guessTabWidth = function(source) {

return result;
};

exports.extend = function(obj) {
var len = arguments.length;
var extension;

for (var i = 1;
i < len;
i++) {
if (extension = arguments[i]) {
for (var key in extension) {
if (Object.prototype.hasOwnProperty.call(extension, key)) {
obj[key] = extension[key];
}
}
}
}

return obj;
}
47 changes: 37 additions & 10 deletions main.js
Expand Up @@ -11,22 +11,23 @@ var assert = require("assert");
var path = require("path");
var fs = require("fs");
var transform = require("./lib/visit").transform;
var guessTabWidth = require("./lib/util").guessTabWidth;
var utils = require("./lib/util");
var recast = require("recast");
var esprimaHarmony = require("esprima");
var genFunExp = /\bfunction\s*\*/;
var blockBindingExp = /\b(let|const)\s*/;

assert.ok(
/harmony/.test(esprimaHarmony.version),
"Bad esprima version: " + esprimaHarmony.version
);

function regenerator(source, options) {
if (!options) {
options = {
includeRuntime: false
};
}
options = utils.extend(options || {}, {
includeRuntime: false,
supportBlockBinding: true
}
);

var runtime = options.includeRuntime ? fs.readFileSync(
regenerator.runtime.dev, "utf-8"
Expand All @@ -36,15 +37,41 @@ function regenerator(source, options) {
return runtime + source; // Shortcut: no generators to transform.
}

var supportBlockBinding = options.supportBlockBinding;
if (supportBlockBinding) {
if (!blockBindingExp.test(source)) {
supportBlockBinding = false;
}
}

var recastOptions = {
tabWidth: guessTabWidth(source),
tabWidth: utils.guessTabWidth(source),
// Use the harmony branch of Esprima that installs with regenerator
// instead of the master branch that recast provides.
esprima: esprimaHarmony
esprima: esprimaHarmony,
range: supportBlockBinding
};

var ast = recast.parse(source, recastOptions);
var es5 = recast.print(transform(ast), recastOptions);
var recastAst = recast.parse(source, recastOptions);
var ast = recastAst.program;

if (supportBlockBinding) {// smart transpiling let/const into var
var defsResult = require("defs")(ast, {
ast: true,
disallowUnknownReferences: false,
disallowDuplicated: false,
disallowVars: false,
loopClosures: "iife"
});

if (defsResult.errors) {
throw new Error(defsResult.errors.join("\n"))
}
}

recastAst.program = transform(ast);

var es5 = recast.print(recastAst, recastOptions);
return runtime + es5;
}

Expand Down
5 changes: 3 additions & 2 deletions package.json
Expand Up @@ -31,8 +31,9 @@
"commander": "~2.0.0",
"esprima": "git://github.com/ariya/esprima.git#harmony",
"ast-types": ">= 0.3.8",
"recast": "~0.4.23",
"private": "~0.0.5"
"recast": "~0.4.25",
"private": "~0.0.5",
"defs": "~0.6.0"
},
"devDependencies": {
"mocha": "~1.13.0",
Expand Down
58 changes: 58 additions & 0 deletions test/tests.es6.js
Expand Up @@ -1048,3 +1048,61 @@ describe("new expressions", function() {
assert.deepEqual(g.next("qwer"), { value: "qwer", done: true });
});
});

describe("block binding", function() {
it("should translate block binding correctly", function() {
"use strict";

function *gen() {
var a$0 = 0, a$1 = 1;

let a = 3;

{
let a = 1;
yield a + a$0;
}

{
let a = 2;
yield a - 1 + a$1;
}

yield a;
}

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";

function *gen() {
let arr = [];

for (let x = 0; x < 3; x++) {
let y = x;
arr.push(function() { return y; });
}

{
let x;
while( x = arr.pop() ) {
yield x;
}
}
}

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 });
});
});

0 comments on commit 911a282

Please sign in to comment.