@azure/cosmos-language-service
Version:
Cosmos DB SQL Language Service for the Monaco editor
299 lines (251 loc) • 12.9 kB
text/typescript
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
import * as ATNState from "antlr4/atn/ATNState";
import * as Transition from "antlr4/atn/Transition";
import { ATN } from "antlr4/atn/ATN";
import { CommonTokenStream } from "antlr4/CommonTokenStream";
import { DFA } from "antlr4/dfa/DFA";
import { LanguageService } from "./LanguageService";
import { NoViableAltException } from "antlr4/error/Errors";
import { Parser } from "antlr4/Parser";
import { ParserATNSimulator } from "antlr4/atn/ParserATNSimulator";
import { PredictionContextCache } from "antlr4/PredictionContext";
import { PredictionMode } from "antlr4/atn/PredictionMode";
import { RuleContext } from "antlr4/RuleContext";
import { Token } from "antlr4/Token";
import { Utils } from "./Utils";
interface StateWithTransitionPath {
state : ATNState.ATNState,
transitionStates : ATNState.ATNState[]
}
export class LSParserATNSimulator extends ParserATNSimulator {
private predictionMode = PredictionMode.LL;
private parser : Parser;
private atn : ATN;
private languageService : LanguageService;
constructor(parser : Parser, atn : ATN, decisionToDFA : Array<DFA>, sharedContextCache : PredictionContextCache, languageService : LanguageService) {
super(parser, atn, decisionToDFA, sharedContextCache);
this.parser = parser;
this.atn = atn;
this.languageService = languageService;
}
public adaptivePredict(input : CommonTokenStream, decision : number, outerContext : RuleContext) {
let tokensLeft : number = -1;
try {
this.languageService.IsInPredict = true;
this.languageService.EofReachedInPredict = false;
if (decision >= 0) {
return super.adaptivePredict(input, decision, outerContext);
}
}
catch(error) {
if (error instanceof NoViableAltException && error.offendingToken.type === Token.EOF) {
tokensLeft = error.offendingToken.tokenIndex - this.parser.getCurrentToken().tokenIndex;
return 1;
} else {
throw error;
}
}
finally {
if (this.languageService.EofReachedInPredict) {
if (tokensLeft < 0) {
tokensLeft = 0;
while (input.LA(tokensLeft + 1) != Token.EOF) {
tokensLeft++;
}
}
if (tokensLeft > 0) {
let states = this.CalculateValidStates(input, tokensLeft);
this.languageService.RecordErrorStatesBeforeEof(states);
}
}
this.languageService.IsInPredict = false;
}
}
private CalculateValidStates(input : CommonTokenStream, tokensLeft : number): ATNState.ATNState[] {
let state = this.atn.states[this.parser.state];
let states : StateWithTransitionPath[] = [ {
state : state,
transitionStates : []
} ];
let validStates : StateWithTransitionPath[] = [];
// one step each time. Consume a single token each time.
for (let index = 1; index <= tokensLeft; index++) {
let _states : StateWithTransitionPath[] = [];
let nextToken : number = input.LA(index);
states.forEach(s => { _states = _states.concat(this.ConsumeSingleTokenAhead(s, nextToken)).filter(Utils.notDuplicate); });
states = _states.filter(Utils.notDuplicate);
}
states.forEach(s => { validStates = validStates.concat(this.SearchValidStates(s)); });
return validStates.map(s => s.state).filter(Utils.notDuplicate);
}
private ConsumeSingleTokenAhead(stateWithTransitionPath : StateWithTransitionPath, matchToken : Token) : StateWithTransitionPath[] {
let validStates : StateWithTransitionPath[] = [];
let currentState = stateWithTransitionPath.state;
let nextStateWithTransitionPath : StateWithTransitionPath = {
state : null, // Temporary null
transitionStates : stateWithTransitionPath.transitionStates.slice()
};
if(nextStateWithTransitionPath.transitionStates.length > 0 &&
nextStateWithTransitionPath.transitionStates[nextStateWithTransitionPath.transitionStates.length - 1].ruleIndex === currentState.ruleIndex) {
nextStateWithTransitionPath.transitionStates.pop();
}
nextStateWithTransitionPath.transitionStates.push(currentState);
if (!(currentState instanceof ATNState.RuleStopState)) {
for (let index = 0;index < currentState.transitions.length;index++) {
let transition = currentState.transitions[index];
let destinationChildState = transition.target;
nextStateWithTransitionPath.state = destinationChildState;
if (!transition.isEpsilon) {
if (transition.label != null && transition.label.contains(matchToken)) {
validStates = validStates.concat(this.SearchValidStates(nextStateWithTransitionPath));
}
} else {
validStates = validStates.concat(this.ConsumeSingleTokenAhead(nextStateWithTransitionPath, matchToken)).filter(Utils.notDuplicate);
}
}
}
return validStates.filter(Utils.notEmpty);
}
private SearchValidStates(stateWithTransitionPath : StateWithTransitionPath) : StateWithTransitionPath[] {
let validStates : StateWithTransitionPath[] = [];
if (!this.IsLastStateBeforeRuleStopState(stateWithTransitionPath.state)) {
validStates.push(stateWithTransitionPath);
} else {
validStates = this.BackTracingAndFindActiveStates(stateWithTransitionPath).filter(Utils.notDuplicate);
if (this.HasActiveChildrenState(stateWithTransitionPath.state)) {
validStates.push(stateWithTransitionPath);
}
}
return validStates;
}
private BackTracingAndFindActiveStates(stateWithTransitionPath : StateWithTransitionPath) : StateWithTransitionPath[] {
let validStates : StateWithTransitionPath[] = [];
let completedRuleIndex = stateWithTransitionPath.state.ruleIndex;
let statesStack = this.GetLastStateInDifferentRulesFomStatesStack(stateWithTransitionPath.transitionStates, completedRuleIndex);
let currentStateIndex = statesStack.length - 1;
let keepBackTracing : boolean = true;
while (keepBackTracing && currentStateIndex >= 0) {
let currentState = statesStack[currentStateIndex];
keepBackTracing = false;
let followingStates = this.GetRuleFollowingState(currentState, completedRuleIndex);
for (let index = 0;index < followingStates.length; index++) {
let lastStateBeforeRuleStopState : boolean = false;
let haveActiveChildrenStatesInCurrentRule : boolean = false;
let transitions = followingStates[index].transitions;
while (transitions.length > 0){
let epsilonTrans = [];
for (let tIndex = 0;tIndex < transitions.length; tIndex++) {
if (transitions[tIndex].isEpsilon) {
if (transitions[tIndex] instanceof Transition.RuleTransition) {
haveActiveChildrenStatesInCurrentRule = true;
} else if (transitions[tIndex].target instanceof ATNState.RuleStopState) {
lastStateBeforeRuleStopState = true;
} else {
epsilonTrans = epsilonTrans.concat(transitions[tIndex].target.transitions);
}
} else {
haveActiveChildrenStatesInCurrentRule = true;
}
}
transitions = epsilonTrans;
if (lastStateBeforeRuleStopState && haveActiveChildrenStatesInCurrentRule) {
// We can jump out of loop ahead of schedule.
break;
}
}
if (lastStateBeforeRuleStopState) {
keepBackTracing = true;
}
if (haveActiveChildrenStatesInCurrentRule) {
//validStates.push(followingStates[index]);
let newValidState : StateWithTransitionPath = {
state : followingStates[index],
transitionStates : statesStack.slice(0, currentStateIndex + 1)
};
validStates.push(newValidState);
}
}
currentStateIndex--;
if(keepBackTracing) {
completedRuleIndex = followingStates[0].ruleIndex;
}
}
return validStates.filter(Utils.notEmpty);
}
private GetLastStateInDifferentRulesFomStatesStack(statesStack : ATNState.ATNState[], lastMatchedRuleIndex : number) : ATNState.ATNState[] {
let lastStates : ATNState.ATNState[] = [];
let matchedRuleIndex = lastMatchedRuleIndex;
for(let currentStateIndex = statesStack.length - 1; currentStateIndex >= 0; currentStateIndex--) {
if(statesStack[currentStateIndex].ruleIndex === matchedRuleIndex) {
continue;
} else {
lastStates.push(statesStack[currentStateIndex]);
matchedRuleIndex = statesStack[currentStateIndex].ruleIndex;
}
}
lastStates.reverse();
return lastStates.filter(Utils.notEmpty);
}
private GetRuleFollowingState(state : ATNState.ATNState, ruleIndex : number) : ATNState.ATNState[] {
let followingStates : ATNState.ATNState[] = [];
if(state instanceof ATNState.RuleStopState) {
return followingStates;
}
let transitions = state.transitions;
while(transitions.length > 0) {
let epsilonTrans = [];
for (let index = 0;index < transitions.length;index++) {
if (transitions[index].isEpsilon) {
if (transitions[index] instanceof Transition.RuleTransition) {
if (transitions[index].ruleIndex === ruleIndex) {
followingStates.push(transitions[index].followState);
}
} else if (!(transitions[index].target instanceof ATNState.RuleStopState)) {
epsilonTrans = epsilonTrans.concat(transitions[index].target.transitions);
}
}
}
transitions = epsilonTrans;
}
return followingStates.filter(Utils.notEmpty);
}
// Means with this state, parser can make up a complete rule.
private IsLastStateBeforeRuleStopState(state : ATNState.ATNState) {
let transitions = state.transitions;
while(transitions.length > 0) {
let epsilonTrans = [];
for (let index = 0;index < transitions.length;index++) {
if (transitions[index].isEpsilon) {
if (transitions[index].target instanceof ATNState.RuleStopState) {
return true;
} else if (!(transitions[index] instanceof Transition.RuleTransition)) {
epsilonTrans = epsilonTrans.concat(transitions[index].target.transitions);
}
}
}
transitions = epsilonTrans;
}
return false;
}
private HasActiveChildrenState(state : ATNState.ATNState) : boolean {
let transitions = state.transitions;
while(transitions.length > 0) {
let epsilonTrans = [];
for (let index = 0;index < transitions.length;index++) {
if (transitions[index].isEpsilon) {
if (transitions[index] instanceof Transition.RuleTransition) {
return true;
} else if (!(transitions[index].target instanceof ATNState.RuleStopState)) {
epsilonTrans = epsilonTrans.concat(transitions[index].target.transitions);
}
} else {
return true;
}
}
transitions = epsilonTrans;
}
return false;
}
}