mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
Re-enabling garbage collection of tempvars, only at function boundaries.
This commit is contained in:
parent
d4dac214ab
commit
69d2048ccc
7 changed files with 69 additions and 29 deletions
|
@ -2,6 +2,6 @@
|
|||
lunch = eat food for food in ['toast', 'cheese', 'wine']
|
||||
|
||||
# Naive collision detection.
|
||||
for roid, index in asteroids
|
||||
for roid, pos in asteroids
|
||||
for roid2 in asteroids when roid isnt roid2
|
||||
roid.explode() if roid.overlaps roid2
|
|
@ -1,4 +1,4 @@
|
|||
var _i, _j, _len, _len2, _len3, _ref, _result, food, index, lunch, roid, roid2;
|
||||
var _i, _len, _len2, _ref, _result, food, lunch, pos, roid, roid2;
|
||||
lunch = (function() {
|
||||
_result = []; _ref = ['toast', 'cheese', 'wine'];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
|
@ -7,10 +7,10 @@ lunch = (function() {
|
|||
}
|
||||
return _result;
|
||||
})();
|
||||
for (index = 0, _len2 = asteroids.length; index < _len2; index++) {
|
||||
roid = asteroids[index];
|
||||
for (_j = 0, _len3 = asteroids.length; _j < _len3; _j++) {
|
||||
roid2 = asteroids[_j];
|
||||
for (pos = 0, _len = asteroids.length; pos < _len; pos++) {
|
||||
roid = asteroids[pos];
|
||||
for (_i = 0, _len2 = asteroids.length; _i < _len2; _i++) {
|
||||
roid2 = asteroids[_i];
|
||||
if (roid !== roid2) {
|
||||
if (roid.overlaps(roid2)) {
|
||||
roid.explode();
|
||||
|
|
12
index.html
12
index.html
|
@ -829,10 +829,10 @@ lyrics = (function() {
|
|||
lunch <span class="Keyword">=</span> eat food <span class="Keyword">for</span> food <span class="Keyword">in</span> [<span class="String"><span class="String">'</span>toast<span class="String">'</span></span>, <span class="String"><span class="String">'</span>cheese<span class="String">'</span></span>, <span class="String"><span class="String">'</span>wine<span class="String">'</span></span>]
|
||||
|
||||
<span class="Comment"><span class="Comment">#</span> Naive collision detection.</span>
|
||||
<span class="Keyword">for</span> roid, index <span class="Keyword">in</span> asteroids
|
||||
<span class="Keyword">for</span> roid, pos <span class="Keyword">in</span> asteroids
|
||||
<span class="Keyword">for</span> roid2 <span class="Keyword">in</span> asteroids <span class="Keyword">when</span> roid <span class="Keyword">isnt</span> roid2
|
||||
roid.explode() <span class="Keyword">if</span> roid.overlaps roid2
|
||||
</pre><pre class="idle"><span class="Storage">var</span> _i, _j, _len, _len2, _len3, _ref, _result, food, index, lunch, roid, roid2;
|
||||
</pre><pre class="idle"><span class="Storage">var</span> _i, _len, _len2, _ref, _result, food, lunch, pos, roid, roid2;
|
||||
lunch <span class="Keyword">=</span> (<span class="Storage">function</span>() {
|
||||
_result <span class="Keyword">=</span> []; _ref <span class="Keyword">=</span> [<span class="String"><span class="String">'</span>toast<span class="String">'</span></span>, <span class="String"><span class="String">'</span>cheese<span class="String">'</span></span>, <span class="String"><span class="String">'</span>wine<span class="String">'</span></span>];
|
||||
<span class="Keyword">for</span> (_i <span class="Keyword">=</span> <span class="Number">0</span>, _len <span class="Keyword">=</span> _ref.<span class="LibraryConstant">length</span>; _i <span class="Keyword"><</span> _len; _i<span class="Keyword">++</span>) {
|
||||
|
@ -841,10 +841,10 @@ lunch <span class="Keyword">=</span> (<span class="Storage">function</span>() {
|
|||
}
|
||||
<span class="Keyword">return</span> _result;
|
||||
})();
|
||||
<span class="Keyword">for</span> (index <span class="Keyword">=</span> <span class="Number">0</span>, _len2 <span class="Keyword">=</span> asteroids.<span class="LibraryConstant">length</span>; index <span class="Keyword"><</span> _len2; index<span class="Keyword">++</span>) {
|
||||
roid <span class="Keyword">=</span> asteroids[index];
|
||||
<span class="Keyword">for</span> (_j <span class="Keyword">=</span> <span class="Number">0</span>, _len3 <span class="Keyword">=</span> asteroids.<span class="LibraryConstant">length</span>; _j <span class="Keyword"><</span> _len3; _j<span class="Keyword">++</span>) {
|
||||
roid2 <span class="Keyword">=</span> asteroids[_j];
|
||||
<span class="Keyword">for</span> (pos <span class="Keyword">=</span> <span class="Number">0</span>, _len <span class="Keyword">=</span> asteroids.<span class="LibraryConstant">length</span>; pos <span class="Keyword"><</span> _len; pos<span class="Keyword">++</span>) {
|
||||
roid <span class="Keyword">=</span> asteroids[pos];
|
||||
<span class="Keyword">for</span> (_i <span class="Keyword">=</span> <span class="Number">0</span>, _len2 <span class="Keyword">=</span> asteroids.<span class="LibraryConstant">length</span>; _i <span class="Keyword"><</span> _len2; _i<span class="Keyword">++</span>) {
|
||||
roid2 <span class="Keyword">=</span> asteroids[_i];
|
||||
<span class="Keyword">if</span> (roid <span class="Keyword">!</span><span class="Keyword">==</span> roid2) {
|
||||
<span class="Keyword">if</span> (roid.overlaps(roid2)) {
|
||||
roid.explode();
|
||||
|
|
20
lib/nodes.js
20
lib/nodes.js
|
@ -785,7 +785,7 @@
|
|||
ObjectNode.prototype.children = ['properties'];
|
||||
ObjectNode.prototype.topSensitive = YES;
|
||||
ObjectNode.prototype.compileNode = function(o) {
|
||||
var _i, _len, _len2, _ref2, _ref3, _result, _result2, i, indent, join, lastNoncom, nonComments, obj, prop, props, top;
|
||||
var _i, _len, _ref2, _result, i, indent, join, lastNoncom, nonComments, obj, prop, props, top;
|
||||
top = del(o, 'top');
|
||||
o.indent = this.idt(1);
|
||||
nonComments = (function() {
|
||||
|
@ -800,10 +800,10 @@
|
|||
}).call(this);
|
||||
lastNoncom = last(nonComments);
|
||||
props = (function() {
|
||||
_result2 = []; _ref3 = this.properties;
|
||||
for (i = 0, _len2 = _ref3.length; i < _len2; i++) {
|
||||
prop = _ref3[i];
|
||||
_result2.push((function() {
|
||||
_result = []; _ref2 = this.properties;
|
||||
for (i = 0, _len = _ref2.length; i < _len; i++) {
|
||||
prop = _ref2[i];
|
||||
_result.push((function() {
|
||||
join = ",\n";
|
||||
if ((prop === lastNoncom) || (prop instanceof CommentNode)) {
|
||||
join = "\n";
|
||||
|
@ -820,7 +820,7 @@
|
|||
return indent + prop.compile(o) + join;
|
||||
}).call(this));
|
||||
}
|
||||
return _result2;
|
||||
return _result;
|
||||
}).call(this);
|
||||
props = props.join('');
|
||||
obj = '{' + (props ? '\n' + props + '\n' + this.idt() : '') + '}';
|
||||
|
@ -1102,7 +1102,7 @@
|
|||
__extends(CodeNode, BaseNode);
|
||||
CodeNode.prototype.children = ['params', 'body'];
|
||||
CodeNode.prototype.compileNode = function(o) {
|
||||
var _i, _j, _len, _len2, _len3, _ref2, _ref3, _result, close, code, empty, func, i, open, param, params, sharedScope, splat, top, value;
|
||||
var _i, _len, _len2, _ref2, _ref3, _result, close, code, empty, func, i, open, param, params, sharedScope, splat, top, value;
|
||||
sharedScope = del(o, 'sharedScope');
|
||||
top = del(o, 'top');
|
||||
o.scope = sharedScope || new Scope(o.scope, this.body, this);
|
||||
|
@ -1139,6 +1139,7 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
o.scope.startLevel();
|
||||
params = (function() {
|
||||
_result = [];
|
||||
for (_i = 0, _len2 = params.length; _i < _len2; _i++) {
|
||||
|
@ -1150,8 +1151,8 @@
|
|||
if (!(empty)) {
|
||||
this.body.makeReturn();
|
||||
}
|
||||
for (_j = 0, _len3 = params.length; _j < _len3; _j++) {
|
||||
param = params[_j];
|
||||
for (_i = 0, _len2 = params.length; _i < _len2; _i++) {
|
||||
param = params[_i];
|
||||
(o.scope.parameter(param));
|
||||
}
|
||||
if (this.className) {
|
||||
|
@ -1161,6 +1162,7 @@
|
|||
open = this.className ? ("(function() {\n" + (this.idt(1)) + "return function " + (this.className) + "(") : "function(";
|
||||
close = this.className ? ("" + (code && this.idt(1)) + "};\n" + (this.tab) + "})()") : ("" + (code && this.tab) + "}");
|
||||
func = ("" + open + (params.join(', ')) + ") {" + code + close);
|
||||
o.scope.endLevel();
|
||||
if (this.bound) {
|
||||
return ("" + (utility('bind')) + "(" + func + ", " + (this.context) + ")");
|
||||
}
|
||||
|
|
29
lib/scope.js
29
lib/scope.js
|
@ -11,13 +11,31 @@
|
|||
this.variables = {
|
||||
'arguments': 'arguments'
|
||||
};
|
||||
if (!(this.parent)) {
|
||||
if (this.parent) {
|
||||
this.garbage = this.parent.garbage;
|
||||
} else {
|
||||
this.garbage = [];
|
||||
Scope.root = this;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
})();
|
||||
Scope.root = null;
|
||||
Scope.prototype.startLevel = function() {
|
||||
return this.garbage.push([]);
|
||||
};
|
||||
Scope.prototype.endLevel = function() {
|
||||
var _i, _len, _ref2, _result, name, vars;
|
||||
vars = this.variables;
|
||||
_result = []; _ref2 = this.garbage.pop();
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
name = _ref2[_i];
|
||||
if (vars[name] === 'var') {
|
||||
_result.push(vars[name] = 'reuse');
|
||||
}
|
||||
}
|
||||
return _result;
|
||||
};
|
||||
Scope.prototype.find = function(name, options) {
|
||||
if (this.check(name, options)) {
|
||||
return true;
|
||||
|
@ -54,10 +72,13 @@
|
|||
Scope.prototype.freeVariable = function(type) {
|
||||
var index, temp;
|
||||
index = 0;
|
||||
while (this.check(temp = this.temporary(type, index))) {
|
||||
while (this.check(temp = this.temporary(type, index)) && this.variables[temp] !== 'reuse') {
|
||||
index++;
|
||||
}
|
||||
this.variables[temp] = 'var';
|
||||
if (this.garbage.length) {
|
||||
last(this.garbage).push(temp);
|
||||
}
|
||||
return temp;
|
||||
};
|
||||
Scope.prototype.assign = function(name, value) {
|
||||
|
@ -68,7 +89,7 @@
|
|||
};
|
||||
Scope.prototype.hasDeclarations = function(body) {
|
||||
return body === this.expressions && this.any(function(k, val) {
|
||||
return val === 'var';
|
||||
return ('var' === val || 'reuse' === val);
|
||||
});
|
||||
};
|
||||
Scope.prototype.hasAssignments = function(body) {
|
||||
|
@ -83,7 +104,7 @@
|
|||
for (key in _ref2) {
|
||||
if (!__hasProp.call(_ref2, key)) continue;
|
||||
val = _ref2[key];
|
||||
if (val === 'var') {
|
||||
if (('var' === val || 'reuse' === val)) {
|
||||
_result.push(key);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -984,6 +984,7 @@ exports.CodeNode = class CodeNode extends BaseNode
|
|||
@body.unshift(splat)
|
||||
else
|
||||
params.push param
|
||||
o.scope.startLevel()
|
||||
params = (param.compile(o) for param in params)
|
||||
@body.makeReturn() unless empty
|
||||
(o.scope.parameter(param)) for param in params
|
||||
|
@ -992,6 +993,7 @@ exports.CodeNode = class CodeNode extends BaseNode
|
|||
open = if @className then "(function() {\n#{@idt(1)}return function #{@className}(" else "function("
|
||||
close = if @className then "#{code and @idt(1)}};\n#{@tab}})()" else "#{code and @tab}}"
|
||||
func = "#{open}#{ params.join(', ') }) {#{code}#{close}"
|
||||
o.scope.endLevel()
|
||||
return "#{utility 'bind'}(#{func}, #{@context})" if @bound
|
||||
if top then "(#{func})" else func
|
||||
|
||||
|
|
|
@ -19,7 +19,21 @@ exports.Scope = class Scope
|
|||
# it wraps.
|
||||
constructor: (@parent, @expressions, @method) ->
|
||||
@variables = {'arguments'}
|
||||
Scope.root = this unless @parent
|
||||
if @parent
|
||||
@garbage = @parent.garbage
|
||||
else
|
||||
@garbage = []
|
||||
Scope.root = this
|
||||
|
||||
# Create a new garbage level
|
||||
startLevel: ->
|
||||
@garbage.push []
|
||||
|
||||
# Return to the previous garbage level and erase referenced temporary
|
||||
# variables in current level from scope.
|
||||
endLevel: ->
|
||||
vars = @variables
|
||||
(vars[name] = 'reuse') for name in @garbage.pop() when vars[name] is 'var'
|
||||
|
||||
# Look up a variable name in lexical scope, and declare it if it does not
|
||||
# already exist.
|
||||
|
@ -57,8 +71,9 @@ exports.Scope = class Scope
|
|||
# compiler-generated variable. `_var`, `_var2`, and so on...
|
||||
freeVariable: (type) ->
|
||||
index = 0
|
||||
index++ while @check(temp = @temporary type, index)
|
||||
index++ while @check(temp = @temporary type, index) and @variables[temp] isnt 'reuse'
|
||||
@variables[temp] = 'var'
|
||||
last(@garbage).push temp if @garbage.length
|
||||
temp
|
||||
|
||||
# Ensure that an assignment is made at the top of this scope
|
||||
|
@ -69,7 +84,7 @@ 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 is 'var'
|
||||
body is @expressions and @any (k, val) -> val in ['var', 'reuse']
|
||||
|
||||
# Does this scope reference any assignments that need to be declared at the
|
||||
# top of the given function body?
|
||||
|
@ -78,7 +93,7 @@ exports.Scope = class Scope
|
|||
|
||||
# Return the list of variables first declared in this scope.
|
||||
declaredVariables: ->
|
||||
(key for key, val of @variables when val is 'var').sort()
|
||||
(key for key, val of @variables when val in ['var', 'reuse']).sort()
|
||||
|
||||
# Return the list of assignments that are supposed to be made at the top
|
||||
# of this scope.
|
||||
|
|
Loading…
Add table
Reference in a new issue