refactored LexerActionExecutor.js to use es6 classes

use const for better scoping
fix: dont wrap class in object for export
This commit is contained in:
Camilo Roca 2020-03-06 20:05:05 +01:00
parent 01c5dca26a
commit 9aeac6d4f4
2 changed files with 164 additions and 157 deletions

View File

@ -33,7 +33,7 @@ var SingletonPredictionContext = require('./../PredictionContext').SingletonPred
var RuleStopState = require('./ATNState').RuleStopState;
var LexerATNConfig = require('./ATNConfig').LexerATNConfig;
var Transition = require('./Transition').Transition;
var LexerActionExecutor = require('./LexerActionExecutor').LexerActionExecutor;
var LexerActionExecutor = require('./LexerActionExecutor');
var LexerNoViableAltException = require('./../error/Errors').LexerNoViableAltException;
function resetSimState(sim) {

View File

@ -1,166 +1,173 @@
//
/* 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.
*/
///
// Represents an executor for a sequence of lexer actions which traversed during
// the matching operation of a lexer rule (token).
//
// <p>The executor tracks position information for position-dependent lexer actions
// efficiently, ensuring that actions appearing only at the end of the rule do
// not cause bloating of the {@link DFA} created for the lexer.</p>
const {hashStuff} = require("../Utils");
const {LexerIndexedCustomAction} = require('./LexerAction');
var hashStuff = require("../Utils").hashStuff;
var LexerIndexedCustomAction = require('./LexerAction').LexerIndexedCustomAction;
class LexerActionExecutor {
/**
* Represents an executor for a sequence of lexer actions which traversed during
* the matching operation of a lexer rule (token).
*
* <p>The executor tracks position information for position-dependent lexer actions
* efficiently, ensuring that actions appearing only at the end of the rule do
* not cause bloating of the {@link DFA} created for the lexer.</p>
*/
constructor(lexerActions) {
this.lexerActions = lexerActions === null ? [] : lexerActions;
/**
* Caches the result of {@link //hashCode} since the hash code is an element
* of the performance-critical {@link LexerATNConfig//hashCode} operation
*/
this.cachedHashCode = hashStuff(lexerActions); // "".join([str(la) for la in
// lexerActions]))
return this;
}
function LexerActionExecutor(lexerActions) {
this.lexerActions = lexerActions === null ? [] : lexerActions;
// Caches the result of {@link //hashCode} since the hash code is an element
// of the performance-critical {@link LexerATNConfig//hashCode} operation.
this.cachedHashCode = hashStuff(lexerActions); // "".join([str(la) for la in
// lexerActions]))
return this;
/**
* Creates a {@link LexerActionExecutor} which encodes the current offset
* for position-dependent lexer actions.
*
* <p>Normally, when the executor encounters lexer actions where
* {@link LexerAction//isPositionDependent} returns {@code true}, it calls
* {@link IntStream//seek} on the input {@link CharStream} to set the input
* position to the <em>end</em> of the current token. This behavior provides
* for efficient DFA representation of lexer actions which appear at the end
* of a lexer rule, even when the lexer rule matches a variable number of
* characters.</p>
*
* <p>Prior to traversing a match transition in the ATN, the current offset
* from the token start index is assigned to all position-dependent lexer
* actions which have not already been assigned a fixed offset. By storing
* the offsets relative to the token start index, the DFA representation of
* lexer actions which appear in the middle of tokens remains efficient due
* to sharing among tokens of the same length, regardless of their absolute
* position in the input stream.</p>
*
* <p>If the current executor already has offsets assigned to all
* position-dependent lexer actions, the method returns {@code this}.</p>
*
* @param offset The current offset to assign to all position-dependent
* lexer actions which do not already have offsets assigned.
*
* @return {LexerActionExecutor} A {@link LexerActionExecutor} which stores input stream offsets
* for all position-dependent lexer actions.
*/
fixOffsetBeforeMatch(offset) {
let updatedLexerActions = null;
for (let i = 0; i < this.lexerActions.length; i++) {
if (this.lexerActions[i].isPositionDependent &&
!(this.lexerActions[i] instanceof LexerIndexedCustomAction)) {
if (updatedLexerActions === null) {
updatedLexerActions = this.lexerActions.concat([]);
}
updatedLexerActions[i] = new LexerIndexedCustomAction(offset,
this.lexerActions[i]);
}
}
if (updatedLexerActions === null) {
return this;
} else {
return new LexerActionExecutor(updatedLexerActions);
}
}
/**
* Execute the actions encapsulated by this executor within the context of a
* particular {@link Lexer}.
*
* <p>This method calls {@link IntStream//seek} to set the position of the
* {@code input} {@link CharStream} prior to calling
* {@link LexerAction//execute} on a position-dependent action. Before the
* method returns, the input position will be restored to the same position
* it was in when the method was invoked.</p>
*
* @param lexer The lexer instance.
* @param input The input stream which is the source for the current token.
* When this method is called, the current {@link IntStream//index} for
* {@code input} should be the start of the following token, i.e. 1
* character past the end of the current token.
* @param startIndex The token start index. This value may be passed to
* {@link IntStream//seek} to set the {@code input} position to the beginning
* of the token.
*/
execute(lexer, input, startIndex) {
let requiresSeek = false;
const stopIndex = input.index;
try {
for (let i = 0; i < this.lexerActions.length; i++) {
let lexerAction = this.lexerActions[i];
if (lexerAction instanceof LexerIndexedCustomAction) {
const offset = lexerAction.offset;
input.seek(startIndex + offset);
lexerAction = lexerAction.action;
requiresSeek = (startIndex + offset) !== stopIndex;
} else if (lexerAction.isPositionDependent) {
input.seek(stopIndex);
requiresSeek = false;
}
lexerAction.execute(lexer);
}
} finally {
if (requiresSeek) {
input.seek(stopIndex);
}
}
}
hashCode() {
return this.cachedHashCode;
}
updateHashCode(hash) {
hash.update(this.cachedHashCode);
}
equals(other) {
if (this === other) {
return true;
} else if (!(other instanceof LexerActionExecutor)) {
return false;
} else if (this.cachedHashCode != other.cachedHashCode) {
return false;
} else if (this.lexerActions.length != other.lexerActions.length) {
return false;
} else {
const numActions = this.lexerActions.length
for (let idx = 0; idx < numActions; ++idx) {
if (!this.lexerActions[idx].equals(other.lexerActions[idx])) {
return false;
}
}
return true;
}
}
/**
* Creates a {@link LexerActionExecutor} which executes the actions for
* the input {@code lexerActionExecutor} followed by a specified
* {@code lexerAction}.
*
* @param lexerActionExecutor The executor for actions already traversed by
* the lexer while matching a token within a particular
* {@link LexerATNConfig}. If this is {@code null}, the method behaves as
* though it were an empty executor.
* @param lexerAction The lexer action to execute after the actions
* specified in {@code lexerActionExecutor}.
*
* @return {LexerActionExecutor} A {@link LexerActionExecutor} for executing the combine actions
* of {@code lexerActionExecutor} and {@code lexerAction}.
*/
static append(lexerActionExecutor, lexerAction) {
if (lexerActionExecutor === null) {
return new LexerActionExecutor([ lexerAction ]);
}
const lexerActions = lexerActionExecutor.lexerActions.concat([ lexerAction ]);
return new LexerActionExecutor(lexerActions);
}
}
// Creates a {@link LexerActionExecutor} which executes the actions for
// the input {@code lexerActionExecutor} followed by a specified
// {@code lexerAction}.
//
// @param lexerActionExecutor The executor for actions already traversed by
// the lexer while matching a token within a particular
// {@link LexerATNConfig}. If this is {@code null}, the method behaves as
// though it were an empty executor.
// @param lexerAction The lexer action to execute after the actions
// specified in {@code lexerActionExecutor}.
//
// @return A {@link LexerActionExecutor} for executing the combine actions
// of {@code lexerActionExecutor} and {@code lexerAction}.
LexerActionExecutor.append = function(lexerActionExecutor, lexerAction) {
if (lexerActionExecutor === null) {
return new LexerActionExecutor([ lexerAction ]);
}
var lexerActions = lexerActionExecutor.lexerActions.concat([ lexerAction ]);
return new LexerActionExecutor(lexerActions);
};
// Creates a {@link LexerActionExecutor} which encodes the current offset
// for position-dependent lexer actions.
//
// <p>Normally, when the executor encounters lexer actions where
// {@link LexerAction//isPositionDependent} returns {@code true}, it calls
// {@link IntStream//seek} on the input {@link CharStream} to set the input
// position to the <em>end</em> of the current token. This behavior provides
// for efficient DFA representation of lexer actions which appear at the end
// of a lexer rule, even when the lexer rule matches a variable number of
// characters.</p>
//
// <p>Prior to traversing a match transition in the ATN, the current offset
// from the token start index is assigned to all position-dependent lexer
// actions which have not already been assigned a fixed offset. By storing
// the offsets relative to the token start index, the DFA representation of
// lexer actions which appear in the middle of tokens remains efficient due
// to sharing among tokens of the same length, regardless of their absolute
// position in the input stream.</p>
//
// <p>If the current executor already has offsets assigned to all
// position-dependent lexer actions, the method returns {@code this}.</p>
//
// @param offset The current offset to assign to all position-dependent
// lexer actions which do not already have offsets assigned.
//
// @return A {@link LexerActionExecutor} which stores input stream offsets
// for all position-dependent lexer actions.
// /
LexerActionExecutor.prototype.fixOffsetBeforeMatch = function(offset) {
var updatedLexerActions = null;
for (var i = 0; i < this.lexerActions.length; i++) {
if (this.lexerActions[i].isPositionDependent &&
!(this.lexerActions[i] instanceof LexerIndexedCustomAction)) {
if (updatedLexerActions === null) {
updatedLexerActions = this.lexerActions.concat([]);
}
updatedLexerActions[i] = new LexerIndexedCustomAction(offset,
this.lexerActions[i]);
}
}
if (updatedLexerActions === null) {
return this;
} else {
return new LexerActionExecutor(updatedLexerActions);
}
};
// Execute the actions encapsulated by this executor within the context of a
// particular {@link Lexer}.
//
// <p>This method calls {@link IntStream//seek} to set the position of the
// {@code input} {@link CharStream} prior to calling
// {@link LexerAction//execute} on a position-dependent action. Before the
// method returns, the input position will be restored to the same position
// it was in when the method was invoked.</p>
//
// @param lexer The lexer instance.
// @param input The input stream which is the source for the current token.
// When this method is called, the current {@link IntStream//index} for
// {@code input} should be the start of the following token, i.e. 1
// character past the end of the current token.
// @param startIndex The token start index. This value may be passed to
// {@link IntStream//seek} to set the {@code input} position to the beginning
// of the token.
// /
LexerActionExecutor.prototype.execute = function(lexer, input, startIndex) {
var requiresSeek = false;
var stopIndex = input.index;
try {
for (var i = 0; i < this.lexerActions.length; i++) {
var lexerAction = this.lexerActions[i];
if (lexerAction instanceof LexerIndexedCustomAction) {
var offset = lexerAction.offset;
input.seek(startIndex + offset);
lexerAction = lexerAction.action;
requiresSeek = (startIndex + offset) !== stopIndex;
} else if (lexerAction.isPositionDependent) {
input.seek(stopIndex);
requiresSeek = false;
}
lexerAction.execute(lexer);
}
} finally {
if (requiresSeek) {
input.seek(stopIndex);
}
}
};
LexerActionExecutor.prototype.hashCode = function() {
return this.cachedHashCode;
};
LexerActionExecutor.prototype.updateHashCode = function(hash) {
hash.update(this.cachedHashCode);
};
LexerActionExecutor.prototype.equals = function(other) {
if (this === other) {
return true;
} else if (!(other instanceof LexerActionExecutor)) {
return false;
} else if (this.cachedHashCode != other.cachedHashCode) {
return false;
} else if (this.lexerActions.length != other.lexerActions.length) {
return false;
} else {
var numActions = this.lexerActions.length
for (var idx = 0; idx < numActions; ++idx) {
if (!this.lexerActions[idx].equals(other.lexerActions[idx])) {
return false;
}
}
return true;
}
};
exports.LexerActionExecutor = LexerActionExecutor;
module.exports = LexerActionExecutor;