From 8fff6e9bafe13a88fa4f25e426946220d4ac362a Mon Sep 17 00:00:00 2001 From: Timothy Jones Date: Wed, 20 Oct 2010 12:36:50 +1300 Subject: [PATCH] Refactoring scope to use an array instead of an object, to make the IE bugfix significantly tidier. --- lib/nodes.js | 206 ++++++++++++++++++++++++++++++++++++++++++++--- lib/rewriter.js | 1 + lib/scope.js | 104 +++++++++++++----------- src/nodes.coffee | 2 +- src/scope.coffee | 41 +++++----- 5 files changed, 275 insertions(+), 79 deletions(-) diff --git a/lib/nodes.js b/lib/nodes.js index 93d80122..6b368f34 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -6,6 +6,168 @@ child.prototype = new ctor; if (typeof parent.extended === "function") parent.extended(child); child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; + }, __extends = function(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor; + if (typeof parent.extended === "function") parent.extended(child); + child.__super__ = parent.prototype; }; Scope = require('./scope').Scope; _ref = require('./helpers'), compact = _ref.compact, flatten = _ref.flatten, merge = _ref.merge, del = _ref.del, include = _ref.include, starts = _ref.starts, ends = _ref.ends, last = _ref.last; @@ -250,6 +412,7 @@ exports.Literal = (function() { Literal = (function() { function Literal(_arg) { + var _arg; this.value = _arg; Literal.__super__.constructor.call(this); return this; @@ -287,6 +450,7 @@ exports.Return = (function() { Return = (function() { function Return(_arg) { + var _arg; this.expression = _arg; Return.__super__.constructor.call(this); return this; @@ -322,6 +486,7 @@ exports.Value = (function() { Value = (function() { function Value(_arg, _arg2, tag) { + var _arg, _arg2; this.properties = _arg2; this.base = _arg; Value.__super__.constructor.call(this); @@ -443,6 +608,7 @@ exports.Comment = (function() { Comment = (function() { function Comment(_arg) { + var _arg; this.comment = _arg; Comment.__super__.constructor.call(this); return this; @@ -460,6 +626,7 @@ exports.Call = (function() { Call = (function() { function Call(variable, _arg, _arg2) { + var _arg, _arg2; this.soakNode = _arg2; this.args = _arg; Call.__super__.constructor.call(this); @@ -598,6 +765,7 @@ exports.Extends = (function() { Extends = (function() { function Extends(_arg, _arg2) { + var _arg, _arg2; this.parent = _arg2; this.child = _arg; Extends.__super__.constructor.call(this); @@ -617,6 +785,7 @@ exports.Accessor = (function() { Accessor = (function() { function Accessor(_arg, tag) { + var _arg; this.name = _arg; Accessor.__super__.constructor.call(this); this.prototype = tag === 'prototype' ? '.prototype' : ''; @@ -639,6 +808,7 @@ exports.Index = (function() { Index = (function() { function Index(_arg) { + var _arg; this.index = _arg; Index.__super__.constructor.call(this); return this; @@ -661,6 +831,7 @@ exports.Range = (function() { Range = (function() { function Range(_arg, _arg2, tag) { + var _arg, _arg2; this.to = _arg2; this.from = _arg; Range.__super__.constructor.call(this); @@ -749,6 +920,7 @@ exports.Slice = (function() { Slice = (function() { function Slice(_arg) { + var _arg; this.range = _arg; Slice.__super__.constructor.call(this); return this; @@ -781,7 +953,7 @@ __extends(ObjectLiteral, Base); ObjectLiteral.prototype.children = ['properties']; ObjectLiteral.prototype.compileNode = function(o) { - var _i, _len, _ref2, _result, i, indent, join, lastNoncom, nonComments, obj, prop, props, top; + var _i, _len, _len2, _ref2, _ref3, _result, _result2, i, indent, join, lastNoncom, nonComments, obj, prop, props, top; top = del(o, 'top'); o.indent = this.idt(1); nonComments = (function() { @@ -796,10 +968,10 @@ }).call(this); lastNoncom = last(nonComments); props = (function() { - _result = []; - for (i = 0, _len = (_ref2 = this.properties).length; i < _len; i++) { - prop = _ref2[i]; - _result.push((function() { + _result2 = []; + for (i = 0, _len2 = (_ref3 = this.properties).length; i < _len2; i++) { + prop = _ref3[i]; + _result2.push((function() { join = i === this.properties.length - 1 ? '' : (prop === lastNoncom || prop instanceof Comment ? '\n' : ',\n'); indent = prop instanceof Comment ? '' : this.idt(1); if (prop instanceof Value && prop.tags["this"]) { @@ -810,7 +982,7 @@ return indent + prop.compile(o) + join; }).call(this)); } - return _result; + return _result2; }).call(this); props = props.join(''); obj = ("{" + (props ? '\n' + props + '\n' + this.idt() : '') + "}"); @@ -831,6 +1003,7 @@ exports.ArrayLiteral = (function() { ArrayLiteral = (function() { function ArrayLiteral(_arg) { + var _arg; this.objects = _arg; ArrayLiteral.__super__.constructor.call(this); this.objects || (this.objects = []); @@ -876,6 +1049,7 @@ exports.Class = (function() { Class = (function() { function Class(variable, _arg, _arg2) { + var _arg, _arg2; this.properties = _arg2; this.parent = _arg; Class.__super__.constructor.call(this); @@ -974,6 +1148,7 @@ exports.Assign = (function() { Assign = (function() { function Assign(_arg, _arg2, _arg3) { + var _arg, _arg2, _arg3; this.context = _arg3; this.value = _arg2; this.variable = _arg; @@ -1107,6 +1282,7 @@ exports.Code = (function() { Code = (function() { function Code(_arg, _arg2, tag) { + var _arg, _arg2; this.body = _arg2; this.params = _arg; Code.__super__.constructor.call(this); @@ -1123,7 +1299,7 @@ __extends(Code, Base); Code.prototype.children = ['params', 'body']; Code.prototype.compileNode = function(o) { - var _i, _len, _len2, _ref2, _ref3, _result, close, code, comm, empty, func, i, open, param, params, sharedScope, splat, top, value; + var _i, _j, _len, _len2, _len3, _ref2, _ref3, _result, close, code, comm, 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); @@ -1171,8 +1347,8 @@ if (!(empty || this.noReturn)) { this.body.makeReturn(); } - for (_i = 0, _len2 = params.length; _i < _len2; _i++) { - param = params[_i]; + for (_j = 0, _len3 = params.length; _j < _len3; _j++) { + param = params[_j]; (o.scope.parameter(param)); } comm = this.comment ? this.comment.compile(o) + '\n' : ''; @@ -1197,6 +1373,7 @@ exports.Param = (function() { Param = (function() { function Param(_arg, _arg2, _arg3) { + var _arg, _arg2, _arg3; this.splat = _arg3; this.attach = _arg2; this.name = _arg; @@ -1465,6 +1642,7 @@ exports.In = (function() { In = (function() { function In(_arg, _arg2) { + var _arg, _arg2; this.array = _arg2; this.object = _arg; In.__super__.constructor.call(this); @@ -1503,6 +1681,7 @@ exports.Try = (function() { Try = (function() { function Try(_arg, _arg2, _arg3, _arg4) { + var _arg, _arg2, _arg3, _arg4; this.ensure = _arg4; this.recovery = _arg3; this.error = _arg2; @@ -1539,6 +1718,7 @@ exports.Throw = (function() { Throw = (function() { function Throw(_arg) { + var _arg; this.expression = _arg; Throw.__super__.constructor.call(this); return this; @@ -1557,6 +1737,7 @@ exports.Existence = (function() { Existence = (function() { function Existence(_arg) { + var _arg; this.expression = _arg; Existence.__super__.constructor.call(this); return this; @@ -1576,6 +1757,7 @@ exports.Parens = (function() { Parens = (function() { function Parens(_arg) { + var _arg; this.expression = _arg; Parens.__super__.constructor.call(this); return this; @@ -1612,7 +1794,7 @@ exports.For = (function() { For = (function() { function For(_arg, source, _arg2, _arg3) { - var _ref2; + var _arg, _arg2, _arg3, _ref2; this.index = _arg3; this.name = _arg2; this.body = _arg; @@ -1771,6 +1953,7 @@ exports.Switch = (function() { Switch = (function() { function Switch(_arg, _arg2, _arg3) { + var _arg, _arg2, _arg3; this.otherwise = _arg3; this.cases = _arg2; this.subject = _arg; @@ -1827,6 +2010,7 @@ exports.If = (function() { If = (function() { function If(condition, _arg, tags) { + var _arg; this.body = _arg; this.tags = tags || (tags = {}); this.condition = tags.invert ? condition.invert() : condition; @@ -1962,7 +2146,7 @@ UTILITIES = { "extends": 'function(child, parent) {\n function ctor() { this.constructor = child; }\n ctor.prototype = parent.prototype;\n child.prototype = new ctor;\n if (typeof parent.extended === "function") parent.extended(child);\n child.__super__ = parent.prototype;\n}', bind: 'function(func, context) {\n return function() { return func.apply(context, arguments); };\n}', - inArray: '(function() {\n var indexOf = Array.prototype.indexOf || function(item) {\n var i = this.length; while (i--) if (this[i] === item) return i;\n return -1;\n };\n return function(item, array) { return indexOf.call(array, item) > -1; };\n})();', + inArray: '(function() {\n var indexOf = Array.prototype.indexOf || function(item) {\n var i = this.length; while (i--) if (this[i] === item) return i;\n return -1;\n };\n return function(item, array) { return indexOf.call(array, item) > -1; };\n})()', hasProp: 'Object.prototype.hasOwnProperty', slice: 'Array.prototype.slice' }; diff --git a/lib/rewriter.js b/lib/rewriter.js index 6999fc88..924d58b5 100644 --- a/lib/rewriter.js +++ b/lib/rewriter.js @@ -8,6 +8,7 @@ return Rewriter; })(); exports.Rewriter.prototype.rewrite = function(_arg) { + var _arg; this.tokens = _arg; this.adjustComments(); this.removeLeadingNewlines(); diff --git a/lib/scope.js b/lib/scope.js index ec81b12c..5a89fbdb 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -1,16 +1,19 @@ (function() { var Scope, _ref, extend, last; - var __hasProp = Object.prototype.hasOwnProperty; _ref = require('./helpers'), extend = _ref.extend, last = _ref.last; exports.Scope = (function() { Scope = (function() { function Scope(_arg, _arg2, _arg3) { + var _arg, _arg2, _arg3; this.method = _arg3; this.expressions = _arg2; this.parent = _arg; - this.variables = { - 'arguments': 'arguments' - }; + this.variables = [ + { + name: 'arguments', + type: 'arguments' + } + ]; if (this.parent) { this.garbage = this.parent.garbage; } else { @@ -26,13 +29,22 @@ return this.garbage.push([]); }; Scope.prototype.endLevel = function() { - var _i, _len, _ref2, _result, name, vars; + var _i, _len, _len2, _ref2, _result, garbage, i, v, vars; vars = this.variables; _result = []; for (_i = 0, _len = (_ref2 = this.garbage.pop()).length; _i < _len; _i++) { - name = _ref2[_i]; - if (vars[name] === 'var') { - _result.push(vars[name] = 'reuse'); + garbage = _ref2[_i]; + if (this.type(garbage) === 'var') { + for (i = 0, _len2 = vars.length; i < _len2; i++) { + v = vars[i]; + if (v.name === garbage.name) { + vars.splice(i, 1, { + name: garbage.name, + type: 'reuse' + }); + break; + } + } } } return _result; @@ -41,25 +53,31 @@ if (this.check(name, options)) { return true; } - this.variables[name] = 'var'; + this.variables.push({ + name: name, + type: 'var' + }); return false; }; Scope.prototype.any = function(fn) { var _i, _len, _ref2, v; - for (_i = 0, _len = (_ref2 = this.allVariables()).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref2 = this.variables).length; _i < _len; _i++) { v = _ref2[_i]; - if (fn(v[0], v[1])) { + if (fn(v.name, v.type)) { return true; } } return false; }; Scope.prototype.parameter = function(name) { - return (this.variables[name] = 'param'); + return this.variables.push({ + name: name, + type: 'param' + }); }; Scope.prototype.check = function(name, options) { var _ref2, immediate; - immediate = Object.prototype.hasOwnProperty.call(this.variables, name); + immediate = !!this.type(name); if (immediate || ((options != null) ? options.immediate : undefined)) { return immediate; } @@ -68,46 +86,40 @@ 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.type = function(name) { + var _i, _len, _ref2, v; + for (_i = 0, _len = (_ref2 = this.variables).length; _i < _len; _i++) { + v = _ref2[_i]; + if (v.name === name) { + return v.type; + } + } + return null; + }; Scope.prototype.freeVariable = function(type) { var index, temp; index = 0; - while (this.check(temp = this.temporary(type, index)) && this.variables[temp] !== 'reuse') { + while (this.check(temp = this.temporary(type, index)) && this.type(temp) !== 'reuse') { index++; } - this.variables[temp] = 'var'; + this.variables.push({ + name: temp, + type: 'var' + }); if (this.garbage.length) { last(this.garbage).push(temp); } return temp; }; Scope.prototype.assign = function(name, value) { - return (this.variables[name] = { - value: value, - assigned: true + return this.variables.push({ + name: name, + type: { + value: value, + assigned: true + } }); }; - Scope.prototype.allVariables = function() { - var _i, _len, _ref2, _result, k, v, vars; - vars = (function() { - _result = []; - for (v in _ref2 = this.variables) { - if (!__hasProp.call(_ref2, v)) continue; - k = _ref2[v]; - _result.push([v, k]); - } - return _result; - }).call(this); - return v.__defineGetter__ ? vars : vars.concat((function() { - _result = []; - for (_i = 0, _len = (_ref2 = 'toString toLocaleString\nhasOwnProperty valueOf constructor propertyIsEnumerable\nisPrototypeOf'.split(' ')).length; _i < _len; _i++) { - v = _ref2[_i]; - if (this.variables.hasOwnProperty(v)) { - _result.push([v, this.variables[v]]); - } - } - return _result; - }).call(this)); - }; Scope.prototype.hasDeclarations = function(body) { return body === this.expressions && this.any(function(k, val) { return (val === 'var' || val === 'reuse'); @@ -122,10 +134,10 @@ var _i, _len, _ref2, _ref3, _result, v; return (function() { _result = []; - for (_i = 0, _len = (_ref2 = this.allVariables()).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref2 = this.variables).length; _i < _len; _i++) { v = _ref2[_i]; - if (((_ref3 = v[1]) === 'var' || _ref3 === 'reuse')) { - _result.push(v[0]); + if (((_ref3 = v.type) === 'var' || _ref3 === 'reuse')) { + _result.push(v.name); } } return _result; @@ -134,10 +146,10 @@ Scope.prototype.assignedVariables = function() { var _i, _len, _ref2, _result, v; _result = []; - for (_i = 0, _len = (_ref2 = this.allVariables()).length; _i < _len; _i++) { + for (_i = 0, _len = (_ref2 = this.variables).length; _i < _len; _i++) { v = _ref2[_i]; - if (v[1].assigned) { - _result.push("" + (v[0]) + " = " + (v[1].value)); + if (v.type.assigned) { + _result.push("" + (v.name) + " = " + (v.type.value)); } } return _result; diff --git a/src/nodes.coffee b/src/nodes.coffee index 99e372a4..cf85d118 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -1679,7 +1679,7 @@ UTILITIES = return -1; }; return function(item, array) { return indexOf.call(array, item) > -1; }; - })(); + })() ''' # Shortcuts to speed up the lookup time for native functions. diff --git a/src/scope.coffee b/src/scope.coffee index 6e320962..88aac430 100644 --- a/src/scope.coffee +++ b/src/scope.coffee @@ -18,7 +18,7 @@ exports.Scope = class Scope # where it should declare its variables, and a reference to the function that # it wraps. constructor: (@parent, @expressions, @method) -> - @variables = {'arguments'} + @variables = [{name: 'arguments', type: 'arguments'}] if @parent @garbage = @parent.garbage else @@ -33,30 +33,33 @@ exports.Scope = class Scope # variables in current level from scope. endLevel: -> vars = @variables - (vars[name] = 'reuse') for name in @garbage.pop() when vars[name] is 'var' + for garbage in @garbage.pop() when @type(garbage) is 'var' + for v, i in vars when v.name is garbage.name + vars.splice(i, 1, {name: garbage.name, type: 'reuse'}) + break # Look up a variable name in lexical scope, and declare it if it does not # already exist. find: (name, options) -> return true if @check name, options - @variables[name] = 'var' + @variables.push {name, type: 'var'} false # Test variables and return true the first time fn(v, k) returns true any: (fn) -> - for v in @allVariables() when fn(v[0], v[1]) + for v in @variables when fn v.name, v.type return true return false # Reserve a variable name as originating from a function parameter for this # scope. No `var` required for internal references. parameter: (name) -> - @variables[name] = 'param' + @variables.push {name, type: 'param'} # 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 + immediate = !!@type(name) return immediate if immediate or options?.immediate !!@parent?.check name @@ -66,29 +69,25 @@ exports.Scope = class Scope '_' + type + if index > 1 then index else '' else '_' + (index + parseInt type, 36).toString(36).replace /\d/g, 'a' - + + # Gets the type of a variable. + type: (name) -> + for v in @variables when v.name is name then return v.type + null + # If we need to store an intermediate result, find an available name for a # compiler-generated variable. `_var`, `_var2`, and so on... freeVariable: (type) -> index = 0 - index++ while @check(temp = @temporary type, index) and @variables[temp] isnt 'reuse' - @variables[temp] = 'var' + index++ while @check(temp = @temporary type, index) and @type(temp) isnt 'reuse' + @variables.push {name: temp, type: 'var'} last(@garbage).push temp if @garbage.length temp # Ensure that an assignment is made at the top of this scope # (or at the top-level scope, if requested). assign: (name, value) -> - @variables[name] = value: value, assigned: true - - # Gets around a bug in IE where it won't enumerate over redefined prototype properties. - allVariables: -> - vars = [v, k] for v, k of @variables - if v.__defineGetter__ then vars - else vars.concat(for v in '''toString toLocaleString - hasOwnProperty valueOf constructor propertyIsEnumerable - isPrototypeOf'''.split(' ') when @variables.hasOwnProperty v - [v, @variables[v]]) + @variables.push {name, type: { value: value, assigned: true }} # Does this scope reference any variables that need to be declared in the # given function body? @@ -102,12 +101,12 @@ exports.Scope = class Scope # Return the list of variables first declared in this scope. declaredVariables: -> - (v[0] for v in @allVariables() when v[1] in ['var', 'reuse']).sort() + (v.name for v in @variables when v.type in ['var', 'reuse']).sort() # Return the list of assignments that are supposed to be made at the top # of this scope. assignedVariables: -> - "#{v[0]} = #{v[1].value}" for v in @allVariables() when v[1].assigned + "#{v.name} = #{v.type.value}" for v in @variables when v.type.assigned # Compile the JavaScript for all of the variable declarations in this scope. compiledDeclarations: ->