/// <summary>
/// Compute set of tokens that can follow
/// <code>s</code>
/// in the ATN in the
/// specified
/// <code>ctx</code>
/// .
/// <p/>
/// If
/// <code>ctx</code>
/// is
/// <see cref="PredictionContext.EmptyLocal"/>
/// and
/// <code>stopState</code>
/// or the end of the rule containing
/// <code>s</code>
/// is reached,
/// <see cref="TokenConstants.Epsilon"/>
/// is added to the result set. If
/// <code>ctx</code>
/// is not
/// <see cref="PredictionContext.EmptyLocal"/>
/// and
/// <code>addEOF</code>
/// is
/// <code>true</code>
/// and
/// <code>stopState</code>
/// or the end of the outermost rule is reached,
/// <see cref="TokenConstants.Eof"/>
/// is added to the result set.
/// </summary>
/// <param name="s">the ATN state.</param>
/// <param name="stopState">
/// the ATN state to stop at. This can be a
/// <see cref="BlockEndState"/>
/// to detect epsilon paths through a closure.
/// </param>
/// <param name="ctx">
/// The outer context, or
/// <see cref="PredictionContext.EmptyLocal"/>
/// if
/// the outer context should not be used.
/// </param>
/// <param name="look">The result lookahead set.</param>
/// <param name="lookBusy">
/// A set used for preventing epsilon closures in the ATN
/// from causing a stack overflow. Outside code should pass
/// <code>new HashSet<ATNConfig></code>
/// for this argument.
/// </param>
/// <param name="calledRuleStack">
/// A set used for preventing left recursion in the
/// ATN from causing a stack overflow. Outside code should pass
/// <code>new BitSet()</code>
/// for this argument.
/// </param>
/// <param name="seeThruPreds">
///
/// <code>true</code>
/// to true semantic predicates as
/// implicitly
/// <code>true</code>
/// and "see through them", otherwise
/// <code>false</code>
/// to treat semantic predicates as opaque and add
/// <see cref="HitPred"/>
/// to the
/// result if one is encountered.
/// </param>
/// <param name="addEOF">
/// Add
/// <see cref="TokenConstants.Eof"/>
/// to the result if the end of the
/// outermost context is reached. This parameter has no effect if
/// <code>ctx</code>
/// is
/// <see cref="PredictionContext.EmptyLocal"/>
/// .
/// </param>
protected internal virtual void Look(ATNState s, ATNState stopState, PredictionContext ctx, IntervalSet look, HashSet<ATNConfig> lookBusy, BitSet calledRuleStack, bool seeThruPreds, bool addEOF)
{
// System.out.println("_LOOK("+s.stateNumber+", ctx="+ctx);
ATNConfig c = ATNConfig.Create(s, 0, ctx);
if (!lookBusy.Add(c))
{
return;
}
if (s == stopState)
{
if (PredictionContext.IsEmptyLocal(ctx))
{
look.Add(TokenConstants.Epsilon);
return;
}
else
{
if (ctx.IsEmpty)
{
if (addEOF)
{
look.Add(TokenConstants.Eof);
}
return;
}
}
}
if (s is RuleStopState)
{
if (ctx.IsEmpty && !PredictionContext.IsEmptyLocal(ctx))
{
if (addEOF)
{
look.Add(TokenConstants.Eof);
}
return;
}
bool removed = calledRuleStack.Get(s.ruleIndex);
try
{
calledRuleStack.Clear(s.ruleIndex);
for (int i = 0; i < ctx.Size; i++)
{
if (ctx.GetReturnState(i) == PredictionContext.EmptyFullStateKey)
{
continue;
}
ATNState returnState = atn.states[ctx.GetReturnState(i)];
// System.out.println("popping back to "+retState);
Look(returnState, stopState, ctx.GetParent(i), look, lookBusy, calledRuleStack, seeThruPreds, addEOF);
}
}
finally
{
if (removed)
{
calledRuleStack.Set(s.ruleIndex);
}
}
}
int n = s.NumberOfTransitions;
for (int i_1 = 0; i_1 < n; i_1++)
{
Transition t = s.Transition(i_1);
if (t is RuleTransition)
{
RuleTransition ruleTransition = (RuleTransition)t;
if (calledRuleStack.Get(ruleTransition.ruleIndex))
{
continue;
}
PredictionContext newContext = ctx.GetChild(ruleTransition.followState.stateNumber);
try
{
calledRuleStack.Set(ruleTransition.ruleIndex);
Look(t.target, stopState, newContext, look, lookBusy, calledRuleStack, seeThruPreds, addEOF);
}
finally
{
calledRuleStack.Clear(ruleTransition.ruleIndex);
}
}
else
{
if (t is AbstractPredicateTransition)
{
if (seeThruPreds)
{
Look(t.target, stopState, ctx, look, lookBusy, calledRuleStack, seeThruPreds, addEOF);
}
else
{
look.Add(HitPred);
}
}
else
{
if (t.IsEpsilon)
{
Look(t.target, stopState, ctx, look, lookBusy, calledRuleStack, seeThruPreds, addEOF);
}
else
{
if (t.GetType() == typeof(WildcardTransition))
{
look.AddAll(IntervalSet.Of(TokenConstants.MinUserTokenType, atn.maxTokenType));
}
else
{
// System.out.println("adding "+ t);
IntervalSet set = t.Label;
if (set != null)
{
if (t is NotSetTransition)
{
set = set.Complement(IntervalSet.Of(TokenConstants.MinUserTokenType, atn.maxTokenType));
}
look.AddAll(set);
}
}
}
}
}
}
}