/** * Guard a rule's previous context from being reused. * <p> * This routine will check whether a given parser rule needs to be rerun, or if * we already have context that can be reused for this parse. */ public IncrementalParserRuleContext guardRule(IncrementalParserRuleContext parentCtx, int state, int ruleIndex) { // If we have no previous parse data, the rule needs to be run. if (this.parseData == null) { return(null); } Console.WriteLine($"guardRule() state = {state.ToString()}, ruleIndex = {ruleIndex.ToString()}"); // See if we have seen this state before at this starting point. IncrementalParserRuleContext existingCtx = this.parseData.tryGetContext( parentCtx != null ? parentCtx.Depth() + 1 : 1, State, ruleIndex, this._input.LT(1).TokenIndex); // We haven't see it, so we need to rerun this rule. if (existingCtx == null) { return(null); } // We have seen it, see if it was affected by the parse if (this.parseData.ruleAffectedByTokenChanges(existingCtx)) { return(null); } // Everything checked out, reuse the rule context - we add it to the // parent context as enterRule would have; if (this._ctx != null) { IncrementalParserRuleContext parent = (IncrementalParserRuleContext)this._ctx; // add current context to parent if we have a parent parent?.AddChild(existingCtx); } return(existingCtx); }
/** * Process each rule context we see in top-down order, adjusting min- * max and start-stop tokens, as well as adding the context to the * rule start map. * * @param ctx Context to process */ public void EnterEveryRule(ParserRuleContext ctx) { IncrementalParserRuleContext incCtx = (IncrementalParserRuleContext)ctx; // Don't bother adjusting rule contexts that we can't possibly // reuse. Also don't touch contexts without an epoch. They must // represent something the incremental parser never saw, // since it sets epochs on all contexts it touches. if (incCtx.epoch == -1) { return; } bool mayNeedAdjustment = parent.tokenOffsets != null && parent.tokenOffsets.Count != 0; if (mayNeedAdjustment) { adjustMinMax(incCtx); } if (!parent.ruleAffectedByTokenChanges(incCtx)) { if (mayNeedAdjustment) { adjustStartStop(incCtx); } String key = parent.getKeyFromContext(incCtx); parent.ruleStartMap.Add(key, incCtx); } }
/** * Adjust the minimum/maximum token index that appears in a rule context. Like * other functions, this simply converts the token indexes from how they appear * in the old stream to how they would appear in the new stream. * * @param ctx Parser context to adjust. */ private void adjustMinMax(IncrementalParserRuleContext ctx) { bool changed = false; int newMin = ctx.MinTokenIndex; IToken newToken = getAdjustedToken(newMin); if (newToken != null) { newMin = newToken.TokenIndex; changed = true; } int newMax = ctx.MaxTokenIndex; newToken = getAdjustedToken(newMax); if (newToken != null) { newMax = newToken.TokenIndex; changed = true; } if (changed) { ctx.setMinMaxTokenIndex(Interval.Of(newMin, newMax)); } }
/* * These two functions are parse of the ParseTreeListener API. We do not need to * call super methods */ public void EnterEveryRule(ParserRuleContext ctx) { // During rule entry, we push a new min/max token state. pushCurrentTokenToMinMax(); IncrementalParserRuleContext incCtx = (IncrementalParserRuleContext)ctx; incCtx.epoch = this.getParserEpoch(); }
/** * Pop the min max stack the stream is using and union the interval into the * passed in context. Return the interval for the context * * @param ctx Context to union interval into. */ private Interval popAndHandleMinMax(IncrementalParserRuleContext ctx) { Interval interval = popCurrentMinMax(ctx); ctx.setMinMaxTokenIndex(ctx.getMinMaxTokenIndex().Union(interval)); // Returning interval is wrong because there may have been child // intervals already merged into this ctx. return(ctx.getMinMaxTokenIndex()); }
/* * This is part of the regular Parser API. The super method must be called. */ /** * The new recursion context is an unfortunate edge case for us. It reparents * the relationship between the contexts, so we need to merge intervals here. */ public override void PushNewRecursionContext(ParserRuleContext localctx, int state, int ruleIndex) { // This context becomes the child IncrementalParserRuleContext previous = (IncrementalParserRuleContext)this._ctx; // The incoming context becomes the parent IncrementalParserRuleContext incLocalCtx = (IncrementalParserRuleContext)localctx; incLocalCtx.setMinMaxTokenIndex(incLocalCtx.getMinMaxTokenIndex().Union(previous.getMinMaxTokenIndex())); base.PushNewRecursionContext(localctx, state, ruleIndex); }
/** * Index a given parse tree and adjust the min/max ranges * * @param tree Parser context to adjust */ private void indexAndAdjustParseTree(IncrementalParserRuleContext tree) { // This is a quick way of indexing the parse tree by start. We actually // could walk the old parse tree as the parse proceeds. This is left as // a future optimization. We also could just allow passing in // constructed maps if this turns out to be slow. tokenStream.Fill(); IParseTreeListener listener = new ParseTreeProcessor(this); ParseTreeWalker.Default.Walk(listener, tree); }
public IncrementalParserData(IncrementalTokenStream tokenStream, List <TokenChange> tokenChanges, IncrementalParserRuleContext oldTree) { this.tokenChanges = tokenChanges; if (tokenChanges != null) { this.tokenStream = tokenStream; computeTokenOffsetRanges(oldTree.MaxTokenIndex); indexAndAdjustParseTree(oldTree); } }
public void ExitEveryRule(ParserRuleContext ctx) { // On exit, we need to merge the min max into the current context, // and then merge the current context interval into our parent. // First merge with the interval on the top of the stack. IncrementalParserRuleContext incCtx = (IncrementalParserRuleContext)ctx; Interval interval = popAndHandleMinMax(incCtx); // Now merge with our parent interval. if (incCtx.Parent != null) { IncrementalParserRuleContext parentIncCtx = (IncrementalParserRuleContext)incCtx.Parent; parentIncCtx.setMinMaxTokenIndex(parentIncCtx.getMinMaxTokenIndex().Union(interval)); } }
/** * Adjust the start/stop token indexes of a rule to take into account position * changes in the token stream. * * @param ctx The rule context to adjust the start/stop tokens of. */ private void adjustStartStop(IncrementalParserRuleContext ctx) { IToken newToken = getAdjustedToken(ctx.Start.TokenIndex); if (newToken != null) { ctx.Start = newToken; } if (ctx.Stop != null) { newToken = getAdjustedToken(ctx.Stop.TokenIndex); if (newToken != null) { ctx.Stop = newToken; } } }
/** * Determine whether a given parser rule is affected by changes to the token * stream. * * @param ctx Current parser context coming into a rule. */ public bool ruleAffectedByTokenChanges(IncrementalParserRuleContext ctx) { // If we never got passed data, reparse everything. if (this.tokenChanges == null) { return(true); } // However if there are no changes, the rule is fine if (this.tokenChanges.Count == 0) { return(false); } // See if any changed token exists in our upper, lower bounds. int start = ctx.MinTokenIndex; int end = ctx.MaxTokenIndex; // See if the set has anything in the range we are asking about bool result = false; // Get a view of all elements >= start token to start. // SortedSet<int> tailSet = this.changedTokens.tailSet(start, true); SortedSet <int> tailSet = this.changedTokens.GetViewBetween(start, this.changedTokens.Max); // If *any* are in range, the rule is modified. // Since the set is ordered, once we go past the end of the [start, end] range, // we can stop. foreach (int elem in tailSet) { if (elem <= end) { result = true; break; } else if (elem > end) { break; } } if (result) { return(true); } return(false); }
// Pop the min max stack the stream is using and return the interval. private Interval popCurrentMinMax(IncrementalParserRuleContext ctx) { IncrementalTokenStream incStream = (IncrementalTokenStream)InputStream; return(incStream.popMinMax()); }
private String getKeyFromContext(IncrementalParserRuleContext ctx) { return(getKey(ctx.Depth(), ctx.invokingState, ctx.RuleIndex, ctx.Start.TokenIndex)); }
public IncrementalParserRuleContext(IncrementalParserRuleContext parent, int invokingStateNumber) : base(parent, invokingStateNumber) { // super(parent, invokingStateNumber); }