text: // Generated by CoffeeScript 2.0.0-beta8-dev
  var ArrayInterface, ArrayType, checkAcceptableObject, clone, console, CS, initializeGlobalTypes, NumberInterface, ObjectInterface, ObjectType, pj, Possibilites, render, rewrite, Scope, Type, TypeSymbol, util, VarSymbol;
  console = {
    log: function () {
    }
  };
  pj = function () {
    try {
      return require('prettyjson');
    } catch (e$) {
      return;
    }
  }.call(this);
  render = function (obj) {
    if (null != pj)
      return pj.render(obj);
  };
  CS = require('./nodes');
  util = require('util');
  clone = function (obj) {
    var flags, key, newInstance;
    if (!(null != obj) || typeof obj !== 'object')
      return obj;
    if (obj instanceof Date)
      return new Date(obj.getTime());
    if (obj instanceof RegExp) {
      flags = '';
      if (null != obj.global)
        flags += 'g';
      if (null != obj.ignoreCase)
        flags += 'i';
      if (null != obj.multiline)
        flags += 'm';
      if (null != obj.sticky)
        flags += 'y';
      return new RegExp(obj.source, flags);
    }
    newInstance = new obj.constructor;
    for (key in obj) {
      newInstance[key] = clone(obj[key]);
    }
    return newInstance;
  };
  rewrite = function (obj, templates) {
    if (typeof obj === 'string' || typeof obj === 'number')
      return;
    return function (accum$) {
      var key, val;
      for (key in obj) {
        val = obj[key];
        accum$.push(typeof val === 'string' ? in$(val, templates) ? obj[key] = 'Any' : void 0 : val instanceof Object ? rewrite(val, templates) : void 0);
      }
      return accum$;
    }.call(this, []);
  };
  NumberInterface = function () {
    return {
      toString: {
        name: 'function',
        args: [],
        returns: 'String'
      }
    };
  };
  ArrayInterface = function (T) {
    if (null == T)
      T = 'Any';
    return {
      length: 'Number',
      push: {
        name: 'function',
        args: [T],
        returns: 'void'
      },
      unshift: {
        name: 'function',
        args: [T],
        returns: 'void'
      },
      shift: {
        name: 'function',
        args: [],
        returns: T
      },
      toString: {
        name: 'function',
        args: [],
        returns: 'String'
      }
    };
  };
  ObjectInterface = function () {
    return {
      toString: {
        name: 'function',
        args: [],
        returns: 'String'
      },
      keys: {
        name: 'function',
        args: ['Any'],
        returns: { array: 'String' }
      }
    };
  };
  Type = function () {
    function Type() {
    }
    return Type;
  }();
  ObjectType = function (super$) {
    extends$(ObjectType, super$);
    function ObjectType(param$) {
      this.type = param$;
    }
    return ObjectType;
  }(Type);
  ArrayType = function (super$) {
    extends$(ArrayType, super$);
    function ArrayType(type) {
      this.array = type;
    }
    return ArrayType;
  }(Type);
  Possibilites = function (super$) {
    extends$(Possibilites, super$);
    function Possibilites(arr) {
      var i;
      if (null == arr)
        arr = [];
      for (var i$ = 0, length$ = arr.length; i$ < length$; ++i$) {
        i = arr[i$];
        this.push(i);
      }
    }
    return Possibilites;
  }(Array);
  checkAcceptableObject = function (left, right) {
    var r;
    console.log('check', left, right);
    if (null != (null != right ? right.possibilities : void 0)) {
      console.log('--right---', right);
      for (var i$ = 0, length$ = right.possibilities.length; i$ < length$; ++i$) {
        r = right.possibilities[i$];
        checkAcceptableObject(left, r);
      }
      return;
    }
    if (left === 'Any')
      return;
    if (null != (null != left ? left.array : void 0)) {
      if (right.array instanceof Array) {
        return function (accum$) {
          for (var i$1 = 0, length$1 = right.array.length; i$1 < length$1; ++i$1) {
            r = right.array[i$1];
            accum$.push(checkAcceptableObject(left.array, r));
          }
          return accum$;
        }.call(this, []);
      } else {
        return checkAcceptableObject(left.array, right.array);
      }
    } else if (null != (null != right ? right.array : void 0)) {
      if (left === 'Array' || left === 'Any' || left === void 0) {
        return 'ok';
      } else {
        throw new Error('object deep equal mismatch ' + JSON.stringify(left) + ', ' + JSON.stringify(right));
      }
    } else if (typeof left === 'string' && typeof right === 'string') {
      if (left === right || left === 'Any' || right === 'Any') {
        return 'ok';
      } else {
        throw new Error('object deep equal mismatch ' + JSON.stringify(left) + ', ' + JSON.stringify(right));
      }
    } else if (typeof left === 'object' && typeof right === 'object') {
      return function (accum$) {
        var key, lval;
        for (key in left) {
          lval = left[key];
          if (right[key] === void 0) {
            if (key === 'returns' || key === 'type')
              return;
            throw new Error("'" + key + "' is not defined on right");
          }
          accum$.push(checkAcceptableObject(lval, right[key]));
        }
        return accum$;
      }.call(this, []);
    } else if (left === void 0 || right === void 0) {
      return 'ignore now';
    } else {
      throw new Error('object deep equal mismatch ' + JSON.stringify(left) + ', ' + JSON.stringify(right));
    }
  };
  initializeGlobalTypes = function (node) {
    node.addTypeObject('String', new TypeSymbol({
      type: 'String',
      'instanceof': function (expr) {
        return typeof expr.data === 'string';
      }
    }));
    node.addTypeObject('Number', new TypeSymbol({
      type: 'Number',
      'instanceof': function (expr) {
        return typeof expr.data === 'number';
      }
    }));
    node.addTypeObject('Boolean', new TypeSymbol({
      type: 'Boolean',
      'instanceof': function (expr) {
        return typeof expr.data === 'boolean';
      }
    }));
    node.addTypeObject('Object', new TypeSymbol({
      type: 'Object',
      'instanceof': function (expr) {
        return typeof expr.data === 'object';
      }
    }));
    node.addTypeObject('Array', new TypeSymbol({
      type: 'Array',
      'instanceof': function (expr) {
        return typeof expr.data === 'object';
      }
    }));
    node.addTypeObject('Undefined', new TypeSymbol({ type: 'Undefined' }));
    return node.addTypeObject('Any', new TypeSymbol({
      type: 'Any',
      'instanceof': function (expr) {
        return true;
      }
    }));
  };
  VarSymbol = function () {
    function VarSymbol(param$) {
      var cache$;
      {
        cache$ = param$;
        this.type = cache$.type;
        this.implicit = cache$.implicit;
      }
    }
    return VarSymbol;
  }();
  TypeSymbol = function () {
    function TypeSymbol(param$) {
      var cache$;
      {
        cache$ = param$;
        this.type = cache$.type;
        this['instanceof'] = cache$['instanceof'];
        this.templates = cache$.templates;
      }
      if (null != this['instanceof'])
        this['instanceof'];
      else
        this['instanceof'] = function (t) {
          return t instanceof this.constructor;
        };
    }
    return TypeSymbol;
  }();
  Scope = function () {
    Scope.dump = function (node, prefix) {
      var key, val;
      if (null == prefix)
        prefix = '';
      console.log(prefix + ('[' + node.name + ']'));
      for (key in node._vars) {
        val = node._vars[key];
        console.log(prefix, ' +', key, '::', val);
      }
      return function (accum$) {
        var next;
        for (var i$ = 0, length$ = node.nodes.length; i$ < length$; ++i$) {
          next = node.nodes[i$];
          accum$.push(Scope.dump(next, prefix + '  '));
        }
        return accum$;
      }.call(this, []);
    };
    function Scope(param$) {
      if (null == param$)
        param$ = null;
      this.parent = param$;
      if (null != this.parent)
        this.parent.nodes.push(this);
      this.name = '';
      this.nodes = [];
      this._vars = {};
      this._types = {};
      this._this = {};
      this._returnables = [];
    }
    Scope.prototype.addReturnable = function (symbol, type) {
      return this._returnables.push(type);
    };
    Scope.prototype.getReturnables = function () {
      return this._returnables;
    };
    Scope.prototype.addType = function (symbol, type, templates) {
      return this._types[symbol] = new TypeSymbol({
        type: type,
        templates: templates
      });
    };
    Scope.prototype.addTypeObject = function (symbol, type_object) {
      return this._types[symbol] = type_object;
    };
    Scope.prototype.getType = function (symbol) {
      return (null != this._types[symbol] ? this._types[symbol].type : void 0) || void 0;
    };
    Scope.prototype.getTypeInScope = function (symbol) {
      return this.getType(symbol) || (null != this.parent ? this.parent.getTypeInScope(symbol) : void 0) || void 0;
    };
    Scope.prototype.addThis = function (symbol, type, implicit) {
      if (null == implicit)
        implicit = true;
      return this._this[symbol] = {
        type: type,
        implicit: implicit
      };
    };
    Scope.prototype.getThis = function (symbol) {
      return null != (null != this._this[symbol] ? this._this[symbol].type : void 0) ? null != this._this[symbol] ? this._this[symbol].type : void 0 : void 0;
    };
    Scope.prototype.addVar = function (symbol, type, implicit) {
      var obj, T;
      if (null == implicit)
        implicit = true;
      if (null != (null != type ? type.base : void 0)) {
        T = this.getType(type.base);
        if (!(null != T ? T.type : void 0))
          return;
        obj = clone(T.type);
        if (T.templates)
          rewrite(obj, T.templates);
        return this._vars[symbol] = new VarSymbol({
          type: obj,
          implicit: implicit
        });
      } else {
        return this._vars[symbol] = new VarSymbol({
          type: type,
          implicit: implicit
        });
      }
    };
    Scope.prototype.getVar = function (symbol) {
      return null != (null != this._vars[symbol] ? this._vars[symbol].type : void 0) ? null != this._vars[symbol] ? this._vars[symbol].type : void 0 : void 0;
    };
    Scope.prototype.getVarInScope = function (symbol) {
      return this.getVar(symbol) || (null != this.parent ? this.parent.getVarInScope(symbol) : void 0) || void 0;
    };
    Scope.prototype.isImplicitVar = function (symbol) {
      return !!(null != this._vars[symbol] ? this._vars[symbol].implicit : void 0);
    };
    Scope.prototype.isImplicitVarInScope = function (symbol) {
      return this.isImplicitVar(symbol) || (null != this.parent ? this.parent.isImplicitVarInScope(symbol) : void 0) || void 0;
    };
    Scope.prototype.extendTypeLiteral = function (node) {
      var key, ret, type, val;
      switch (typeof node) {
      case 'object':
        if (node instanceof Array) {
          return function (accum$) {
            var i;
            for (var i$ = 0, length$ = node.length; i$ < length$; ++i$) {
              i = node[i$];
              accum$.push(this.extendTypeLiteral(i));
            }
            return accum$;
          }.call(this, []);
        } else {
          ret = {};
          for (key in node) {
            val = node[key];
            ret[key] = this.extendTypeLiteral(val);
          }
          return ret;
        }
      case 'string':
        type = this.getTypeInScope(node);
        switch (typeof type) {
        case 'object':
          return this.extendTypeLiteral(type);
        case 'string':
          return type;
        }
      }
    };
    Scope.prototype.checkAcceptableObject = function (left, right) {
      var l, r;
      l = this.extendTypeLiteral(left);
      r = this.extendTypeLiteral(right);
      return checkAcceptableObject(l, r);
    };
    Scope.prototype.checkFunctionLiteral = function (left, right) {
      var i, l_arg, r_arg;
      console.log('checkFunctionLiteral', left, right);
      left = this.extendTypeLiteral(left);
      right = this.extendTypeLiteral(right);
      if (left === void 0 || left === 'Any')
        return;
      if (null != left.args)
        left.args;
      else
        left.args = [];
      console.log(left);
      if ((null != left ? left.args : void 0) === void 0)
        throw new Error('left is not arguments: ' + JSON.stringify(left) + ', ' + JSON.stringify(right));
      for (var i$ = 0, length$ = left.args.length; i$ < length$; ++i$) {
        l_arg = left.args[i$];
        i = i$;
        r_arg = right.args[i];
        checkAcceptableObject(l_arg, r_arg);
      }
      if (right.returns !== 'Any')
        return checkAcceptableObject(left.returns, right.returns);
    };
    return Scope;
  }();
  module.exports = {
    checkAcceptableObject: checkAcceptableObject,
    initializeGlobalTypes: initializeGlobalTypes,
    VarSymbol: VarSymbol,
    TypeSymbol: TypeSymbol,
    Scope: Scope,
    ArrayType: ArrayType,
    ObjectType: ObjectType,
    Type: Type,
    Possibilites: Possibilites
  };
  function in$(member, list) {
    for (var i = 0, length = list.length; i < length; ++i)
      if (i in list && list[i] === member)
        return true;
    return false;
  }
  function isOwn$(o, p) {
    return {}.hasOwnProperty.call(o, p);
  }
  function extends$(child, parent) {
    for (var key in parent)
      if (isOwn$(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;
  }
  