protected internal virtual ATNConfig GetEpsilonTarget(ICharStream input, ATNConfig config, Transition t, ATNConfigSet configs, bool speculative, bool treatEofAsEpsilon)
{
ATNConfig c;
switch (t.TransitionType)
{
case TransitionType.Rule:
{
RuleTransition ruleTransition = (RuleTransition)t;
if (optimize_tail_calls && ruleTransition.optimizedTailCall && !config.Context.HasEmpty)
{
c = config.Transform(t.target, true);
}
else
{
PredictionContext newContext = config.Context.GetChild(ruleTransition.followState.stateNumber);
c = config.Transform(t.target, newContext, true);
}
break;
}
case TransitionType.Precedence:
{
throw new NotSupportedException("Precedence predicates are not supported in lexers.");
}
case TransitionType.Predicate:
{
PredicateTransition pt = (PredicateTransition)t;
configs.MarkExplicitSemanticContext();
if (EvaluatePredicate(input, pt.ruleIndex, pt.predIndex, speculative))
{
c = config.Transform(t.target, true);
}
else
{
c = null;
}
break;
}
case TransitionType.Action:
{
if (config.Context.HasEmpty)
{
// 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 hasEmpty() 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.
LexerActionExecutor lexerActionExecutor = LexerActionExecutor.Append(config.ActionExecutor, atn.lexerActions[((ActionTransition)t).actionIndex]);
c = config.Transform(t.target, lexerActionExecutor, true);
break;
}
else
{
// ignore actions in referenced rules
c = config.Transform(t.target, true);
break;
}
goto case TransitionType.Epsilon;
}
case TransitionType.Epsilon:
{
c = config.Transform(t.target, true);
break;
}
case TransitionType.Atom:
case TransitionType.Range:
case TransitionType.Set:
{
if (treatEofAsEpsilon)
{
if (t.Matches(IntStreamConstants.Eof, char.MinValue, char.MaxValue))
{
c = config.Transform(t.target, false);
break;
}
}
c = null;
break;
}
default:
{
c = null;
break;
}
}
return(c);
}