mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
scope: refactored
This commit is contained in:
parent
8d6b909b93
commit
b0a4b7ab85
2 changed files with 35 additions and 38 deletions
42
lib/scope.js
42
lib/scope.js
|
@ -27,29 +27,28 @@
|
|||
Scope.root = null;
|
||||
Scope.prototype.setVar = function(name, type) {
|
||||
if (this.positions.hasOwnProperty(name)) {
|
||||
return (this.variables[this.positions[name]].type = type);
|
||||
this.variables[this.positions[name]].type = type;
|
||||
} else {
|
||||
this.positions[name] = this.variables.length;
|
||||
return this.variables.push({
|
||||
this.positions[name] = -1 + this.variables.push({
|
||||
name: name,
|
||||
type: type
|
||||
});
|
||||
}
|
||||
return this;
|
||||
};
|
||||
Scope.prototype.startLevel = function() {
|
||||
return this.garbage.push([]);
|
||||
this.garbage.push([]);
|
||||
return this;
|
||||
};
|
||||
Scope.prototype.endLevel = function() {
|
||||
var _i, _len, _ref2, _result, garbage, vars;
|
||||
vars = this.variables;
|
||||
_result = [];
|
||||
var _i, _len, _ref2, name;
|
||||
for (_i = 0, _len = (_ref2 = this.garbage.pop()).length; _i < _len; _i++) {
|
||||
garbage = _ref2[_i];
|
||||
if (this.type(garbage) === 'var') {
|
||||
_result.push(this.setVar(garbage, 'reuse'));
|
||||
name = _ref2[_i];
|
||||
if (this.type(name) === 'var') {
|
||||
this.setVar(name, 'reuse');
|
||||
}
|
||||
}
|
||||
return _result;
|
||||
return this;
|
||||
};
|
||||
Scope.prototype.find = function(name, options) {
|
||||
if (this.check(name, options)) {
|
||||
|
@ -62,7 +61,7 @@
|
|||
var _i, _len, _ref2, v;
|
||||
for (_i = 0, _len = (_ref2 = this.variables).length; _i < _len; _i++) {
|
||||
v = _ref2[_i];
|
||||
if (fn(v.name, v.type)) {
|
||||
if (fn(v)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -79,8 +78,8 @@
|
|||
}
|
||||
return !!(((_ref2 = this.parent) != null) ? _ref2.check(name) : undefined);
|
||||
};
|
||||
Scope.prototype.temporary = function(type, index) {
|
||||
return type.length > 1 ? '_' + type + (index > 1 ? index : '') : '_' + (index + parseInt(type, 36)).toString(36).replace(/\d/g, 'a');
|
||||
Scope.prototype.temporary = function(name, index) {
|
||||
return name.length > 1 ? '_' + name + (index > 1 ? index : '') : '_' + (index + parseInt(name, 36)).toString(36).replace(/\d/g, 'a');
|
||||
};
|
||||
Scope.prototype.type = function(name) {
|
||||
var _i, _len, _ref2, v;
|
||||
|
@ -93,15 +92,13 @@
|
|||
return null;
|
||||
};
|
||||
Scope.prototype.freeVariable = function(type) {
|
||||
var index, temp;
|
||||
var _ref2, index, temp;
|
||||
index = 0;
|
||||
while (this.check(temp = this.temporary(type, index)) && this.type(temp) !== 'reuse') {
|
||||
index++;
|
||||
}
|
||||
this.setVar(temp, 'var');
|
||||
if (this.garbage.length) {
|
||||
last(this.garbage).push(temp);
|
||||
}
|
||||
(((_ref2 = last(this.garbage)) != null) ? _ref2.push(temp) : undefined);
|
||||
return temp;
|
||||
};
|
||||
Scope.prototype.assign = function(name, value) {
|
||||
|
@ -111,13 +108,14 @@
|
|||
});
|
||||
};
|
||||
Scope.prototype.hasDeclarations = function(body) {
|
||||
return body === this.expressions && this.any(function(k, val) {
|
||||
return (val === 'var' || val === 'reuse');
|
||||
return body === this.expressions && this.any(function(v) {
|
||||
var _ref2;
|
||||
return ((_ref2 = v.type) === 'var' || _ref2 === 'reuse');
|
||||
});
|
||||
};
|
||||
Scope.prototype.hasAssignments = function(body) {
|
||||
return body === this.expressions && this.any(function(k, val) {
|
||||
return val.assigned;
|
||||
return body === this.expressions && this.any(function(v) {
|
||||
return v.type.assigned;
|
||||
});
|
||||
};
|
||||
Scope.prototype.declaredVariables = function() {
|
||||
|
|
|
@ -21,7 +21,7 @@ exports.Scope = class Scope
|
|||
@variables = [{name: 'arguments', type: 'arguments'}]
|
||||
@positions = {}
|
||||
if @parent
|
||||
@garbage = @parent.garbage
|
||||
{@garbage} = @parent
|
||||
else
|
||||
@garbage = []
|
||||
Scope.root = this
|
||||
|
@ -31,19 +31,19 @@ exports.Scope = class Scope
|
|||
if @positions.hasOwnProperty name
|
||||
@variables[@positions[name]].type = type
|
||||
else
|
||||
@positions[name] = @variables.length
|
||||
@variables.push {name, type}
|
||||
@positions[name] = -1 + @variables.push {name, type}
|
||||
this
|
||||
|
||||
# Create a new garbage level
|
||||
startLevel: ->
|
||||
@garbage.push []
|
||||
this
|
||||
|
||||
# Return to the previous garbage level and erase referenced temporary
|
||||
# variables in current level from scope.
|
||||
endLevel: ->
|
||||
vars = @variables
|
||||
for garbage in @garbage.pop() when @type(garbage) is 'var'
|
||||
@setVar garbage, 'reuse'
|
||||
@setVar name, 'reuse' for name in @garbage.pop() when @type(name) is 'var'
|
||||
this
|
||||
|
||||
# Look up a variable name in lexical scope, and declare it if it does not
|
||||
# already exist.
|
||||
|
@ -52,10 +52,9 @@ exports.Scope = class Scope
|
|||
@setVar name, 'var'
|
||||
false
|
||||
|
||||
# Test variables and return true the first time fn(v, k) returns true
|
||||
# Test variables and return `true` the first time `fn(v)` returns `true`
|
||||
any: (fn) ->
|
||||
for v in @variables when fn v.name, v.type
|
||||
return true
|
||||
for v in @variables when fn v then return true
|
||||
return false
|
||||
|
||||
# Reserve a variable name as originating from a function parameter for this
|
||||
|
@ -71,11 +70,11 @@ exports.Scope = class Scope
|
|||
!!@parent?.check name
|
||||
|
||||
# Generate a temporary variable name at the given index.
|
||||
temporary: (type, index) ->
|
||||
if type.length > 1
|
||||
'_' + type + if index > 1 then index else ''
|
||||
temporary: (name, index) ->
|
||||
if name.length > 1
|
||||
'_' + name + if index > 1 then index else ''
|
||||
else
|
||||
'_' + (index + parseInt type, 36).toString(36).replace /\d/g, 'a'
|
||||
'_' + (index + parseInt name, 36).toString(36).replace /\d/g, 'a'
|
||||
|
||||
# Gets the type of a variable.
|
||||
type: (name) ->
|
||||
|
@ -88,7 +87,7 @@ exports.Scope = class Scope
|
|||
index = 0
|
||||
index++ while @check(temp = @temporary type, index) and @type(temp) isnt 'reuse'
|
||||
@setVar temp, 'var'
|
||||
last(@garbage).push temp if @garbage.length
|
||||
last(@garbage)?.push temp
|
||||
temp
|
||||
|
||||
# Ensure that an assignment is made at the top of this scope
|
||||
|
@ -99,12 +98,12 @@ exports.Scope = class Scope
|
|||
# Does this scope reference any variables that need to be declared in the
|
||||
# given function body?
|
||||
hasDeclarations: (body) ->
|
||||
body is @expressions and @any (k, val) -> val in ['var', 'reuse']
|
||||
body is @expressions and @any (v) -> v.type in ['var', 'reuse']
|
||||
|
||||
# Does this scope reference any assignments that need to be declared at the
|
||||
# top of the given function body?
|
||||
hasAssignments: (body) ->
|
||||
body is @expressions and @any (k, val) -> val.assigned
|
||||
body is @expressions and @any (v) -> v.type.assigned
|
||||
|
||||
# Return the list of variables first declared in this scope.
|
||||
declaredVariables: ->
|
||||
|
|
Loading…
Add table
Reference in a new issue