Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Javascript: migrate prototypical DFA objects to es6 classes #2746

Merged
merged 11 commits into from
Feb 12, 2020
269 changes: 139 additions & 130 deletions runtime/JavaScript/src/antlr4/dfa/DFA.js
Original file line number Diff line number Diff line change
@@ -1,153 +1,162 @@
//
/* Copyright (c) 2012-2017 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.
*/

var Set = require("../Utils").Set;
var DFAState = require('./DFAState').DFAState;
var StarLoopEntryState = require('../atn/ATNState').StarLoopEntryState;
var ATNConfigSet = require('./../atn/ATNConfigSet').ATNConfigSet;
var DFASerializer = require('./DFASerializer').DFASerializer;
var LexerDFASerializer = require('./DFASerializer').LexerDFASerializer;

const {Set} = require("../Utils");
const {DFAState} = require('./DFAState');
const {StarLoopEntryState} = require('../atn/ATNState');
const {ATNConfigSet} = require('./../atn/ATNConfigSet');
const {DFASerializer} = require('./DFASerializer');
const {LexerDFASerializer} = require('./DFASerializer');

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 Set();
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;
}
}
}

function DFA(atnStartState, decision) {
if (decision === undefined) {
decision = 0;
/**
* 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;
}
// 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 Set();
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;
var precedenceState = new DFAState(null, new ATNConfigSet());
precedenceState.edges = [];
precedenceState.isAcceptState = false;
precedenceState.requiresFullContext = false;
this.s0 = precedenceState;
}
}
return this;
}

// 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()
/**
* 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;
}

DFA.prototype.getPrecedenceStartState = function(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;
/**
* 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;
}
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()
//
DFA.prototype.setPrecedenceStartState = function(precedence, startState) {
if (!(this.precedenceDfa)) {
throw ("Only precedence DFAs may contain a precedence start state.");
}
if (precedence < 0) {
return;
/**
* 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 DFAStatesSet();
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;
}
}

// 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}
/**
* 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;
});
}

DFA.prototype.setPrecedenceDfa = function(precedenceDfa) {
if (this.precedenceDfa!==precedenceDfa) {
this._states = new DFAStatesSet();
if (precedenceDfa) {
var precedenceState = new DFAState(null, new ATNConfigSet());
precedenceState.edges = [];
precedenceState.isAcceptState = false;
precedenceState.requiresFullContext = false;
this.s0 = precedenceState;
} else {
this.s0 = null;
toString(literalNames, symbolicNames) {
literalNames = literalNames || null;
symbolicNames = symbolicNames || null;
if (this.s0 === null) {
return "";
}
this.precedenceDfa = precedenceDfa;
const serializer = new DFASerializer(this, literalNames, symbolicNames);
return serializer.toString();
}
};

Object.defineProperty(DFA.prototype, "states", {
get : function() {
return this._states;
toLexerString() {
if (this.s0 === null) {
return "";
}
const serializer = new LexerDFASerializer(this);
return serializer.toString();
}
});

// Return a list of all states in this DFA, ordered by state number.
DFA.prototype.sortedStates = function() {
var list = this._states.values();
return list.sort(function(a, b) {
return a.stateNumber - b.stateNumber;
});
};

DFA.prototype.toString = function(literalNames, symbolicNames) {
literalNames = literalNames || null;
symbolicNames = symbolicNames || null;
if (this.s0 === null) {
return "";
get states(){
return this._states;
}
var serializer = new DFASerializer(this, literalNames, symbolicNames);
return serializer.toString();
};
}

DFA.prototype.toLexerString = function() {
if (this.s0 === null) {
return "";
}
var serializer = new LexerDFASerializer(this);
return serializer.toString();
};

exports.DFA = DFA;
module.exports = { DFA };
Loading