Fixing Issue #643. Be a little bit safer about declaring block variables as close to the block scope as possible.

This commit is contained in:
Jeremy Ashkenas 2010-08-24 22:19:53 -04:00
parent e2c46d14f0
commit fa95f743f3
5 changed files with 33 additions and 14 deletions

View File

@ -1598,10 +1598,14 @@
name = (this.name && this.name.compile(o)) || scope.freeVariable();
index = this.index && this.index.compile(o);
if (name && !this.pattern && (range || !codeInBody)) {
scope.find(name);
scope.find(name, {
immediate: true
});
}
if (index) {
scope.find(index);
scope.find(index, {
immediate: true
});
}
if (!(topLevel)) {
rvar = scope.freeVariable();

View File

@ -21,8 +21,8 @@
return this;
};
Scope.root = null;
Scope.prototype.find = function(name) {
if (this.check(name)) {
Scope.prototype.find = function(name, options) {
if (this.check(name, options)) {
return true;
}
this.variables[name] = 'var';
@ -43,9 +43,11 @@
Scope.prototype.parameter = function(name) {
return (this.variables[name] = 'param');
};
Scope.prototype.check = function(name) {
if (Object.prototype.hasOwnProperty.call(this.variables, name)) {
return true;
Scope.prototype.check = function(name, options) {
var immediate;
immediate = Object.prototype.hasOwnProperty.call(this.variables, name);
if (immediate || (options && options.immediate)) {
return immediate;
}
return !!(this.parent && this.parent.check(name));
};

View File

@ -1357,8 +1357,8 @@ exports.ForNode = class ForNode extends BaseNode
scope = o.scope
name = (@name and @name.compile(o)) or scope.freeVariable()
index = @index and @index.compile o
scope.find name if name and not @pattern and (range or not codeInBody)
scope.find index if index
scope.find(name, immediate: yes) if name and not @pattern and (range or not codeInBody)
scope.find(index, immediate: yes) if index
rvar = scope.freeVariable() unless topLevel
ivar = if codeInBody then scope.freeVariable() else if range then name else index or scope.freeVariable()
varPart = ''

View File

@ -28,8 +28,8 @@ exports.Scope = class Scope
# Look up a variable name in lexical scope, and declare it if it does not
# already exist.
find: (name) ->
return true if @check name
find: (name, options) ->
return true if @check name, options
@variables[name] = 'var'
false
@ -44,9 +44,11 @@ exports.Scope = class Scope
parameter: (name) ->
@variables[name] = 'param'
# Just check to see if a variable has already been declared, without reserving.
check: (name) ->
return true if Object::hasOwnProperty.call @variables, name
# Just check to see if a variable has already been declared, without reserving,
# walks up to the root scope.
check: (name, options) ->
immediate = Object::hasOwnProperty.call @variables, name
return immediate if immediate or (options and options.immediate)
!!(@parent and @parent.check(name))
# If we need to store an intermediate result, find an available name for a

View File

@ -141,3 +141,14 @@ ok all.sort().join(' ') is 'Whiskers cream tabby'
exxes = 'x' for [0...10]
ok exxes.join(' ') is 'x x x x x x x x x x'
# Comprehensions safely redeclare parameters if they're not present in closest
# scope.
rule = (x) -> x
learn = ->
rule for rule in [1, 2, 3]
ok learn().join(' ') is '1 2 3'
ok rule(101) is 101