UNPKG

antlr4ts

Version:

ANTLR 4 runtime for JavaScript written in Typescript

977 lines (976 loc) 111 kB
"use strict"; /*! * Copyright 2016 The ANTLR Project. All rights reserved. * Licensed under the BSD-3-Clause license. See LICENSE file in the project root for license information. */ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ParserATNSimulator = void 0; // ConvertTo-TS run at 2016-10-04T11:26:31.1989835-07:00 const AcceptStateInfo_1 = require("../dfa/AcceptStateInfo"); const ActionTransition_1 = require("./ActionTransition"); const Array2DHashSet_1 = require("../misc/Array2DHashSet"); const Arrays_1 = require("../misc/Arrays"); const ATN_1 = require("./ATN"); const ATNConfig_1 = require("./ATNConfig"); const ATNConfigSet_1 = require("./ATNConfigSet"); const ATNSimulator_1 = require("./ATNSimulator"); const ATNStateType_1 = require("./ATNStateType"); const AtomTransition_1 = require("./AtomTransition"); const BitSet_1 = require("../misc/BitSet"); const ConflictInfo_1 = require("./ConflictInfo"); const DecisionState_1 = require("./DecisionState"); const DFAState_1 = require("../dfa/DFAState"); const IntegerList_1 = require("../misc/IntegerList"); const Interval_1 = require("../misc/Interval"); const IntStream_1 = require("../IntStream"); const Decorators_1 = require("../Decorators"); const NotSetTransition_1 = require("./NotSetTransition"); const NoViableAltException_1 = require("../NoViableAltException"); const ObjectEqualityComparator_1 = require("../misc/ObjectEqualityComparator"); const ParserRuleContext_1 = require("../ParserRuleContext"); const PredictionContext_1 = require("./PredictionContext"); const PredictionContextCache_1 = require("./PredictionContextCache"); const PredictionMode_1 = require("./PredictionMode"); const RuleStopState_1 = require("./RuleStopState"); const RuleTransition_1 = require("./RuleTransition"); const SemanticContext_1 = require("./SemanticContext"); const SetTransition_1 = require("./SetTransition"); const SimulatorState_1 = require("./SimulatorState"); const Token_1 = require("../Token"); const VocabularyImpl_1 = require("../VocabularyImpl"); const assert = require("assert"); const MAX_SHORT_VALUE = 0xFFFF; const MIN_INTEGER_VALUE = -((1 << 31) >>> 0); /** * The embodiment of the adaptive LL(*), ALL(*), parsing strategy. * * The basic complexity of the adaptive strategy makes it harder to understand. * We begin with ATN simulation to build paths in a DFA. Subsequent prediction * requests go through the DFA first. If they reach a state without an edge for * the current symbol, the algorithm fails over to the ATN simulation to * complete the DFA path for the current input (until it finds a conflict state * or uniquely predicting state). * * All of that is done without using the outer context because we want to create * a DFA that is not dependent upon the rule invocation stack when we do a * prediction. One DFA works in all contexts. We avoid using context not * necessarily because it's slower, although it can be, but because of the DFA * caching problem. The closure routine only considers the rule invocation stack * created during prediction beginning in the decision rule. For example, if * prediction occurs without invoking another rule's ATN, there are no context * stacks in the configurations. When lack of context leads to a conflict, we * don't know if it's an ambiguity or a weakness in the strong LL(*) parsing * strategy (versus full LL(*)). * * When SLL yields a configuration set with conflict, we rewind the input and * retry the ATN simulation, this time using full outer context without adding * to the DFA. Configuration context stacks will be the full invocation stacks * from the start rule. If we get a conflict using full context, then we can * definitively say we have a true ambiguity for that input sequence. If we * don't get a conflict, it implies that the decision is sensitive to the outer * context. (It is not context-sensitive in the sense of context-sensitive * grammars.) * * The next time we reach this DFA state with an SLL conflict, through DFA * simulation, we will again retry the ATN simulation using full context mode. * This is slow because we can't save the results and have to "interpret" the * ATN each time we get that input. * * **CACHING FULL CONTEXT PREDICTIONS** * * We could cache results from full context to predicted alternative easily and * that saves a lot of time but doesn't work in presence of predicates. The set * of visible predicates from the ATN start state changes depending on the * context, because closure can fall off the end of a rule. I tried to cache * tuples (stack context, semantic context, predicted alt) but it was slower * than interpreting and much more complicated. Also required a huge amount of * memory. The goal is not to create the world's fastest parser anyway. I'd like * to keep this algorithm simple. By launching multiple threads, we can improve * the speed of parsing across a large number of files. * * There is no strict ordering between the amount of input used by SLL vs LL, * which makes it really hard to build a cache for full context. Let's say that * we have input A B C that leads to an SLL conflict with full context X. That * implies that using X we might only use A B but we could also use A B C D to * resolve conflict. Input A B C D could predict alternative 1 in one position * in the input and A B C E could predict alternative 2 in another position in * input. The conflicting SLL configurations could still be non-unique in the * full context prediction, which would lead us to requiring more input than the * original A B C. To make a prediction cache work, we have to track the exact * input used during the previous prediction. That amounts to a cache that maps * X to a specific DFA for that context. * * Something should be done for left-recursive expression predictions. They are * likely LL(1) + pred eval. Easier to do the whole SLL unless error and retry * with full LL thing Sam does. * * **AVOIDING FULL CONTEXT PREDICTION** * * We avoid doing full context retry when the outer context is empty, we did not * dip into the outer context by falling off the end of the decision state rule, * or when we force SLL mode. * * As an example of the not dip into outer context case, consider as super * constructor calls versus function calls. One grammar might look like * this: * * ```antlr * ctorBody * : '{' superCall? stat* '}' * ; * ``` * * Or, you might see something like * * ```antlr * stat * : superCall ';' * | expression ';' * | ... * ; * ``` * * In both cases I believe that no closure operations will dip into the outer * context. In the first case ctorBody in the worst case will stop at the '}'. * In the 2nd case it should stop at the ';'. Both cases should stay within the * entry rule and not dip into the outer context. * * **PREDICATES** * * Predicates are always evaluated if present in either SLL or LL both. SLL and * LL simulation deals with predicates differently. SLL collects predicates as * it performs closure operations like ANTLR v3 did. It delays predicate * evaluation until it reaches and accept state. This allows us to cache the SLL * ATN simulation whereas, if we had evaluated predicates on-the-fly during * closure, the DFA state configuration sets would be different and we couldn't * build up a suitable DFA. * * When building a DFA accept state during ATN simulation, we evaluate any * predicates and return the sole semantically valid alternative. If there is * more than 1 alternative, we report an ambiguity. If there are 0 alternatives, * we throw an exception. Alternatives without predicates act like they have * true predicates. The simple way to think about it is to strip away all * alternatives with false predicates and choose the minimum alternative that * remains. * * When we start in the DFA and reach an accept state that's predicated, we test * those and return the minimum semantically viable alternative. If no * alternatives are viable, we throw an exception. * * During full LL ATN simulation, closure always evaluates predicates and * on-the-fly. This is crucial to reducing the configuration set size during * closure. It hits a landmine when parsing with the Java grammar, for example, * without this on-the-fly evaluation. * * **SHARING DFA** * * All instances of the same parser share the same decision DFAs through a * static field. Each instance gets its own ATN simulator but they share the * same {@link ATN#decisionToDFA} field. They also share a * {@link PredictionContextCache} object that makes sure that all * {@link PredictionContext} objects are shared among the DFA states. This makes * a big size difference. * * **THREAD SAFETY** * * The {@link ParserATNSimulator} locks on the {@link ATN#decisionToDFA} field when * it adds a new DFA object to that array. {@link #addDFAEdge} * locks on the DFA for the current decision when setting the * {@link DFAState#edges} field. {@link #addDFAState} locks on * the DFA for the current decision when looking up a DFA state to see if it * already exists. We must make sure that all requests to add DFA states that * are equivalent result in the same shared DFA object. This is because lots of * threads will be trying to update the DFA at once. The * {@link #addDFAState} method also locks inside the DFA lock * but this time on the shared context cache when it rebuilds the * configurations' {@link PredictionContext} objects using cached * subgraphs/nodes. No other locking occurs, even during DFA simulation. This is * safe as long as we can guarantee that all threads referencing * `s.edge[t]` get the same physical target {@link DFAState}, or * `undefined`. Once into the DFA, the DFA simulation does not reference the * {@link DFA#states} map. It follows the {@link DFAState#edges} field to new * targets. The DFA simulator will either find {@link DFAState#edges} to be * `undefined`, to be non-`undefined` and `dfa.edges[t]` undefined, or * `dfa.edges[t]` to be non-undefined. The * {@link #addDFAEdge} method could be racing to set the field * but in either case the DFA simulator works; if `undefined`, and requests ATN * simulation. It could also race trying to get `dfa.edges[t]`, but either * way it will work because it's not doing a test and set operation. * * **Starting with SLL then failing to combined SLL/LL (Two-Stage * Parsing)** * * Sam pointed out that if SLL does not give a syntax error, then there is no * point in doing full LL, which is slower. We only have to try LL if we get a * syntax error. For maximum speed, Sam starts the parser set to pure SLL * mode with the {@link BailErrorStrategy}: * * ``` * parser.interpreter.{@link #setPredictionMode setPredictionMode}`(`{@link PredictionMode#SLL}`)`; * parser.{@link Parser#setErrorHandler setErrorHandler}(new {@link BailErrorStrategy}()); * ``` * * If it does not get a syntax error, then we're done. If it does get a syntax * error, we need to retry with the combined SLL/LL strategy. * * The reason this works is as follows. If there are no SLL conflicts, then the * grammar is SLL (at least for that input set). If there is an SLL conflict, * the full LL analysis must yield a set of viable alternatives which is a * subset of the alternatives reported by SLL. If the LL set is a singleton, * then the grammar is LL but not SLL. If the LL set is the same size as the SLL * set, the decision is SLL. If the LL set has size &gt; 1, then that decision * is truly ambiguous on the current input. If the LL set is smaller, then the * SLL conflict resolution might choose an alternative that the full LL would * rule out as a possibility based upon better context information. If that's * the case, then the SLL parse will definitely get an error because the full LL * analysis says it's not viable. If SLL conflict resolution chooses an * alternative within the LL set, them both SLL and LL would choose the same * alternative because they both choose the minimum of multiple conflicting * alternatives. * * Let's say we have a set of SLL conflicting alternatives `{1, 2, 3}` and * a smaller LL set called *s*. If *s* is `{2, 3}`, then SLL * parsing will get an error because SLL will pursue alternative 1. If * *s* is `{1, 2}` or `{1, 3}` then both SLL and LL will * choose the same alternative because alternative one is the minimum of either * set. If *s* is `{2}` or `{3}` then SLL will get a syntax * error. If *s* is `{1}` then SLL will succeed. * * Of course, if the input is invalid, then we will get an error for sure in * both SLL and LL parsing. Erroneous input will therefore require 2 passes over * the input. */ let ParserATNSimulator = class ParserATNSimulator extends ATNSimulator_1.ATNSimulator { constructor(atn, parser) { super(atn); this.predictionMode = PredictionMode_1.PredictionMode.LL; this.force_global_context = false; this.always_try_local_context = true; /** * Determines whether the DFA is used for full-context predictions. When * `true`, the DFA stores transition information for both full-context * and SLL parsing; otherwise, the DFA only stores SLL transition * information. * * For some grammars, enabling the full-context DFA can result in a * substantial performance improvement. However, this improvement typically * comes at the expense of memory used for storing the cached DFA states, * configuration sets, and prediction contexts. * * The default value is `false`. */ this.enable_global_context_dfa = false; this.optimize_unique_closure = true; this.optimize_ll1 = true; this.optimize_tail_calls = true; this.tail_call_preserves_sll = true; this.treat_sllk1_conflict_as_ambiguity = false; /** * When `true`, ambiguous alternatives are reported when they are * encountered within {@link #execATN}. When `false`, these messages * are suppressed. The default is `false`. * * When messages about ambiguous alternatives are not required, setting this * to `false` enables additional internal optimizations which may lose * this information. */ this.reportAmbiguities = false; /** By default we do full context-sensitive LL(*) parsing not * Strong LL(*) parsing. If we fail with Strong LL(*) we * try full LL(*). That means we rewind and use context information * when closure operations fall off the end of the rule that * holds the decision were evaluating. */ this.userWantsCtxSensitive = true; this._parser = parser; } getPredictionMode() { return this.predictionMode; } setPredictionMode(predictionMode) { this.predictionMode = predictionMode; } reset() { // intentionally empty } adaptivePredict(input, decision, outerContext, useContext) { if (useContext === undefined) { useContext = false; } let dfa = this.atn.decisionToDFA[decision]; assert(dfa != null); if (this.optimize_ll1 && !dfa.isPrecedenceDfa && !dfa.isEmpty) { let ll_1 = input.LA(1); if (ll_1 >= 0 && ll_1 <= 0xFFFF) { let key = ((decision << 16) >>> 0) + ll_1; let alt = this.atn.LL1Table.get(key); if (alt != null) { return alt; } } } this.dfa = dfa; if (this.force_global_context) { useContext = true; } else if (!this.always_try_local_context) { useContext = useContext || dfa.isContextSensitive; } this.userWantsCtxSensitive = useContext || (this.predictionMode !== PredictionMode_1.PredictionMode.SLL && outerContext != null && !this.atn.decisionToState[decision].sll); if (outerContext == null) { outerContext = ParserRuleContext_1.ParserRuleContext.emptyContext(); } let state; if (!dfa.isEmpty) { state = this.getStartState(dfa, input, outerContext, useContext); } if (state == null) { if (outerContext == null) { outerContext = ParserRuleContext_1.ParserRuleContext.emptyContext(); } if (ParserATNSimulator.debug) { console.log("ATN decision " + dfa.decision + " exec LA(1)==" + this.getLookaheadName(input) + ", outerContext=" + outerContext.toString(this._parser)); } state = this.computeStartState(dfa, outerContext, useContext); } let m = input.mark(); let index = input.index; try { let alt = this.execDFA(dfa, input, index, state); if (ParserATNSimulator.debug) { console.log("DFA after predictATN: " + dfa.toString(this._parser.vocabulary, this._parser.ruleNames)); } return alt; } finally { this.dfa = undefined; input.seek(index); input.release(m); } } getStartState(dfa, input, outerContext, useContext) { if (!useContext) { if (dfa.isPrecedenceDfa) { // the start state for a precedence DFA depends on the current // parser precedence, and is provided by a DFA method. let state = dfa.getPrecedenceStartState(this._parser.precedence, false); if (state == null) { return undefined; } return new SimulatorState_1.SimulatorState(outerContext, state, false, outerContext); } else { if (dfa.s0 == null) { return undefined; } return new SimulatorState_1.SimulatorState(outerContext, dfa.s0, false, outerContext); } } if (!this.enable_global_context_dfa) { return undefined; } let remainingContext = outerContext; assert(outerContext != null); let s0; if (dfa.isPrecedenceDfa) { s0 = dfa.getPrecedenceStartState(this._parser.precedence, true); } else { s0 = dfa.s0full; } while (remainingContext != null && s0 != null && s0.isContextSensitive) { remainingContext = this.skipTailCalls(remainingContext); s0 = s0.getContextTarget(this.getReturnState(remainingContext)); if (remainingContext.isEmpty) { assert(s0 == null || !s0.isContextSensitive); } else { remainingContext = remainingContext.parent; } } if (s0 == null) { return undefined; } return new SimulatorState_1.SimulatorState(outerContext, s0, useContext, remainingContext); } execDFA(dfa, input, startIndex, state) { let outerContext = state.outerContext; if (ParserATNSimulator.dfa_debug) { console.log("DFA decision " + dfa.decision + " exec LA(1)==" + this.getLookaheadName(input) + ", outerContext=" + outerContext.toString(this._parser)); } if (ParserATNSimulator.dfa_debug) { console.log(dfa.toString(this._parser.vocabulary, this._parser.ruleNames)); } let s = state.s0; let t = input.LA(1); let remainingOuterContext = state.remainingOuterContext; while (true) { if (ParserATNSimulator.dfa_debug) { console.log("DFA state " + s.stateNumber + " LA(1)==" + this.getLookaheadName(input)); } if (state.useContext) { while (s.isContextSymbol(t)) { let next; if (remainingOuterContext != null) { remainingOuterContext = this.skipTailCalls(remainingOuterContext); next = s.getContextTarget(this.getReturnState(remainingOuterContext)); } if (next == null) { // fail over to ATN let initialState = new SimulatorState_1.SimulatorState(state.outerContext, s, state.useContext, remainingOuterContext); return this.execATN(dfa, input, startIndex, initialState); } assert(remainingOuterContext != null); remainingOuterContext = remainingOuterContext.parent; s = next; } } if (this.isAcceptState(s, state.useContext)) { if (s.predicates != null) { if (ParserATNSimulator.dfa_debug) { console.log("accept " + s); } } else { if (ParserATNSimulator.dfa_debug) { console.log("accept; predict " + s.prediction + " in state " + s.stateNumber); } } // keep going unless we're at EOF or state only has one alt number // mentioned in configs; check if something else could match // TODO: don't we always stop? only lexer would keep going // TODO: v3 dfa don't do this. break; } // t is not updated if one of these states is reached assert(!this.isAcceptState(s, state.useContext)); // if no edge, pop over to ATN interpreter, update DFA and return let target = this.getExistingTargetState(s, t); if (target == null) { if (ParserATNSimulator.dfa_debug && t >= 0) { console.log("no edge for " + this._parser.vocabulary.getDisplayName(t)); } let alt; if (ParserATNSimulator.dfa_debug) { let interval = Interval_1.Interval.of(startIndex, this._parser.inputStream.index); console.log("ATN exec upon " + this._parser.inputStream.getText(interval) + " at DFA state " + s.stateNumber); } let initialState = new SimulatorState_1.SimulatorState(outerContext, s, state.useContext, remainingOuterContext); alt = this.execATN(dfa, input, startIndex, initialState); if (ParserATNSimulator.dfa_debug) { console.log("back from DFA update, alt=" + alt + ", dfa=\n" + dfa.toString(this._parser.vocabulary, this._parser.ruleNames)); //dump(dfa); } // action already executed if (ParserATNSimulator.dfa_debug) { console.log("DFA decision " + dfa.decision + " predicts " + alt); } return alt; // we've updated DFA, exec'd action, and have our deepest answer } else if (target === ATNSimulator_1.ATNSimulator.ERROR) { let errorState = new SimulatorState_1.SimulatorState(outerContext, s, state.useContext, remainingOuterContext); return this.handleNoViableAlt(input, startIndex, errorState); } s = target; if (!this.isAcceptState(s, state.useContext) && t !== IntStream_1.IntStream.EOF) { input.consume(); t = input.LA(1); } } // if ( acceptState==null ) { // if ( debug ) System.out.println("!!! no viable alt in dfa"); // return -1; // } if (!state.useContext && s.configs.conflictInfo != null) { if (dfa.atnStartState instanceof DecisionState_1.DecisionState) { if (!this.userWantsCtxSensitive || (!s.configs.dipsIntoOuterContext && s.configs.isExactConflict) || (this.treat_sllk1_conflict_as_ambiguity && input.index === startIndex)) { // we don't report the ambiguity again //if ( !this.acceptState.configset.hasSemanticContext ) { // this.reportAmbiguity(dfa, acceptState, startIndex, input.index, acceptState.configset.conflictingAlts, acceptState.configset); //} } else { assert(!state.useContext); // Before attempting full context prediction, check to see if there are // disambiguating or validating predicates to evaluate which allow an // immediate decision let conflictingAlts; let predicates = s.predicates; if (predicates != null) { let conflictIndex = input.index; if (conflictIndex !== startIndex) { input.seek(startIndex); } conflictingAlts = this.evalSemanticContext(predicates, outerContext, true); if (conflictingAlts.cardinality() === 1) { return conflictingAlts.nextSetBit(0); } if (conflictIndex !== startIndex) { // restore the index so reporting the fallback to full // context occurs with the index at the correct spot input.seek(conflictIndex); } } if (this.reportAmbiguities) { let conflictState = new SimulatorState_1.SimulatorState(outerContext, s, state.useContext, remainingOuterContext); this.reportAttemptingFullContext(dfa, conflictingAlts, conflictState, startIndex, input.index); } input.seek(startIndex); return this.adaptivePredict(input, dfa.decision, outerContext, true); } } } // Before jumping to prediction, check to see if there are // disambiguating or validating predicates to evaluate let predicates = s.predicates; if (predicates != null) { let stopIndex = input.index; if (startIndex !== stopIndex) { input.seek(startIndex); } let alts = this.evalSemanticContext(predicates, outerContext, this.reportAmbiguities && this.predictionMode === PredictionMode_1.PredictionMode.LL_EXACT_AMBIG_DETECTION); switch (alts.cardinality()) { case 0: throw this.noViableAlt(input, outerContext, s.configs, startIndex); case 1: return alts.nextSetBit(0); default: // report ambiguity after predicate evaluation to make sure the correct // set of ambig alts is reported. if (startIndex !== stopIndex) { input.seek(stopIndex); } this.reportAmbiguity(dfa, s, startIndex, stopIndex, s.configs.isExactConflict, alts, s.configs); return alts.nextSetBit(0); } } if (ParserATNSimulator.dfa_debug) { console.log("DFA decision " + dfa.decision + " predicts " + s.prediction); } return s.prediction; } /** * Determines if a particular DFA state should be treated as an accept state * for the current prediction mode. In addition to the `useContext` * parameter, the {@link #getPredictionMode()} method provides the * prediction mode controlling the prediction algorithm as a whole. * * The default implementation simply returns the value of * `DFAState.isAcceptState` except for conflict states when * `useContext` is `true` and {@link #getPredictionMode()} is * {@link PredictionMode#LL_EXACT_AMBIG_DETECTION}. In that case, only * conflict states where {@link ATNConfigSet#isExactConflict} is * `true` are considered accept states. * * @param state The DFA state to check. * @param useContext `true` if the prediction algorithm is currently * considering the full parser context; otherwise, `false` if the * algorithm is currently performing a local context prediction. * * @returns `true` if the specified `state` is an accept state; * otherwise, `false`. */ isAcceptState(state, useContext) { if (!state.isAcceptState) { return false; } if (state.configs.conflictingAlts == null) { // unambiguous return true; } // More picky when we need exact conflicts if (useContext && this.predictionMode === PredictionMode_1.PredictionMode.LL_EXACT_AMBIG_DETECTION) { return state.configs.isExactConflict; } return true; } /** Performs ATN simulation to compute a predicted alternative based * upon the remaining input, but also updates the DFA cache to avoid * having to traverse the ATN again for the same input sequence. * * There are some key conditions we're looking for after computing a new * set of ATN configs (proposed DFA state): * * * if the set is empty, there is no viable alternative for current symbol * * does the state uniquely predict an alternative? * * does the state have a conflict that would prevent us from * putting it on the work list? * * if in non-greedy decision is there a config at a rule stop state? * * We also have some key operations to do: * * * add an edge from previous DFA state to potentially new DFA state, D, * upon current symbol but only if adding to work list, which means in all * cases except no viable alternative (and possibly non-greedy decisions?) * * collecting predicates and adding semantic context to DFA accept states * * adding rule context to context-sensitive DFA accept states * * consuming an input symbol * * reporting a conflict * * reporting an ambiguity * * reporting a context sensitivity * * reporting insufficient predicates * * We should isolate those operations, which are side-effecting, to the * main work loop. We can isolate lots of code into other functions, but * they should be side effect free. They can return package that * indicates whether we should report something, whether we need to add a * DFA edge, whether we need to augment accept state with semantic * context or rule invocation context. Actually, it seems like we always * add predicates if they exist, so that can simply be done in the main * loop for any accept state creation or modification request. * * cover these cases: * dead end * single alt * single alt + preds * conflict * conflict + preds * * TODO: greedy + those */ execATN(dfa, input, startIndex, initialState) { if (ParserATNSimulator.debug) { console.log("execATN decision " + dfa.decision + " exec LA(1)==" + this.getLookaheadName(input)); } let outerContext = initialState.outerContext; let useContext = initialState.useContext; let t = input.LA(1); let previous = initialState; let contextCache = new PredictionContextCache_1.PredictionContextCache(); while (true) { // while more work let nextState = this.computeReachSet(dfa, previous, t, contextCache); if (nextState == null) { this.setDFAEdge(previous.s0, input.LA(1), ATNSimulator_1.ATNSimulator.ERROR); return this.handleNoViableAlt(input, startIndex, previous); } let D = nextState.s0; // predicted alt => accept state assert(D.isAcceptState || D.prediction === ATN_1.ATN.INVALID_ALT_NUMBER); // conflicted => accept state assert(D.isAcceptState || D.configs.conflictInfo == null); if (this.isAcceptState(D, useContext)) { let conflictingAlts = D.configs.conflictingAlts; let predictedAlt = conflictingAlts == null ? D.prediction : ATN_1.ATN.INVALID_ALT_NUMBER; if (predictedAlt !== ATN_1.ATN.INVALID_ALT_NUMBER) { if (this.optimize_ll1 && input.index === startIndex && !dfa.isPrecedenceDfa && nextState.outerContext === nextState.remainingOuterContext && dfa.decision >= 0 && !D.configs.hasSemanticContext) { if (t >= 0 && t <= MAX_SHORT_VALUE) { let key = ((dfa.decision << 16) >>> 0) + t; this.atn.LL1Table.set(key, predictedAlt); } } if (useContext && this.always_try_local_context) { this.reportContextSensitivity(dfa, predictedAlt, nextState, startIndex, input.index); } } predictedAlt = D.prediction; // int k = input.index - startIndex + 1; // how much input we used // System.out.println("used k="+k); let attemptFullContext = conflictingAlts != null && this.userWantsCtxSensitive; if (attemptFullContext) { // Only exact conflicts are known to be ambiguous when local // prediction does not step out of the decision rule. attemptFullContext = !useContext && (D.configs.dipsIntoOuterContext || !D.configs.isExactConflict) && (!this.treat_sllk1_conflict_as_ambiguity || input.index !== startIndex); } if (D.configs.hasSemanticContext) { let predPredictions = D.predicates; if (predPredictions != null) { let conflictIndex = input.index; if (conflictIndex !== startIndex) { input.seek(startIndex); } // use complete evaluation here if we'll want to retry with full context if still ambiguous conflictingAlts = this.evalSemanticContext(predPredictions, outerContext, attemptFullContext || this.reportAmbiguities); switch (conflictingAlts.cardinality()) { case 0: throw this.noViableAlt(input, outerContext, D.configs, startIndex); case 1: return conflictingAlts.nextSetBit(0); default: break; } if (conflictIndex !== startIndex) { // restore the index so reporting the fallback to full // context occurs with the index at the correct spot input.seek(conflictIndex); } } } if (!attemptFullContext) { if (conflictingAlts != null) { if (this.reportAmbiguities && conflictingAlts.cardinality() > 1) { this.reportAmbiguity(dfa, D, startIndex, input.index, D.configs.isExactConflict, conflictingAlts, D.configs); } predictedAlt = conflictingAlts.nextSetBit(0); } return predictedAlt; } else { assert(!useContext); assert(this.isAcceptState(D, false)); if (ParserATNSimulator.debug) { console.log("RETRY with outerContext=" + outerContext); } let fullContextState = this.computeStartState(dfa, outerContext, true); if (this.reportAmbiguities) { this.reportAttemptingFullContext(dfa, conflictingAlts, nextState, startIndex, input.index); } input.seek(startIndex); return this.execATN(dfa, input, startIndex, fullContextState); } } previous = nextState; if (t !== IntStream_1.IntStream.EOF) { input.consume(); t = input.LA(1); } } } /** * This method is used to improve the localization of error messages by * choosing an alternative rather than throwing a * {@link NoViableAltException} in particular prediction scenarios where the * {@link #ERROR} state was reached during ATN simulation. * * The default implementation of this method uses the following * algorithm to identify an ATN configuration which successfully parsed the * decision entry rule. Choosing such an alternative ensures that the * {@link ParserRuleContext} returned by the calling rule will be complete * and valid, and the syntax error will be reported later at a more * localized location. * * * If no configuration in `configs` reached the end of the * decision rule, return {@link ATN#INVALID_ALT_NUMBER}. * * If all configurations in `configs` which reached the end of the * decision rule predict the same alternative, return that alternative. * * If the configurations in `configs` which reached the end of the * decision rule predict multiple alternatives (call this *S*), * choose an alternative in the following order. * * 1. Filter the configurations in `configs` to only those * configurations which remain viable after evaluating semantic predicates. * If the set of these filtered configurations which also reached the end of * the decision rule is not empty, return the minimum alternative * represented in this set. * 1. Otherwise, choose the minimum alternative in *S*. * * In some scenarios, the algorithm described above could predict an * alternative which will result in a {@link FailedPredicateException} in * parser. Specifically, this could occur if the *only* configuration * capable of successfully parsing to the end of the decision rule is * blocked by a semantic predicate. By choosing this alternative within * {@link #adaptivePredict} instead of throwing a * {@link NoViableAltException}, the resulting * {@link FailedPredicateException} in the parser will identify the specific * predicate which is preventing the parser from successfully parsing the * decision rule, which helps developers identify and correct logic errors * in semantic predicates. * * @param input The input {@link TokenStream} * @param startIndex The start index for the current prediction, which is * the input index where any semantic context in `configs` should be * evaluated * @param previous The ATN simulation state immediately before the * {@link #ERROR} state was reached * * @returns The value to return from {@link #adaptivePredict}, or * {@link ATN#INVALID_ALT_NUMBER} if a suitable alternative was not * identified and {@link #adaptivePredict} should report an error instead. */ handleNoViableAlt(input, startIndex, previous) { if (previous.s0 != null) { let alts = new BitSet_1.BitSet(); let maxAlt = 0; for (let config of previous.s0.configs) { if (config.reachesIntoOuterContext || config.state instanceof RuleStopState_1.RuleStopState) { alts.set(config.alt); maxAlt = Math.max(maxAlt, config.alt); } } switch (alts.cardinality()) { case 0: break; case 1: return alts.nextSetBit(0); default: if (!previous.s0.configs.hasSemanticContext) { // configs doesn't contain any predicates, so the predicate // filtering code below would be pointless return alts.nextSetBit(0); } /* * Try to find a configuration set that not only dipped into the outer * context, but also isn't eliminated by a predicate. */ let filteredConfigs = new ATNConfigSet_1.ATNConfigSet(); for (let config of previous.s0.configs) { if (config.reachesIntoOuterContext || config.state instanceof RuleStopState_1.RuleStopState) { filteredConfigs.add(config); } } /* The following code blocks are adapted from predicateDFAState with * the following key changes. * * 1. The code operates on an ATNConfigSet rather than a DFAState. * 2. Predicates are collected for all alternatives represented in * filteredConfigs, rather than restricting the evaluation to * conflicting and/or unique configurations. */ let altToPred = this.getPredsForAmbigAlts(alts, filteredConfigs, maxAlt); if (altToPred != null) { let predicates = this.getPredicatePredictions(alts, altToPred); if (predicates != null) { let stopIndex = input.index; try { input.seek(startIndex); let filteredAlts = this.evalSemanticContext(predicates, previous.outerContext, false); if (!filteredAlts.isEmpty) { return filteredAlts.nextSetBit(0); } } finally { input.seek(stopIndex); } } } return alts.nextSetBit(0); } } throw this.noViableAlt(input, previous.outerContext, previous.s0.configs, startIndex); } computeReachSet(dfa, previous, t, contextCache) { let useContext = previous.useContext; let remainingGlobalContext = previous.remainingOuterContext; let s = previous.s0; if (useContext) { while (s.isContextSymbol(t)) { let next; if (remainingGlobalContext != null) { remainingGlobalContext = this.skipTailCalls(remainingGlobalContext); next = s.getContextTarget(this.getReturnState(remainingGlobalContext)); } if (next == null) { break; } assert(remainingGlobalContext != null); remainingGlobalContext = remainingGlobalContext.parent; s = next; } } assert(!this.isAcceptState(s, useContext)); if (this.isAcceptState(s, useContext)) { return new SimulatorState_1.SimulatorState(previous.outerContext, s, useContext, remainingGlobalContext); } let s0 = s; let target = this.getExistingTargetState(s0, t); if (target == null) { let result = this.computeTargetState(dfa, s0, remainingGlobalContext, t, useContext, contextCache); target = result[0]; remainingGlobalContext = result[1]; } if (target === ATNSimulator_1.ATNSimulator.ERROR) { return undefined; } assert(!useContext || !target.configs.dipsIntoOuterContext); return new SimulatorState_1.SimulatorState(previous.outerContext, target, useContext, remainingGlobalContext); } /** * Get an existing target state for an edge in the DFA. If the target state * for the edge has not yet been computed or is otherwise not available, * this method returns `undefined`. * * @param s The current DFA state * @param t The next input symbol * @returns The existing target DFA state for the given input symbol * `t`, or `undefined` if the target state for this edge is not * already cached */ getExistingTargetState(s, t) { return s.getTarget(t); } /** * Compute a target state for an edge in the DFA, and attempt to add the * computed state and corresponding edge to the DFA. * * @param dfa * @param s The current DFA state * @param remainingGlobalContext * @param t The next input symbol * @param useContext * @param contextCache * * @returns The computed target DFA state for the given input symbol * `t`. If `t` does not lead to a valid DFA state, this method * returns {@link #ERROR}. */ computeTargetState(dfa, s, remainingGlobalContext, t, useContext, contextCache) { let closureConfigs = s.configs.toArray(); let contextElements; let reach = new ATNConfigSet_1.ATNConfigSet(); let stepIntoGlobal; do { let hasMoreContext = !useContext || remainingGlobalContext != null; if (!hasMoreContext) { reach.isOutermostConfigSet = true; } let reachIntermediate = new ATNConfigSet_1.ATNConfigSet(); /* Configurations already in a rule stop state indicate reaching the end * of the decision rule (local context) or end of the start rule (full * context). Once reached, these configurations are never updated by a * closure operation, so they are handled separately for the performance * advantage of having a smaller intermediate set when calling closure. * * For full-context reach operations, separate handling is required to * ensure that the alternative matching the longest overall sequence is * chosen when multiple such configurations can match the input. */ let skippedStopStates; for (let c of closureConfigs) { if (ParserATNSimulator.debug) { console.log("testing " + this.getTokenName(t) + " at " + c.toString()); } if (c.state instanceof RuleStopState_1.RuleStopState) { assert(c.context.isEmpty); if (useContext && !c.reachesIntoOuterContext || t === IntStream_1.IntStream.EOF) { if (skippedStopStates == null) { skippedStopStates = []; } skippedStopStates.push(c); } continue; } let n = c.state.numberOfOptimizedTransitions; for (let ti = 0; ti < n; ti++) { // for each optimized transition let trans = c.state.getOptimizedTransition(ti); let target = this.getReachableTarget(c, trans, t); if (target != null) { reachIntermediate.add(c.transform(target, false), contextCache); } } } /* This block optimizes the reach operation for intermediate sets which