Skip to content

Commit c5f6a4b

Browse files
committed
Include scope.depth in temporary variable names.
This elegantly ensures that temporary names will not collide with names in nested or enclosing scopes, without requiring any actual scanning of those other scopes.
1 parent 291dda1 commit c5f6a4b

File tree

2 files changed

+74
-8
lines changed

2 files changed

+74
-8
lines changed

lib/scope.js

+12-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ var assert = require("assert");
22
var types = require("./types");
33
var Type = types.Type;
44
var namedTypes = types.namedTypes;
5-
var builders = types.builders;
65
var Node = namedTypes.Node;
76
var isArray = types.builtInTypes.array;
87
var hasOwn = Object.prototype.hasOwnProperty;
@@ -62,17 +61,25 @@ Sp.declares = function(name) {
6261
};
6362

6463
Sp.declareTemporary = function(prefix) {
65-
assert.ok(/^[a-z$_]/i.test(prefix), prefix);
64+
if (prefix) {
65+
assert.ok(/^[a-z$_]/i.test(prefix), prefix);
66+
} else {
67+
prefix = "t$";
68+
}
69+
70+
// Include this.depth in the name to make sure the name does not
71+
// collide with any variables in nested/enclosing scopes.
72+
prefix += this.depth.toString(36) + "$";
73+
6674
this.scan();
6775

6876
var index = 0;
6977
while (this.declares(prefix + index)) {
7078
++index;
7179
}
7280

73-
var id = builders.identifier(prefix + index);
74-
this.bindings[prefix + index] = id;
75-
return id;
81+
var name = prefix + index;
82+
return this.bindings[name] = types.builders.identifier(name);
7683
};
7784

7885
Sp.scan = function(force) {

test/run.js

+62-3
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,7 @@ describe("global scope", function() {
726726
});
727727
});
728728

729-
describe("scope.getBindings", function () {
729+
describe("scope methods", function () {
730730
var traverse = types.traverse;
731731

732732
var scope = [
@@ -739,8 +739,9 @@ describe("scope.getBindings", function () {
739739
"};"
740740
];
741741

742-
var ast = parse(scope.join("\n"));
743-
it("should get local and global scope bindings", function() {
742+
it("getBindings should get local and global scope bindings", function() {
743+
var ast = parse(scope.join("\n"));
744+
744745
traverse(ast, function(node) {
745746
var bindings;
746747
if (n.Program.check(node)) {
@@ -760,6 +761,64 @@ describe("scope.getBindings", function () {
760761
}
761762
});
762763
});
764+
765+
it("declareTemporary should use distinct names in nested scopes", function() {
766+
var ast = parse(scope.join("\n"));
767+
var globalVarDecl;
768+
var barVarDecl;
769+
var romVarDecl;
770+
771+
types.visit(ast, {
772+
visitProgram: function(path) {
773+
path.get("body").unshift(
774+
globalVarDecl = b.variableDeclaration("var", [
775+
b.variableDeclarator(
776+
path.scope.declareTemporary("$"),
777+
b.literal("global")
778+
),
779+
b.variableDeclarator(
780+
path.scope.declareTemporary("$"),
781+
b.literal("global")
782+
)
783+
])
784+
);
785+
786+
this.traverse(path);
787+
},
788+
789+
visitFunction: function(path) {
790+
var funcId = path.value.id;
791+
792+
var varDecl = b.variableDeclaration("var", [
793+
b.variableDeclarator(
794+
path.scope.declareTemporary("$"),
795+
b.literal(funcId.name + 1)
796+
),
797+
b.variableDeclarator(
798+
path.scope.declareTemporary("$"),
799+
b.literal(funcId.name + 2)
800+
)
801+
]);
802+
803+
path.get("body", "body").unshift(varDecl);
804+
805+
if (funcId.name === "bar") {
806+
barVarDecl = varDecl;
807+
} else if (funcId.name === "rom") {
808+
romVarDecl = varDecl;
809+
}
810+
811+
this.traverse(path);
812+
}
813+
});
814+
815+
assert.strictEqual(globalVarDecl.declarations[0].id.name, "$0$0");
816+
assert.strictEqual(globalVarDecl.declarations[1].id.name, "$0$1");
817+
assert.strictEqual(barVarDecl.declarations[0].id.name, "$1$0");
818+
assert.strictEqual(barVarDecl.declarations[1].id.name, "$1$1");
819+
assert.strictEqual(romVarDecl.declarations[0].id.name, "$1$0");
820+
assert.strictEqual(romVarDecl.declarations[1].id.name, "$1$1");
821+
});
763822
});
764823

765824
describe("catch block scope", function() {

0 commit comments

Comments
 (0)