bitmark-grammar
Version:
265 lines (242 loc) • 9.52 kB
text/typescript
/*!
* 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.
*/
// ConvertTo-TS run at 2016-10-04T11:26:30.4445360-07:00
import { AbstractPredicateTransition } from "./AbstractPredicateTransition";
import { Array2DHashSet } from "../misc/Array2DHashSet";
import { ATN } from "./ATN";
import { ATNConfig } from "./ATNConfig";
import { ATNState } from "./ATNState";
import { BitSet } from "../misc/BitSet";
import { IntervalSet } from "../misc/IntervalSet";
import { NotNull } from "../Decorators";
import { NotSetTransition } from "./NotSetTransition";
import { ObjectEqualityComparator } from "../misc/ObjectEqualityComparator";
import { PredictionContext } from "./PredictionContext";
import { RuleStopState } from "./RuleStopState";
import { RuleTransition } from "./RuleTransition";
import { SetTransition } from "./SetTransition";
import { Token } from "../Token";
import { Transition } from "./Transition";
import { WildcardTransition } from "./WildcardTransition";
export class LL1Analyzer {
/** Special value added to the lookahead sets to indicate that we hit
* a predicate during analysis if `seeThruPreds==false`.
*/
public static readonly HIT_PRED: number = Token.INVALID_TYPE;
public atn: ATN;
constructor( atn: ATN) { this.atn = atn; }
/**
* Calculates the SLL(1) expected lookahead set for each outgoing transition
* of an {@link ATNState}. The returned array has one element for each
* outgoing transition in `s`. If the closure from transition
* *i* leads to a semantic predicate before matching a symbol, the
* element at index *i* of the result will be `undefined`.
*
* @param s the ATN state
* @returns the expected symbols for each outgoing transition of `s`.
*/
public getDecisionLookahead(s: ATNState | undefined): Array<IntervalSet | undefined> | undefined {
// System.out.println("LOOK("+s.stateNumber+")");
if (s == null) {
return undefined;
}
let look: Array<IntervalSet | undefined> = new Array<IntervalSet>(s.numberOfTransitions);
for (let alt = 0; alt < s.numberOfTransitions; alt++) {
let current: IntervalSet | undefined = new IntervalSet();
look[alt] = current;
let lookBusy: Array2DHashSet<ATNConfig> = new Array2DHashSet<ATNConfig>(ObjectEqualityComparator.INSTANCE);
let seeThruPreds: boolean = false; // fail to get lookahead upon pred
this._LOOK(s.transition(alt).target, undefined, PredictionContext.EMPTY_LOCAL,
current, lookBusy, new BitSet(), seeThruPreds, false);
// Wipe out lookahead for this alternative if we found nothing
// or we had a predicate when we !seeThruPreds
if (current.size === 0 || current.contains(LL1Analyzer.HIT_PRED)) {
current = undefined;
look[alt] = current;
}
}
return look;
}
/**
* Compute set of tokens that can follow `s` in the ATN in the
* specified `ctx`.
*
* If `ctx` is `undefined` and the end of the rule containing
* `s` is reached, {@link Token#EPSILON} is added to the result set.
* If `ctx` is not `undefined` and the end of the outermost rule is
* reached, {@link Token#EOF} is added to the result set.
*
* @param s the ATN state
* @param ctx the complete parser context, or `undefined` if the context
* should be ignored
*
* @returns The set of tokens that can follow `s` in the ATN in the
* specified `ctx`.
*/
// @NotNull
public LOOK(/*@NotNull*/ s: ATNState, /*@NotNull*/ ctx: PredictionContext): IntervalSet;
/**
* Compute set of tokens that can follow `s` in the ATN in the
* specified `ctx`.
*
* If `ctx` is `undefined` and the end of the rule containing
* `s` is reached, {@link Token#EPSILON} is added to the result set.
* If `ctx` is not `PredictionContext#EMPTY_LOCAL` and the end of the outermost rule is
* reached, {@link Token#EOF} is added to the result set.
*
* @param s the ATN state
* @param stopState the ATN state to stop at. This can be a
* {@link BlockEndState} to detect epsilon paths through a closure.
* @param ctx the complete parser context, or `undefined` if the context
* should be ignored
*
* @returns The set of tokens that can follow `s` in the ATN in the
* specified `ctx`.
*/
// @NotNull
public LOOK(/*@NotNull*/ s: ATNState, /*@NotNull*/ ctx: PredictionContext, stopState: ATNState | null): IntervalSet;
public LOOK( s: ATNState, ctx: PredictionContext, stopState?: ATNState | null): IntervalSet {
if (stopState === undefined) {
if (s.atn == null) {
throw new Error("Illegal state");
}
stopState = s.atn.ruleToStopState[s.ruleIndex];
} else if (stopState === null) {
// This is an explicit request to pass undefined as the stopState to _LOOK. Used to distinguish an overload
// from the method which simply omits the stopState parameter.
stopState = undefined;
}
let r: IntervalSet = new IntervalSet();
let seeThruPreds: boolean = true; // ignore preds; get all lookahead
let addEOF: boolean = true;
this._LOOK(s, stopState, ctx, r, new Array2DHashSet<ATNConfig>(), new BitSet(), seeThruPreds, addEOF);
return r;
}
/**
* Compute set of tokens that can follow `s` in the ATN in the
* specified `ctx`.
* <p/>
* If `ctx` is {@link PredictionContext#EMPTY_LOCAL} and
* `stopState` or the end of the rule containing `s` is reached,
* {@link Token#EPSILON} is added to the result set. If `ctx` is not
* {@link PredictionContext#EMPTY_LOCAL} and `addEOF` is `true`
* and `stopState` or the end of the outermost rule is reached,
* {@link Token#EOF} is added to the result set.
*
* @param s the ATN state.
* @param stopState the ATN state to stop at. This can be a
* {@link BlockEndState} to detect epsilon paths through a closure.
* @param ctx The outer context, or {@link PredictionContext#EMPTY_LOCAL} if
* the outer context should not be used.
* @param look The result lookahead set.
* @param lookBusy A set used for preventing epsilon closures in the ATN
* from causing a stack overflow. Outside code should pass
* `new HashSet<ATNConfig>` for this argument.
* @param calledRuleStack A set used for preventing left recursion in the
* ATN from causing a stack overflow. Outside code should pass
* `new BitSet()` for this argument.
* @param seeThruPreds `true` to true semantic predicates as
* implicitly `true` and "see through them", otherwise `false`
* to treat semantic predicates as opaque and add {@link #HIT_PRED} to the
* result if one is encountered.
* @param addEOF Add {@link Token#EOF} to the result if the end of the
* outermost context is reached. This parameter has no effect if `ctx`
* is {@link PredictionContext#EMPTY_LOCAL}.
*/
protected _LOOK(
s: ATNState,
stopState: ATNState | undefined,
ctx: PredictionContext,
look: IntervalSet,
lookBusy: Array2DHashSet<ATNConfig>,
calledRuleStack: BitSet,
seeThruPreds: boolean,
addEOF: boolean): void {
// System.out.println("_LOOK("+s.stateNumber+", ctx="+ctx);
let c: ATNConfig = ATNConfig.create(s, 0, ctx);
if (!lookBusy.add(c)) {
return;
}
if (s === stopState) {
if (PredictionContext.isEmptyLocal(ctx)) {
look.add(Token.EPSILON);
return;
} else if (ctx.isEmpty) {
if (addEOF) {
look.add(Token.EOF);
}
return;
}
}
if (s instanceof RuleStopState) {
if (ctx.isEmpty && !PredictionContext.isEmptyLocal(ctx)) {
if (addEOF) {
look.add(Token.EOF);
}
return;
}
let removed: boolean = calledRuleStack.get(s.ruleIndex);
try {
calledRuleStack.clear(s.ruleIndex);
for (let i = 0; i < ctx.size; i++) {
if (ctx.getReturnState(i) === PredictionContext.EMPTY_FULL_STATE_KEY) {
continue;
}
let returnState: ATNState = this.atn.states[ctx.getReturnState(i)];
// System.out.println("popping back to "+retState);
this._LOOK(returnState, stopState, ctx.getParent(i), look, lookBusy, calledRuleStack, seeThruPreds, addEOF);
}
}
finally {
if (removed) {
calledRuleStack.set(s.ruleIndex);
}
}
}
let n: number = s.numberOfTransitions;
for (let i = 0; i < n; i++) {
let t: Transition = s.transition(i);
if (t instanceof RuleTransition) {
if (calledRuleStack.get(t.ruleIndex)) {
continue;
}
let newContext: PredictionContext = ctx.getChild(t.followState.stateNumber);
try {
calledRuleStack.set(t.ruleIndex);
this._LOOK(t.target, stopState, newContext, look, lookBusy, calledRuleStack, seeThruPreds, addEOF);
}
finally {
calledRuleStack.clear(t.ruleIndex);
}
}
else if (t instanceof AbstractPredicateTransition) {
if (seeThruPreds) {
this._LOOK(t.target, stopState, ctx, look, lookBusy, calledRuleStack, seeThruPreds, addEOF);
}
else {
look.add(LL1Analyzer.HIT_PRED);
}
}
else if (t.isEpsilon) {
this._LOOK(t.target, stopState, ctx, look, lookBusy, calledRuleStack, seeThruPreds, addEOF);
}
else if (t instanceof WildcardTransition) {
look.addAll(IntervalSet.of(Token.MIN_USER_TOKEN_TYPE, this.atn.maxTokenType));
}
else {
// System.out.println("adding "+ t);
let set: IntervalSet | undefined = t.label;
if (set != null) {
if (t instanceof NotSetTransition) {
set = set.complement(IntervalSet.of(Token.MIN_USER_TOKEN_TYPE, this.atn.maxTokenType));
}
look.addAll(set);
}
}
}
}
}