bitmark-grammar
Version:
224 lines (193 loc) • 7.3 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:38.3567094-07:00
import { Array2DHashSet } from "../misc/Array2DHashSet";
import { ATN } from "../atn/ATN";
import { ATNConfigSet } from "../atn/ATNConfigSet";
import { ATNState } from "../atn/ATNState";
import { ATNType } from "../atn/ATNType";
import { DecisionState } from "../atn/DecisionState";
import { DFASerializer } from "./DFASerializer";
import { DFAState } from "./DFAState";
import { LexerATNSimulator } from "../atn/LexerATNSimulator";
import { LexerDFASerializer } from "./LexerDFASerializer";
import { NotNull } from "../Decorators";
import { ObjectEqualityComparator } from "../misc/ObjectEqualityComparator";
import { StarLoopEntryState } from "../atn/StarLoopEntryState";
import { Token } from "../Token";
import { TokensStartState } from "../atn/TokensStartState";
import { Vocabulary } from "../Vocabulary";
import { VocabularyImpl } from "../VocabularyImpl";
export class DFA {
/**
* A set of all states in the `DFA`.
*
* Note that this collection of states holds the DFA states for both SLL and LL prediction. Only the start state
* needs to be differentiated for these cases, which is tracked by the `s0` and `s0full` fields.
*/
public readonly states: Array2DHashSet<DFAState> = new Array2DHashSet<DFAState>(ObjectEqualityComparator.INSTANCE);
public s0: DFAState | undefined;
public s0full: DFAState | undefined;
public readonly decision: number;
/** From which ATN state did we create this DFA? */
public atnStartState: ATNState;
/**
* Note: this field is accessed as `atnStartState.atn` in other targets. The TypeScript target keeps a separate copy
* to avoid a number of additional null/undefined checks each time the ATN is accessed.
*/
public atn: ATN;
private nextStateNumber: number = 0;
/**
* `true` if this DFA is for a precedence decision; otherwise,
* `false`. This is the backing field for {@link #isPrecedenceDfa}.
*/
private precedenceDfa: boolean;
/**
* Constructs a `DFA` instance associated with a lexer mode.
*
* The start state for a `DFA` constructed with this constructor should be a `TokensStartState`, which is the start
* state for a lexer mode. The prediction made by this DFA determines the lexer rule which matches the current
* input.
*
* @param atnStartState The start state for the mode.
*/
constructor(atnStartState: TokensStartState);
/**
* Constructs a `DFA` instance associated with a decision.
*
* @param atnStartState The decision associated with this DFA.
* @param decision The decision number.
*/
constructor(atnStartState: DecisionState, decision: number);
constructor( atnStartState: ATNState, decision: number = 0) {
if (!atnStartState.atn) {
throw new Error("The ATNState must be associated with an ATN");
}
this.atnStartState = atnStartState;
this.atn = atnStartState.atn;
this.decision = decision;
// Precedence DFAs are associated with the special precedence decision created for left-recursive rules which
// evaluate their alternatives using a precedence hierarchy. When such a decision is encountered, we mark this
// DFA instance as a precedence DFA and initialize the initial states s0 and s0full to special DFAState
// instances which use outgoing edges to link to the actual start state used for each precedence level.
let isPrecedenceDfa: boolean = false;
if (atnStartState instanceof StarLoopEntryState) {
if (atnStartState.precedenceRuleDecision) {
isPrecedenceDfa = true;
this.s0 = new DFAState(new ATNConfigSet());
this.s0full = new DFAState(new ATNConfigSet());
}
}
this.precedenceDfa = isPrecedenceDfa;
}
/**
* Gets whether this DFA is a precedence DFA. Precedence DFAs use a special
* start state {@link #s0} which is not stored in {@link #states}. The
* {@link DFAState#edges} array for this start state contains outgoing edges
* supplying individual start states corresponding to specific precedence
* values.
*
* @returns `true` if this is a precedence DFA; otherwise,
* `false`.
* @see Parser.precedence
*/
get isPrecedenceDfa(): boolean {
return this.precedenceDfa;
}
/**
* Get the start state for a specific precedence value.
*
* @param precedence The current precedence.
* @returns The start state corresponding to the specified precedence, or
* `undefined` if no start state exists for the specified precedence.
*
* @ if this is not a precedence DFA.
* @see `isPrecedenceDfa`
*/
public getPrecedenceStartState(precedence: number, fullContext: boolean): DFAState | undefined {
if (!this.isPrecedenceDfa) {
throw new Error("Only precedence DFAs may contain a precedence start state.");
}
// s0 and s0full are never null for a precedence DFA
if (fullContext) {
return (this.s0full as DFAState).getTarget(precedence);
}
else {
return (this.s0 as DFAState).getTarget(precedence);
}
}
/**
* Set the start state for a specific precedence value.
*
* @param precedence The current precedence.
* @param startState The start state corresponding to the specified
* precedence.
*
* @ if this is not a precedence DFA.
* @see `isPrecedenceDfa`
*/
public setPrecedenceStartState(precedence: number, fullContext: boolean, startState: DFAState): void {
if (!this.isPrecedenceDfa) {
throw new Error("Only precedence DFAs may contain a precedence start state.");
}
if (precedence < 0) {
return;
}
if (fullContext) {
// s0full is never null for a precedence DFA
(this.s0full as DFAState).setTarget(precedence, startState);
}
else {
// s0 is never null for a precedence DFA
(this.s0 as DFAState).setTarget(precedence, startState);
}
}
get isEmpty(): boolean {
if (this.isPrecedenceDfa) {
// s0 and s0full are never null for a precedence DFA
return this.s0!.getEdgeMap().size === 0 && this.s0full!.getEdgeMap().size === 0;
}
return this.s0 == null && this.s0full == null;
}
get isContextSensitive(): boolean {
if (this.isPrecedenceDfa) {
// s0full is never null for a precedence DFA
return (this.s0full as DFAState).getEdgeMap().size > 0;
}
return this.s0full != null;
}
public addState(state: DFAState): DFAState {
state.stateNumber = this.nextStateNumber++;
return this.states.getOrAdd(state);
}
public toString(): string;
public toString(/*@NotNull*/ vocabulary: Vocabulary): string;
public toString(/*@NotNull*/ vocabulary: Vocabulary, ruleNames: string[] | undefined): string;
public toString(vocabulary?: Vocabulary, ruleNames?: string[]): string {
if (!vocabulary) {
vocabulary = VocabularyImpl.EMPTY_VOCABULARY;
}
if (!this.s0) {
return "";
}
let serializer: DFASerializer;
if (ruleNames) {
serializer = new DFASerializer(this, vocabulary, ruleNames, this.atnStartState.atn);
} else {
serializer = new DFASerializer(this, vocabulary);
}
return serializer.toString();
}
public toLexerString(): string {
if (!this.s0) {
return "";
}
let serializer: DFASerializer = new LexerDFASerializer(this);
return serializer.toString();
}
}