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:
parent
e2c46d14f0
commit
fa95f743f3
|
@ -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();
|
||||
|
|
12
lib/scope.js
12
lib/scope.js
|
@ -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));
|
||||
};
|
||||
|
|
|
@ -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 = ''
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue