antlr4ng
Version:
Alternative JavaScript/TypeScript runtime for ANTLR4
286 lines (282 loc) • 9.55 kB
JavaScript
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
// src/utils/MurmurHash.ts
var c1 = 3432918353;
var c2 = 461845907;
var r1 = 15;
var r2 = 13;
var m = 5;
var n = 3864292196;
var MurmurHash = class _MurmurHash {
static {
__name(this, "MurmurHash");
}
static defaultSeed = 701;
constructor() {
}
/**
* Initialize the hash using the specified {@code seed}.
*
* @param seed the seed
*
* @returns the intermediate hash value
*/
static initialize(seed = _MurmurHash.defaultSeed) {
return seed;
}
static updateFromComparable(hash, value) {
return this.update(hash, value?.hashCode() ?? 0);
}
/**
* Update the intermediate hash value for the next input {@code value}.
*
* @param hash The intermediate hash value.
* @param value the value to add to the current hash.
*
* @returns the updated intermediate hash value
*/
static update(hash, value) {
value = Math.imul(value, c1);
value = value << r1 | value >>> 32 - r1;
value = Math.imul(value, c2);
hash = hash ^ value;
hash = hash << r2 | hash >>> 32 - r2;
hash = Math.imul(hash, m) + n;
return hash;
}
/**
* Apply the final computation steps to the intermediate value {@code hash}
* to form the final result of the MurmurHash 3 hash function.
*
* @param hash The intermediate hash value.
* @param entryCount The number of values added to the hash.
*
* @returns the final hash result
*/
static finish(hash, entryCount) {
hash ^= entryCount * 4;
hash ^= hash >>> 16;
hash = Math.imul(hash, 2246822507);
hash ^= hash >>> 13;
hash = Math.imul(hash, 3266489909);
hash ^= hash >>> 16;
return hash;
}
/**
* An all-in-one convenience method to compute a hash for a single value.
*
* @param value The value to hash.
* @param seed The seed for the hash value.
*
* @returns The computed hash.
*/
static hashCode(value, seed) {
return _MurmurHash.finish(_MurmurHash.update(seed ?? _MurmurHash.defaultSeed, value), 1);
}
};
// src/atn/LexerIndexedCustomAction.ts
var LexerIndexedCustomAction = class _LexerIndexedCustomAction {
static {
__name(this, "LexerIndexedCustomAction");
}
offset;
action;
actionType;
isPositionDependent = true;
cachedHashCode;
constructor(offset, action) {
this.actionType = action.actionType;
this.offset = offset;
this.action = action;
}
/**
* This method calls {@link execute} on the result of {@link getAction}
* using the provided `lexer`.
*/
execute(lexer) {
this.action.execute(lexer);
}
hashCode() {
if (this.cachedHashCode === void 0) {
let hash = MurmurHash.initialize();
hash = MurmurHash.update(hash, this.offset);
hash = MurmurHash.updateFromComparable(hash, this.action);
this.cachedHashCode = MurmurHash.finish(hash, 2);
}
return this.cachedHashCode;
}
equals(other) {
if (this === other) {
return true;
}
if (!(other instanceof _LexerIndexedCustomAction)) {
return false;
}
return this.offset === other.offset && this.action === other.action;
}
};
// src/atn/LexerActionExecutor.ts
var LexerActionExecutor = class _LexerActionExecutor {
static {
__name(this, "LexerActionExecutor");
}
lexerActions;
actionType;
isPositionDependent = false;
cachedHashCode;
/**
* Represents an executor for a sequence of lexer actions which traversed during
* the matching operation of a lexer rule (token).
*
* 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.
*/
constructor(lexerActions) {
this.actionType = -1;
this.lexerActions = lexerActions ?? [];
return this;
}
/**
* Creates a {@link LexerActionExecutor} which executes the actions for
* the input `lexerActionExecutor` followed by a specified
* `lexerAction`.
*
* @param lexerActionExecutor The executor for actions already traversed by
* the lexer while matching a token within a particular
* {@link LexerATNConfig}. If this is `null`, the method behaves as
* though it were an empty executor.
* @param lexerAction The lexer action to execute after the actions
* specified in `lexerActionExecutor`.
*
* @returns {LexerActionExecutor} A {@link LexerActionExecutor} for executing the combine actions
* of `lexerActionExecutor` and `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 encodes the current offset
* for position-dependent lexer actions.
*
* Normally, when the executor encounters lexer actions where
* {@link LexerAction//isPositionDependent} returns `true`, it calls
* {@link IntStream.seek} on the input {@link CharStream} to set the input
* position to the *end* 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.
*
* 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.
*
* If the current executor already has offsets assigned to all
* position-dependent lexer actions, the method returns `this`.
*
* @param offset The current offset to assign to all position-dependent
* lexer actions which do not already have offsets assigned.
*
* @returns {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}.
*
* This method calls {@link IntStream.seek} to set the position of the
* `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.
*
* @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
* `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 `input` position to the beginning
* of the token.
*/
execute(lexer, input, startIndex) {
if (input === void 0 || startIndex === void 0) {
return;
}
let requiresSeek = false;
const stopIndex = input.index;
try {
for (const lexerAction of this.lexerActions) {
let action = lexerAction;
if (lexerAction instanceof LexerIndexedCustomAction) {
const offset = lexerAction.offset;
input.seek(startIndex + offset);
action = lexerAction.action;
requiresSeek = startIndex + offset !== stopIndex;
} else if (lexerAction.isPositionDependent) {
input.seek(stopIndex);
requiresSeek = false;
}
action.execute(lexer);
}
} finally {
if (requiresSeek) {
input.seek(stopIndex);
}
}
}
hashCode() {
if (this.cachedHashCode === void 0) {
let hashCode = MurmurHash.initialize(7);
for (const lexerAction of this.lexerActions) {
hashCode = MurmurHash.update(hashCode, lexerAction.hashCode());
}
this.cachedHashCode = MurmurHash.finish(hashCode, this.lexerActions.length);
}
return this.cachedHashCode;
}
equals(other) {
if (this === other) {
return true;
}
if (this.cachedHashCode !== other.cachedHashCode) {
return false;
}
if (this.lexerActions.length !== other.lexerActions.length) {
return false;
}
return this.lexerActions.every((action, index) => {
return action.equals(other.lexerActions[index]);
});
}
};
export {
LexerActionExecutor
};