mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-01-14 17:27:59 -05:00
Get rid of Scope.root hack
Using the static property `Scope.root` for the top-level scope of a file is a hack, which makes it impossible to have several independent `Scope` instances at the same time (should we ever need that). This commit makes every instance have a reference to its root instead.
This commit is contained in:
@@ -1054,7 +1054,7 @@
|
||||
Extends.prototype.children = ['child', 'parent'];
|
||||
|
||||
Extends.prototype.compileToFragments = function(o) {
|
||||
return new Call(new Value(new Literal(utility('extends'))), [this.child, this.parent]).compileToFragments(o);
|
||||
return new Call(new Value(new Literal(utility('extends', o))), [this.child, this.parent]).compileToFragments(o);
|
||||
};
|
||||
|
||||
return Extends;
|
||||
@@ -1423,7 +1423,7 @@
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
bvar = _ref2[_i];
|
||||
lhs = (new Value(new Literal("this"), [new Access(bvar)])).compile(o);
|
||||
this.ctor.body.unshift(new Literal(lhs + " = " + (utility('bind')) + "(" + lhs + ", this)"));
|
||||
this.ctor.body.unshift(new Literal(lhs + " = " + (utility('bind', o)) + "(" + lhs + ", this)"));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1698,7 +1698,7 @@
|
||||
if (!expandedIdx && obj instanceof Splat) {
|
||||
name = obj.name.unwrap().value;
|
||||
obj = obj.unwrap();
|
||||
val = olen + " <= " + vvarText + ".length ? " + (utility('slice')) + ".call(" + vvarText + ", " + i;
|
||||
val = olen + " <= " + vvarText + ".length ? " + (utility('slice', o)) + ".call(" + vvarText + ", " + i;
|
||||
if (rest = olen - i - 1) {
|
||||
ivar = o.scope.freeVariable('i');
|
||||
val += ", " + ivar + " = " + vvarText + ".length - " + rest + ") : (" + ivar + " = " + i + ", [])";
|
||||
@@ -2111,13 +2111,13 @@
|
||||
if (apply) {
|
||||
return fragments;
|
||||
}
|
||||
return [].concat(node.makeCode((utility('slice')) + ".call("), fragments, node.makeCode(")"));
|
||||
return [].concat(node.makeCode((utility('slice', o)) + ".call("), fragments, node.makeCode(")"));
|
||||
}
|
||||
args = list.slice(index);
|
||||
for (i = _i = 0, _len = args.length; _i < _len; i = ++_i) {
|
||||
node = args[i];
|
||||
compiledNode = node.compileToFragments(o, LEVEL_LIST);
|
||||
args[i] = node instanceof Splat ? [].concat(node.makeCode((utility('slice')) + ".call("), compiledNode, node.makeCode(")")) : [].concat(node.makeCode("["), compiledNode, node.makeCode("]"));
|
||||
args[i] = node instanceof Splat ? [].concat(node.makeCode((utility('slice', o)) + ".call("), compiledNode, node.makeCode(")")) : [].concat(node.makeCode("["), compiledNode, node.makeCode("]"));
|
||||
}
|
||||
if (index === 0) {
|
||||
node = list[0];
|
||||
@@ -2489,7 +2489,7 @@
|
||||
|
||||
Op.prototype.compileModulo = function(o) {
|
||||
var mod;
|
||||
mod = new Value(new Literal(utility('modulo')));
|
||||
mod = new Value(new Literal(utility('modulo', o)));
|
||||
return new Call(mod, [this.first, this.second]).compileToFragments(o);
|
||||
};
|
||||
|
||||
@@ -2555,7 +2555,7 @@
|
||||
In.prototype.compileLoopTest = function(o) {
|
||||
var fragments, ref, sub, _ref2;
|
||||
_ref2 = this.object.cache(o, LEVEL_LIST), sub = _ref2[0], ref = _ref2[1];
|
||||
fragments = [].concat(this.makeCode(utility('indexOf') + ".call("), this.array.compileToFragments(o, LEVEL_LIST), this.makeCode(", "), ref, this.makeCode(") " + (this.negated ? '< 0' : '>= 0')));
|
||||
fragments = [].concat(this.makeCode(utility('indexOf', o) + ".call("), this.array.compileToFragments(o, LEVEL_LIST), this.makeCode(", "), ref, this.makeCode(") " + (this.negated ? '< 0' : '>= 0')));
|
||||
if (fragmentsToText(sub) === fragmentsToText(ref)) {
|
||||
return fragments;
|
||||
}
|
||||
@@ -2839,7 +2839,7 @@
|
||||
if (this.object) {
|
||||
forPartFragments = [this.makeCode(kvar + " in " + svar)];
|
||||
if (this.own) {
|
||||
guardPart = "\n" + idt1 + "if (!" + (utility('hasProp')) + ".call(" + svar + ", " + kvar + ")) continue;";
|
||||
guardPart = "\n" + idt1 + "if (!" + (utility('hasProp', o)) + ".call(" + svar + ", " + kvar + ")) continue;";
|
||||
}
|
||||
}
|
||||
bodyFragments = body.compileToFragments(merge(o, {
|
||||
@@ -3093,8 +3093,8 @@
|
||||
})(Base);
|
||||
|
||||
UTILITIES = {
|
||||
"extends": function() {
|
||||
return "function(child, parent) { for (var key in parent) { if (" + (utility('hasProp')) + ".call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }";
|
||||
"extends": function(o) {
|
||||
return "function(child, parent) { for (var key in parent) { if (" + (utility('hasProp', o)) + ".call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }";
|
||||
},
|
||||
bind: function() {
|
||||
return 'function(fn, me){ return function(){ return fn.apply(me, arguments); }; }';
|
||||
@@ -3143,14 +3143,15 @@
|
||||
|
||||
IS_REGEX = /^\//;
|
||||
|
||||
utility = function(name) {
|
||||
var ref;
|
||||
if (name in Scope.root.utilities) {
|
||||
return Scope.root.utilities[name];
|
||||
utility = function(name, o) {
|
||||
var ref, root;
|
||||
root = o.scope.root;
|
||||
if (name in root.utilities) {
|
||||
return root.utilities[name];
|
||||
} else {
|
||||
ref = Scope.root.freeVariable("_" + name);
|
||||
Scope.root.assign(ref, UTILITIES[name]());
|
||||
return Scope.root.utilities[name] = ref;
|
||||
ref = root.freeVariable("_" + name);
|
||||
root.assign(ref, UTILITIES[name](o));
|
||||
return root.utilities[name] = ref;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -6,9 +6,8 @@
|
||||
_ref = require('./helpers'), extend = _ref.extend, last = _ref.last;
|
||||
|
||||
exports.Scope = Scope = (function() {
|
||||
Scope.root = null;
|
||||
|
||||
function Scope(_at_parent, _at_expressions, _at_method, _at_referencedVars) {
|
||||
var _ref1, _ref2;
|
||||
this.parent = _at_parent;
|
||||
this.expressions = _at_expressions;
|
||||
this.method = _at_method;
|
||||
@@ -22,8 +21,8 @@
|
||||
this.positions = {};
|
||||
if (!this.parent) {
|
||||
this.utilities = {};
|
||||
Scope.root = this;
|
||||
}
|
||||
this.root = (_ref1 = (_ref2 = this.parent) != null ? _ref2.root : void 0) != null ? _ref1 : this;
|
||||
}
|
||||
|
||||
Scope.prototype.add = function(name, type, immediate) {
|
||||
@@ -96,7 +95,7 @@
|
||||
index = 0;
|
||||
while (true) {
|
||||
temp = this.temporary(name, index);
|
||||
if (!(this.check(temp) || __indexOf.call(Scope.root.referencedVars, temp) >= 0)) {
|
||||
if (!(this.check(temp) || __indexOf.call(this.root.referencedVars, temp) >= 0)) {
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
|
||||
@@ -736,7 +736,7 @@ exports.Extends = class Extends extends Base
|
||||
|
||||
# Hooks one constructor into another's prototype chain.
|
||||
compileToFragments: (o) ->
|
||||
new Call(new Value(new Literal utility 'extends'), [@child, @parent]).compileToFragments o
|
||||
new Call(new Value(new Literal utility 'extends', o), [@child, @parent]).compileToFragments o
|
||||
|
||||
#### Access
|
||||
|
||||
@@ -1017,7 +1017,7 @@ exports.Class = class Class extends Base
|
||||
addBoundFunctions: (o) ->
|
||||
for bvar in @boundFuncs
|
||||
lhs = (new Value (new Literal "this"), [new Access bvar]).compile o
|
||||
@ctor.body.unshift new Literal "#{lhs} = #{utility 'bind'}(#{lhs}, this)"
|
||||
@ctor.body.unshift new Literal "#{lhs} = #{utility 'bind', o}(#{lhs}, this)"
|
||||
return
|
||||
|
||||
# Merge the properties from a top-level object as prototypal properties
|
||||
@@ -1231,7 +1231,7 @@ exports.Assign = class Assign extends Base
|
||||
if not expandedIdx and obj instanceof Splat
|
||||
name = obj.name.unwrap().value
|
||||
obj = obj.unwrap()
|
||||
val = "#{olen} <= #{vvarText}.length ? #{ utility 'slice' }.call(#{vvarText}, #{i}"
|
||||
val = "#{olen} <= #{vvarText}.length ? #{ utility 'slice', o }.call(#{vvarText}, #{i}"
|
||||
if rest = olen - i - 1
|
||||
ivar = o.scope.freeVariable 'i'
|
||||
val += ", #{ivar} = #{vvarText}.length - #{rest}) : (#{ivar} = #{i}, [])"
|
||||
@@ -1506,12 +1506,12 @@ exports.Splat = class Splat extends Base
|
||||
node = list[0]
|
||||
fragments = node.compileToFragments o, LEVEL_LIST
|
||||
return fragments if apply
|
||||
return [].concat node.makeCode("#{ utility 'slice' }.call("), fragments, node.makeCode(")")
|
||||
return [].concat node.makeCode("#{ utility 'slice', o }.call("), fragments, node.makeCode(")")
|
||||
args = list[index..]
|
||||
for node, i in args
|
||||
compiledNode = node.compileToFragments o, LEVEL_LIST
|
||||
args[i] = if node instanceof Splat
|
||||
then [].concat node.makeCode("#{ utility 'slice' }.call("), compiledNode, node.makeCode(")")
|
||||
then [].concat node.makeCode("#{ utility 'slice', o }.call("), compiledNode, node.makeCode(")")
|
||||
else [].concat node.makeCode("["), compiledNode, node.makeCode("]")
|
||||
if index is 0
|
||||
node = list[0]
|
||||
@@ -1777,7 +1777,7 @@ exports.Op = class Op extends Base
|
||||
new Call(floor, [div]).compileToFragments o
|
||||
|
||||
compileModulo: (o) ->
|
||||
mod = new Value new Literal utility 'modulo'
|
||||
mod = new Value new Literal utility 'modulo', o
|
||||
new Call(mod, [@first, @second]).compileToFragments o
|
||||
|
||||
toString: (idt) ->
|
||||
@@ -1811,7 +1811,7 @@ exports.In = class In extends Base
|
||||
|
||||
compileLoopTest: (o) ->
|
||||
[sub, ref] = @object.cache o, LEVEL_LIST
|
||||
fragments = [].concat @makeCode(utility('indexOf') + ".call("), @array.compileToFragments(o, LEVEL_LIST),
|
||||
fragments = [].concat @makeCode(utility('indexOf', o) + ".call("), @array.compileToFragments(o, LEVEL_LIST),
|
||||
@makeCode(", "), ref, @makeCode(") " + if @negated then '< 0' else '>= 0')
|
||||
return fragments if fragmentsToText(sub) is fragmentsToText(ref)
|
||||
fragments = sub.concat @makeCode(', '), fragments
|
||||
@@ -2020,7 +2020,7 @@ exports.For = class For extends While
|
||||
varPart = "\n#{idt1}#{namePart};" if namePart
|
||||
if @object
|
||||
forPartFragments = [@makeCode("#{kvar} in #{svar}")]
|
||||
guardPart = "\n#{idt1}if (!#{utility 'hasProp'}.call(#{svar}, #{kvar})) continue;" if @own
|
||||
guardPart = "\n#{idt1}if (!#{utility 'hasProp', o}.call(#{svar}, #{kvar})) continue;" if @own
|
||||
bodyFragments = body.compileToFragments merge(o, indent: idt1), LEVEL_TOP
|
||||
if bodyFragments and (bodyFragments.length > 0)
|
||||
bodyFragments = [].concat @makeCode("\n"), bodyFragments, @makeCode("\n")
|
||||
@@ -2179,10 +2179,10 @@ UTILITIES =
|
||||
|
||||
# Correctly set up a prototype chain for inheritance, including a reference
|
||||
# to the superclass for `super()` calls, and copies of any static properties.
|
||||
extends: -> "
|
||||
extends: (o) -> "
|
||||
function(child, parent) {
|
||||
for (var key in parent) {
|
||||
if (#{utility 'hasProp'}.call(parent, key)) child[key] = parent[key];
|
||||
if (#{utility 'hasProp', o}.call(parent, key)) child[key] = parent[key];
|
||||
}
|
||||
function ctor() {
|
||||
this.constructor = child;
|
||||
@@ -2259,13 +2259,14 @@ IS_REGEX = /^\//
|
||||
# ----------------
|
||||
|
||||
# Helper for ensuring that utility functions are assigned at the top level.
|
||||
utility = (name) ->
|
||||
if name of Scope.root.utilities
|
||||
Scope.root.utilities[name]
|
||||
utility = (name, o) ->
|
||||
{root} = o.scope
|
||||
if name of root.utilities
|
||||
root.utilities[name]
|
||||
else
|
||||
ref = Scope.root.freeVariable "_#{name}"
|
||||
Scope.root.assign ref, UTILITIES[name]()
|
||||
Scope.root.utilities[name] = ref
|
||||
ref = root.freeVariable "_#{name}"
|
||||
root.assign ref, UTILITIES[name] o
|
||||
root.utilities[name] = ref
|
||||
|
||||
multident = (code, tab) ->
|
||||
code = code.replace /\n/g, '$&' + tab
|
||||
|
||||
@@ -11,10 +11,6 @@ Import the helpers we plan to use.
|
||||
|
||||
exports.Scope = class Scope
|
||||
|
||||
The `root` is the top-level **Scope** object for a given file.
|
||||
|
||||
@root: null
|
||||
|
||||
Initialize a scope with its parent, for lookups up the chain,
|
||||
as well as a reference to the **Block** node it belongs to, which is
|
||||
where it should declare its variables, a reference to the function that
|
||||
@@ -24,9 +20,11 @@ and therefore should be avoided when generating variables.
|
||||
constructor: (@parent, @expressions, @method, @referencedVars) ->
|
||||
@variables = [{name: 'arguments', type: 'arguments'}]
|
||||
@positions = {}
|
||||
unless @parent
|
||||
@utilities = {}
|
||||
Scope.root = this
|
||||
@utilities = {} unless @parent
|
||||
|
||||
The `@root` is the top-level **Scope** object for a given file.
|
||||
|
||||
@root = @parent?.root ? this
|
||||
|
||||
Adds a new variable or overrides an existing one.
|
||||
|
||||
@@ -89,7 +87,7 @@ compiler-generated variable. `_var`, `_var2`, and so on...
|
||||
index = 0
|
||||
loop
|
||||
temp = @temporary name, index
|
||||
break unless @check(temp) or temp in Scope.root.referencedVars
|
||||
break unless @check(temp) or temp in @root.referencedVars
|
||||
index++
|
||||
@add temp, 'var', yes if reserve
|
||||
temp
|
||||
|
||||
Reference in New Issue
Block a user