antlr4-runtime
Version:
JavaScript runtime for ANTLR4
160 lines (149 loc) • 4.84 kB
JavaScript
/* Copyright (c) 2012-2022 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
import DFAState from './DFAState.js';
import StarLoopEntryState from '../state/StarLoopEntryState.js';
import ATNConfigSet from './../atn/ATNConfigSet.js';
import DFASerializer from './DFASerializer.js';
import LexerDFASerializer from './LexerDFASerializer.js';
import HashSet from "../misc/HashSet.js";
export default class DFA {
constructor(atnStartState, decision) {
if (decision === undefined) {
decision = 0;
}
/**
* From which ATN state did we create this DFA?
*/
this.atnStartState = atnStartState;
this.decision = decision;
/**
* A set of all DFA states. Use {@link Map} so we can get old state back
* ({@link Set} only allows you to see if it's there).
*/
this._states = new HashSet();
this.s0 = null;
/**
* {@code true} if this DFA is for a precedence decision; otherwise,
* {@code false}. This is the backing field for {@link //isPrecedenceDfa},
* {@link //setPrecedenceDfa}
*/
this.precedenceDfa = false;
if (atnStartState instanceof StarLoopEntryState)
{
if (atnStartState.isPrecedenceDecision) {
this.precedenceDfa = true;
const precedenceState = new DFAState(null, new ATNConfigSet());
precedenceState.edges = [];
precedenceState.isAcceptState = false;
precedenceState.requiresFullContext = false;
this.s0 = precedenceState;
}
}
}
/**
* Get the start state for a specific precedence value.
*
* @param precedence The current precedence.
* @return The start state corresponding to the specified precedence, or
* {@code null} if no start state exists for the specified precedence.
*
* @throws IllegalStateException if this is not a precedence DFA.
* @see //isPrecedenceDfa()
*/
getPrecedenceStartState(precedence) {
if (!(this.precedenceDfa)) {
throw ("Only precedence DFAs may contain a precedence start state.");
}
// s0.edges is never null for a precedence DFA
if (precedence < 0 || precedence >= this.s0.edges.length) {
return null;
}
return this.s0.edges[precedence] || null;
}
/**
* Set the start state for a specific precedence value.
*
* @param precedence The current precedence.
* @param startState The start state corresponding to the specified
* precedence.
*
* @throws IllegalStateException if this is not a precedence DFA.
* @see //isPrecedenceDfa()
*/
setPrecedenceStartState(precedence, startState) {
if (!(this.precedenceDfa)) {
throw ("Only precedence DFAs may contain a precedence start state.");
}
if (precedence < 0) {
return;
}
/**
* synchronization on s0 here is ok. when the DFA is turned into a
* precedence DFA, s0 will be initialized once and not updated again
* s0.edges is never null for a precedence DFA
*/
this.s0.edges[precedence] = startState;
}
/**
* Sets whether this is a precedence DFA. If the specified value differs
* from the current DFA configuration, the following actions are taken;
* otherwise no changes are made to the current DFA.
*
* <ul>
* <li>The {@link //states} map is cleared</li>
* <li>If {@code precedenceDfa} is {@code false}, the initial state
* {@link //s0} is set to {@code null}; otherwise, it is initialized to a new
* {@link DFAState} with an empty outgoing {@link DFAState//edges} array to
* store the start states for individual precedence values.</li>
* <li>The {@link //precedenceDfa} field is updated</li>
* </ul>
*
* @param precedenceDfa {@code true} if this is a precedence DFA; otherwise,
* {@code false}
*/
setPrecedenceDfa(precedenceDfa) {
if (this.precedenceDfa!==precedenceDfa) {
this._states = new HashSet();
if (precedenceDfa) {
const precedenceState = new DFAState(null, new ATNConfigSet());
precedenceState.edges = [];
precedenceState.isAcceptState = false;
precedenceState.requiresFullContext = false;
this.s0 = precedenceState;
} else {
this.s0 = null;
}
this.precedenceDfa = precedenceDfa;
}
}
/**
* Return a list of all states in this DFA, ordered by state number.
*/
sortedStates() {
const list = this._states.values();
return list.sort(function(a, b) {
return a.stateNumber - b.stateNumber;
});
}
toString(literalNames, symbolicNames) {
literalNames = literalNames || null;
symbolicNames = symbolicNames || null;
if (this.s0 === null) {
return "";
}
const serializer = new DFASerializer(this, literalNames, symbolicNames);
return serializer.toString();
}
toLexerString() {
if (this.s0 === null) {
return "";
}
const serializer = new LexerDFASerializer(this);
return serializer.toString();
}
get states(){
return this._states;
}
}