function Computable (scope, input_computables, output_type) {
  this.setMaxListeners(0);
  if (!scope || !scope.emit) {
    throw new Error("It is illegal to have an unscoped Computable");
  }
  if (!(output_type instanceof IRType)) {
    throw new Error("Must pass in an IRType output type");
  }

  this._identity = ''+current_unique_id;
  current_unique_id++;

  this._output_type = output_type;
  this._inputs = [];
  this._dependees = [];
  this._scope = scope;

  var _this = this;

  // TODO: this needs to be updated when dependee's inputs are removed
  function find_dependee (computable) {
    var dependee_entry;
    for (var i = 0; i !== _this._dependees.length; ++i) {
      var current_entry = _this._dependees[i];
      if (current_entry.computable === computable) {
        dependee_entry = current_entry;
        break;
      }
    }

    return { entry: dependee_entry, index: i };
  }

  // TODO: come up with a better way to handle all these cases than to use the event emitter pattern, just feels awkward.
  this.on('dependee_added', function (computable, input_index) {
    var dependee_result = find_dependee(computable);
    var dependee_entry = dependee_result.entry;
    if (dependee_entry) {
      dependee_entry.indexes.push(input_index);
    } else {
      dependee_entry = {
        computable: computable,
        indexes: [input_index],
        destroy_listener: function () {
          var dependee_result = find_dependee(computable);
          _this._dependees.splice(dependee_result.index, 1);
        },
        cleanup: function () {
          computable.removeListener('destroyed', dependee_entry.destroy_listener);
        }
      };

      _this._dependees.push(dependee_entry);
      computable.once('destroyed', dependee_entry.destroy_listener);
    }
  });

  this.on('dependee_removed', function (computable, input_index) {
    var dependee_result = find_dependee(computable);

    var dependee_entry = dependee_result.entry;

    var indexes = dependee_entry.indexes;
    var input_indexes_entry_index = indexes.indexOf(input_index);
    if (input_indexes_entry_index !== -1) {
      indexes.splice(input_indexes_entry_index, 1);
    }
    if (!indexes.length) {
      _this._dependees.splice(dependee_result.index, 1);
      dependee_entry.cleanup();
    }
  });

  for (var i = 0; i < input_computables.length; i++) {
    var input_computable = input_computables[i];
    this.set_input(i, input_computable);
  }

  scope.emit('computable_added', this);
}
/**
 * Abstract base for all Computable implementations.
 * @constructor
 * @extends EventEmitter
 * @emits Scope#computable_added
 * @param {Scope} scope The scope this computable is associated with.
 * @param {Array.<Computable>} input_computables The Computables to bind the inputs to.
 * @param {IRType} output_type The output type specification.
 */
Abstract base for all Computable implementations.
@constructor
@extends EventEmitter
@emits Scope#computable_added
@param {Scope} scope The scope this computable is associated with.
@param {Array.} input_computables The Computables to bind the inputs to.
@param {IRType} output_type The output type specification.
Abstract base for all Computable implementations . @constructor @extends EventEmitter @emits Scope#computable_added @param { Scope } scope The scope this computable is associated with . @param { Array . } input_computables The Computables to bind the inputs to . @param { IRType } output_type The output type specification .
function Computable (scope, input_computables, output_type) {
  this.setMaxListeners(0);
  if (!scope || !scope.emit) {
    throw new Error("It is illegal to have an unscoped Computable");
  }
  if (!(output_type instanceof IRType)) {
    throw new Error("Must pass in an IRType output type");
  }
  this._identity = ''+current_unique_id;
  current_unique_id++;
  this._output_type = output_type;
  this._inputs = [];
  this._dependees = [];
  this._scope = scope;
  var _this = this;
  function find_dependee (computable) {
    var dependee_entry;
    for (var i = 0; i !== _this._dependees.length; ++i) {
      var current_entry = _this._dependees[i];
      if (current_entry.computable === computable) {
        dependee_entry = current_entry;
        break;
      }
    }
    return { entry: dependee_entry, index: i };
  }
  this.on('dependee_added', function (computable, input_index) {
    var dependee_result = find_dependee(computable);
    var dependee_entry = dependee_result.entry;
    if (dependee_entry) {
      dependee_entry.indexes.push(input_index);
    } else {
      dependee_entry = {
        computable: computable,
        indexes: [input_index],
        destroy_listener: function () {
          var dependee_result = find_dependee(computable);
          _this._dependees.splice(dependee_result.index, 1);
        },
        cleanup: function () {
          computable.removeListener('destroyed', dependee_entry.destroy_listener);
        }
      };
      _this._dependees.push(dependee_entry);
      computable.once('destroyed', dependee_entry.destroy_listener);
    }
  });
  this.on('dependee_removed', function (computable, input_index) {
    var dependee_result = find_dependee(computable);
    var dependee_entry = dependee_result.entry;
    var indexes = dependee_entry.indexes;
    var input_indexes_entry_index = indexes.indexOf(input_index);
    if (input_indexes_entry_index !== -1) {
      indexes.splice(input_indexes_entry_index, 1);
    }
    if (!indexes.length) {
      _this._dependees.splice(dependee_result.index, 1);
      dependee_entry.cleanup();
    }
  });
  for (var i = 0; i < input_computables.length; i++) {
    var input_computable = input_computables[i];
    this.set_input(i, input_computable);
  }
  scope.emit('computable_added', this);
}
function Computable ( scope , input_computables , output_type ) { this . setMaxListeners ( 0 ) ; if ( ! scope || ! scope . emit ) { throw new Error ( "It is illegal to have an unscoped Computable" ) ; } if ( ! ( output_type instanceof IRType ) ) { throw new Error ( "Must pass in an IRType output type" ) ; } this . _identity = '' + current_unique_id ; current_unique_id ++ ; this . _output_type = output_type ; this . _inputs = [ ] ; this . _dependees = [ ] ; this . _scope = scope ; var _this = this ; function find_dependee ( computable ) { var dependee_entry ; for ( var i = 0 ; i !== _this . _dependees . length ; ++ i ) { var current_entry = _this . _dependees [ i ] ; if ( current_entry . computable === computable ) { dependee_entry = current_entry ; break ; } } return { entry : dependee_entry , index : i } ; } this . on ( 'dependee_added' , function ( computable , input_index ) { var dependee_result = find_dependee ( computable ) ; var dependee_entry = dependee_result . entry ; if ( dependee_entry ) { dependee_entry . indexes . push ( input_index ) ; } else { dependee_entry = { computable : computable , indexes : [ input_index ] , destroy_listener : function ( ) { var dependee_result = find_dependee ( computable ) ; _this . _dependees . splice ( dependee_result . index , 1 ) ; } , cleanup : function ( ) { computable . removeListener ( 'destroyed' , dependee_entry . destroy_listener ) ; } } ; _this . _dependees . push ( dependee_entry ) ; computable . once ( 'destroyed' , dependee_entry . destroy_listener ) ; } } ) ; this . on ( 'dependee_removed' , function ( computable , input_index ) { var dependee_result = find_dependee ( computable ) ; var dependee_entry = dependee_result . entry ; var indexes = dependee_entry . indexes ; var input_indexes_entry_index = indexes . indexOf ( input_index ) ; if ( input_indexes_entry_index !== - 1 ) { indexes . splice ( input_indexes_entry_index , 1 ) ; } if ( ! indexes . length ) { _this . _dependees . splice ( dependee_result . index , 1 ) ; dependee_entry . cleanup ( ) ; } } ) ; for ( var i = 0 ; i < input_computables . length ; i ++ ) { var input_computable = input_computables [ i ] ; this . set_input ( i , input_computable ) ; } scope . emit ( 'computable_added' , this ) ; }
Abstract base for all Computable implementations.
Abstract base for all Computable implementations .
// TODO: this needs to be updated when dependee's inputs are removed // TODO: come up with a better way to handle all these cases than to use the event emitter pattern, just feels awkward.