text: //
  /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
   * Use of this file is governed by the BSD 3-clause license that
   * can be found in the LICENSE.txt file in the project root.
   */
  ///
  
  // A tuple: (ATN state, predicted alt, syntactic, semantic context).
  //  The syntactic context is a graph-structured stack node whose
  //  path(s) to the root is the rule invocation(s)
  //  chain used to arrive at the state.  The semantic context is
  //  the tree of semantic predicates encountered before reaching
  //  an ATN state.
  ///
  
  var DecisionState = require('./ATNState').DecisionState;
  var SemanticContext = require('./SemanticContext').SemanticContext;
  var Hash = require("../Utils").Hash;
  
  
  function checkParams(params, isCfg) {
  	if(params===null) {
  		var result = { state:null, alt:null, context:null, semanticContext:null };
  		if(isCfg) {
  			result.reachesIntoOuterContext = 0;
  		}
  		return result;
  	} else {
  		var props = {};
  		props.state = params.state || null;
  		props.alt = (params.alt === undefined) ? null : params.alt;
  		props.context = params.context || null;
  		props.semanticContext = params.semanticContext || null;
  		if(isCfg) {
  			props.reachesIntoOuterContext = params.reachesIntoOuterContext || 0;
  			props.precedenceFilterSuppressed = params.precedenceFilterSuppressed || false;
  		}
  		return props;
  	}
  }
  
  function ATNConfig(params, config) {
  	this.checkContext(params, config);
  	params = checkParams(params);
  	config = checkParams(config, true);
      // The ATN state associated with this configuration///
      this.state = params.state!==null ? params.state : config.state;
      // What alt (or lexer rule) is predicted by this configuration///
      this.alt = params.alt!==null ? params.alt : config.alt;
      // The stack of invoking states leading to the rule/states associated
      //  with this config.  We track only those contexts pushed during
      //  execution of the ATN simulator.
      this.context = params.context!==null ? params.context : config.context;
      this.semanticContext = params.semanticContext!==null ? params.semanticContext :
          (config.semanticContext!==null ? config.semanticContext : SemanticContext.NONE);
      // We cannot execute predicates dependent upon local context unless
      // we know for sure we are in the correct context. Because there is
      // no way to do this efficiently, we simply cannot evaluate
      // dependent predicates unless we are in the rule that initially
      // invokes the ATN simulator.
      //
      // closure() tracks the depth of how far we dip into the
      // outer context: depth &gt; 0.  Note that it may not be totally
      // accurate depth since I don't ever decrement. TODO: make it a boolean then
      this.reachesIntoOuterContext = config.reachesIntoOuterContext;
      this.precedenceFilterSuppressed = config.precedenceFilterSuppressed;
      return this;
  }
  
  ATNConfig.prototype.checkContext = function(params, config) {
  	if((params.context===null || params.context===undefined) &&
  			(config===null || config.context===null || config.context===undefined)) {
  		this.context = null;
  	}
  };
  
  
  ATNConfig.prototype.hashCode = function() {
      var hash = new Hash();
      this.updateHashCode(hash);
      return hash.finish();
  };
  
  
  ATNConfig.prototype.updateHashCode = function(hash) {
      hash.update(this.state.stateNumber, this.alt, this.context, this.semanticContext);
  };
  
  // An ATN configuration is equal to another if both have
  //  the same state, they predict the same alternative, and
  //  syntactic/semantic contexts are the same.
  
  ATNConfig.prototype.equals = function(other) {
      if (this === other) {
          return true;
      } else if (! (other instanceof ATNConfig)) {
          return false;
      } else {
          return this.state.stateNumber===other.state.stateNumber &&
              this.alt===other.alt &&
              (this.context===null ? other.context===null : this.context.equals(other.context)) &&
              this.semanticContext.equals(other.semanticContext) &&
              this.precedenceFilterSuppressed===other.precedenceFilterSuppressed;
      }
  };
  
  
  ATNConfig.prototype.hashCodeForConfigSet = function() {
      var hash = new Hash();
      hash.update(this.state.stateNumber, this.alt, this.semanticContext);
      return hash.finish();
  };
  
  
  ATNConfig.prototype.equalsForConfigSet = function(other) {
      if (this === other) {
          return true;
      } else if (! (other instanceof ATNConfig)) {
          return false;
      } else {
          return this.state.stateNumber===other.state.stateNumber &&
              this.alt===other.alt &&
              this.semanticContext.equals(other.semanticContext);
      }
  };
  
  
  ATNConfig.prototype.toString = function() {
      return "(" + this.state + "," + this.alt +
          (this.context!==null ? ",[" + this.context.toString() + "]" : "") +
          (this.semanticContext !== SemanticContext.NONE ?
                  ("," + this.semanticContext.toString())
                  : "") +
          (this.reachesIntoOuterContext>0 ?
                  (",up=" + this.reachesIntoOuterContext)
                  : "") + ")";
  };
  
  
  function LexerATNConfig(params, config) {
  	ATNConfig.call(this, params, config);
  
      // This is the backing field for {@link //getLexerActionExecutor}.
  	var lexerActionExecutor = params.lexerActionExecutor || null;
      this.lexerActionExecutor = lexerActionExecutor || (config!==null ? config.lexerActionExecutor : null);
      this.passedThroughNonGreedyDecision = config!==null ? this.checkNonGreedyDecision(config, this.state) : false;
      return this;
  }
  
  LexerATNConfig.prototype = Object.create(ATNConfig.prototype);
  LexerATNConfig.prototype.constructor = LexerATNConfig;
  
  LexerATNConfig.prototype.updateHashCode = function(hash) {
      hash.update(this.state.stateNumber, this.alt, this.context, this.semanticContext, this.passedThroughNonGreedyDecision, this.lexerActionExecutor);
  };
  
  LexerATNConfig.prototype.equals = function(other) {
      return this === other ||
              (other instanceof LexerATNConfig &&
              this.passedThroughNonGreedyDecision == other.passedThroughNonGreedyDecision &&
              (this.lexerActionExecutor ? this.lexerActionExecutor.equals(other.lexerActionExecutor) : !other.lexerActionExecutor) &&
              ATNConfig.prototype.equals.call(this, other));
  };
  
  LexerATNConfig.prototype.hashCodeForConfigSet = LexerATNConfig.prototype.hashCode;
  
  LexerATNConfig.prototype.equalsForConfigSet = LexerATNConfig.prototype.equals;
  
  
  LexerATNConfig.prototype.checkNonGreedyDecision = function(source, target) {
      return source.passedThroughNonGreedyDecision ||
          (target instanceof DecisionState) && target.nonGreedy;
  };
  
  exports.ATNConfig = ATNConfig;
  exports.LexerATNConfig = LexerATNConfig;