// Heavily inspired by coffee-script again

exports.Scope = function (parent) {
    var self = this;

    if (parent) {
        self.root = null;
    } else {
        self.root = self;
    }

    self.parent = parent;

    // where we keep the variables names for this scope
    self.variables = {};

    // add a variable to the scope
    self.add = function (name) {
        if (self.variables[name]) {
            throw "Variable " + name + " already defined";
        } else {
            self.variables[name] = true;
        }
    }

    // check the existence of a variable in this scope or any parent
    self.check = function (name) {
        return !!self.variables[name] || self.parent.check(name);
    }

    // generate a temporary variable name
    self.temporary = function (name, index) {
        return '_' + name + index;
    }

    // create a temporary variable with an available name
    self.addTempVar = function (name, reserve) {
        var index = 0,
            newName = self.temporary(name, index);

        while (self.check(newName)) {
            index++;
            newName = self.temporary(name, index);
        }

        if (reserve) {
            self.add(newName);
        }

        return newName;
    }
}

// Heavily inspired by coffee-script again
(function() {
    var Scope;

    exports.Scope = Scope = (function () {
        Scope.root = null;

        function Scope(parent) {
            this.parent = parent;

            if (!this.parent) {
                Scope.root = this;
            }

            // where we keep the variables names for this scope
            this.variables = {};
        };

        // add a variable to the scope
        Scope.prototype.add = function (name) {
            if (this.variables[name]) {
                throw "Variable " + name + " already defined";
            } else {
                this.variables[name] = true;
            }
        };

        // check the existence of a variable in this scope or any parent
        Scope.prototype.check = function (name) {
            return !!this.variables[name] || this.parent.check(name);
        };

        // generate a temporary variable name
        Scope.prototype.temporary = function (name, index) {
            return '_' + name + index;
        };

        // create a temporary variable with an available name
        Scope.prototype.addTempVar = function (name, reserve) {
            var index = 0,
                newName = this.temporary(name, index);

            while (this.check(newName)) {
                index++;
                newName = this.temporary(name, index);
            }

            if (reserve) {
                this.add(newName);
            }

            return newName;
        };

        return Scope;
    })();

}).call(this);


Rewrite Scope with prototypal notation
Rewrite Scope with prototypal notation
