getEpsilonTarget method

LexerATNConfig? getEpsilonTarget(
  1. CharStream input,
  2. LexerATNConfig config,
  3. Transition t,
  4. ATNConfigSet configs,
  5. bool speculative,
  6. bool treatEofAsEpsilon,
)

Implementation

LexerATNConfig? getEpsilonTarget(
  CharStream input,
  LexerATNConfig config,
  Transition t,
  ATNConfigSet configs,
  bool speculative,
  bool treatEofAsEpsilon,
) {
  LexerATNConfig? c;
  switch (t.type) {
    case TransitionType.RULE:
      final ruleTransition = t as RuleTransition;
      PredictionContext newContext = SingletonPredictionContext.create(
        config.context!,
        ruleTransition.followState.stateNumber,
      );
      c = LexerATNConfig.dup(config, t.target, context: newContext);
      break;

    case TransitionType.PRECEDENCE:
      throw UnsupportedError(
          'Precedence predicates are not supported in lexers.');
    case TransitionType.PREDICATE:
      /*  Track traversing semantic predicates. If we traverse,
				 we cannot add a DFA state for this "reach" computation
				 because the DFA would not test the predicate again in the
				 future. Rather than creating collections of semantic predicates
				 like v3 and testing them on prediction, v4 will test them on the
				 fly all the time using the ATN not the DFA. This is slower but
				 semantically it's not used that often. One of the key elements to
				 this predicate mechanism is not adding DFA states that see
				 predicates immediately afterwards in the ATN. For example,

				 a : ID {p1}? | ID {p2}? ;

				 should create the start state for rule 'a' (to save start state
				 competition), but should not create target of ID state. The
				 collection of ATN states the following ID references includes
				 states reached by traversing predicates. Since this is when we
				 test them, we cannot cash the DFA state target of ID.
			 */
      final pt = t as PredicateTransition;
      if (debug) {
        log('EVAL rule ${pt.ruleIndex}:${pt.predIndex}',
            level: Level.FINE.value);
      }
      configs.hasSemanticContext = true;
      if (evaluatePredicate(input, pt.ruleIndex, pt.predIndex, speculative)) {
        c = LexerATNConfig.dup(config, t.target);
      }
      break;
    case TransitionType.ACTION:
      if (config.context == null || config.context!.hasEmptyPath()) {
        // execute actions anywhere in the start rule for a token.
        //
        // TODO: if the entry rule is invoked recursively, some
        // actions may be executed during the recursive call. The
        // problem can appear when hasEmptyPath() is true but
        // isEmpty is false. In this case, the config needs to be
        // split into two contexts - one with just the empty path
        // and another with everything but the empty path.
        // Unfortunately, the current algorithm does not allow
        // getEpsilonTarget to return two configurations, so
        // additional modifications are needed before we can support
        // the split operation.
        final lexerActionExecutor = LexerActionExecutor.append(
          config.lexerActionExecutor,
          atn.lexerActions![(t as ActionTransition).actionIndex],
        );
        c = LexerATNConfig.dup(config, t.target,
            lexerActionExecutor: lexerActionExecutor);
      } else {
        // ignore actions in referenced rules
        c = LexerATNConfig.dup(config, t.target);
      }
      break;

    case TransitionType.EPSILON:
      c = LexerATNConfig.dup(config, t.target);
      break;

    case TransitionType.ATOM:
    case TransitionType.RANGE:
    case TransitionType.SET:
      if (treatEofAsEpsilon) {
        if (t.matches(
            IntStream.EOF, Lexer.MIN_CHAR_VALUE, Lexer.MAX_CHAR_VALUE)) {
          c = LexerATNConfig.dup(config, t.target);
          break;
        }
      }
      break;
    case TransitionType.NOT_SET:
      break;
    case TransitionType.WILDCARD:
      break;
    case TransitionType.INVALID:
      throw ArgumentError.value(t.type, 'TransitionType');
  }

  return c;
}