antlr4ng
Version:
Alternative JavaScript/TypeScript runtime for ANTLR4
912 lines (903 loc) • 25 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/atn/ATNConfig.ts
var ATNConfig_exports = {};
__export(ATNConfig_exports, {
ATNConfig: () => ATNConfig
});
module.exports = __toCommonJS(ATNConfig_exports);
// 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/misc/ObjectEqualityComparator.ts
var ObjectEqualityComparator = class _ObjectEqualityComparator {
static {
__name(this, "ObjectEqualityComparator");
}
static instance = new _ObjectEqualityComparator();
hashCode(obj) {
if (obj == null) {
return 0;
}
return obj.hashCode();
}
equals(a, b) {
if (a == null) {
return b == null;
}
return a.equals(b);
}
};
// src/misc/DefaultEqualityComparator.ts
var DefaultEqualityComparator = class _DefaultEqualityComparator {
static {
__name(this, "DefaultEqualityComparator");
}
static instance = new _DefaultEqualityComparator();
hashCode(obj) {
if (obj == null) {
return 0;
}
return ObjectEqualityComparator.instance.hashCode(obj);
}
equals(a, b) {
if (a == null) {
return b == null;
}
if (typeof a === "string" || typeof a === "number") {
return a === b;
}
return ObjectEqualityComparator.instance.equals(a, b);
}
};
// src/misc/HashSet.ts
var HashSet = class _HashSet {
static {
__name(this, "HashSet");
}
static defaultLoadFactor = 0.75;
static initialCapacity = 16;
// must be power of 2
comparator;
buckets;
threshold;
/** How many elements in set */
itemCount = 0;
constructor(comparatorOrSet, initialCapacity = _HashSet.initialCapacity) {
if (comparatorOrSet instanceof _HashSet) {
this.comparator = comparatorOrSet.comparator;
this.buckets = comparatorOrSet.buckets.slice(0);
for (let i = 0; i < this.buckets.length; i++) {
const bucket = this.buckets[i];
if (bucket) {
this.buckets[i] = bucket.slice(0);
}
}
this.itemCount = comparatorOrSet.itemCount;
this.threshold = comparatorOrSet.threshold;
} else {
this.comparator = comparatorOrSet ?? DefaultEqualityComparator.instance;
this.buckets = this.createBuckets(initialCapacity);
this.threshold = Math.floor(_HashSet.initialCapacity * _HashSet.defaultLoadFactor);
}
}
/**
* Add `o` to set if not there; return existing value if already
* there. This method performs the same operation as {@link #add} aside from
* the return value.
*
* @param o the object to add to the set.
*
* @returns An existing element that equals to `o` if already in set, otherwise `o`.
*/
getOrAdd(o) {
if (this.itemCount > this.threshold) {
this.expand();
}
const b = this.getBucket(o);
let bucket = this.buckets[b];
if (!bucket) {
bucket = [o];
this.buckets[b] = bucket;
++this.itemCount;
return o;
}
for (const existing of bucket) {
if (this.comparator.equals(existing, o)) {
return existing;
}
}
bucket.push(o);
++this.itemCount;
return o;
}
get(o) {
if (o == null) {
return o;
}
const b = this.getBucket(o);
const bucket = this.buckets[b];
if (!bucket) {
return void 0;
}
for (const e of bucket) {
if (this.comparator.equals(e, o)) {
return e;
}
}
return void 0;
}
/**
* Removes the specified element from this set if it is present.
*
* @param o object to be removed from this set, if present.
*
* @returns `true` if the set contained the specified element.
*/
remove(o) {
if (o == null) {
return false;
}
const b = this.getBucket(o);
const bucket = this.buckets[b];
if (!bucket) {
return false;
}
for (let i = 0; i < bucket.length; i++) {
const existing = bucket[i];
if (this.comparator.equals(existing, o)) {
bucket.splice(i, 1);
--this.itemCount;
return true;
}
}
return false;
}
hashCode() {
let hash = MurmurHash.initialize();
for (const bucket of this.buckets) {
if (bucket == null) {
continue;
}
for (const o of bucket) {
if (o == null) {
break;
}
hash = MurmurHash.update(hash, this.comparator.hashCode(o));
}
}
hash = MurmurHash.finish(hash, this.size);
return hash;
}
equals(o) {
if (o === this) {
return true;
}
if (!(o instanceof _HashSet)) {
return false;
}
if (o.size !== this.size) {
return false;
}
return this.containsAll(o);
}
add(t) {
const existing = this.getOrAdd(t);
return existing === t;
}
contains(o) {
return this.containsFast(o);
}
containsFast(obj) {
if (obj == null) {
return false;
}
return this.get(obj) !== void 0;
}
*[Symbol.iterator]() {
yield* this.toArray();
}
toArray() {
const a = new Array(this.size);
let i = 0;
for (const bucket of this.buckets) {
if (bucket == null) {
continue;
}
for (const o of bucket) {
if (o == null) {
break;
}
a[i++] = o;
}
}
return a;
}
containsAll(collection) {
if (collection instanceof _HashSet) {
for (const bucket of collection.buckets) {
if (bucket == null) {
continue;
}
for (const o of bucket) {
if (o == null) {
break;
}
if (!this.containsFast(o)) {
return false;
}
}
}
} else {
for (const o of collection) {
if (!this.containsFast(o)) {
return false;
}
}
}
return true;
}
addAll(c) {
let changed = false;
for (const o of c) {
const existing = this.getOrAdd(o);
if (existing !== o) {
changed = true;
}
}
return changed;
}
clear() {
this.buckets = this.createBuckets(_HashSet.initialCapacity);
this.itemCount = 0;
this.threshold = Math.floor(_HashSet.initialCapacity * _HashSet.defaultLoadFactor);
}
toString() {
if (this.size === 0) {
return "{}";
}
let buf = "{";
let first = true;
for (const bucket of this.buckets) {
if (bucket == null) {
continue;
}
for (const o of bucket) {
if (o == null) {
break;
}
if (first) {
first = false;
} else {
buf += ", ";
}
buf += o.toString();
}
}
buf += "}";
return buf;
}
toTableString() {
let buf = "";
for (const bucket of this.buckets) {
if (bucket == null) {
buf += "null\n";
continue;
}
buf += "[";
let first = true;
for (const o of bucket) {
if (first) {
first = false;
} else {
buf += " ";
}
if (o == null) {
buf += "_";
} else {
buf += o.toString();
}
}
buf += "]\n";
}
return buf;
}
getBucket(o) {
const hash = this.comparator.hashCode(o);
const b = hash & this.buckets.length - 1;
return b;
}
expand() {
const old = this.buckets;
const newCapacity = this.buckets.length * 2;
const newTable = this.createBuckets(newCapacity);
this.buckets = newTable;
this.threshold = Math.floor(newCapacity * _HashSet.defaultLoadFactor);
for (const bucket of old) {
if (!bucket) {
continue;
}
for (const o of bucket) {
const b = this.getBucket(o);
let newBucket = this.buckets[b];
if (!newBucket) {
newBucket = [];
this.buckets[b] = newBucket;
}
newBucket.push(o);
}
}
}
get size() {
return this.itemCount;
}
get isEmpty() {
return this.itemCount === 0;
}
/**
* Return an array of `T[]` with length `capacity`.
*
* @param capacity the length of the array to return
* @returns the newly constructed array
*/
createBuckets(capacity) {
return new Array(capacity);
}
};
// src/utils/helpers.ts
var equalArrays = /* @__PURE__ */ __name((a, b) => {
if (a === b) {
return true;
}
if (a.length !== b.length) {
return false;
}
for (let i = 0; i < a.length; i++) {
const left = a[i];
const right = b[i];
if (left === right) {
continue;
}
if (!left || !left.equals(right)) {
return false;
}
}
return true;
}, "equalArrays");
// src/atn/SemanticContext.ts
var SemanticContext = class _SemanticContext {
static {
__name(this, "SemanticContext");
}
cachedHashCode;
static andContext(a, b) {
if (a === null || a === _SemanticContext.NONE) {
return b;
}
if (b === null || b === _SemanticContext.NONE) {
return a;
}
const result = new AND(a, b);
if (result.operands.length === 1) {
return result.operands[0];
}
return result;
}
static orContext(a, b) {
if (a === null) {
return b;
}
if (b === null) {
return a;
}
if (a === _SemanticContext.NONE || b === _SemanticContext.NONE) {
return _SemanticContext.NONE;
}
const result = new OR(a, b);
if (result.operands.length === 1) {
return result.operands[0];
} else {
return result;
}
}
static filterPrecedencePredicates(set) {
const result = [];
for (const context of set) {
if (context instanceof _SemanticContext.PrecedencePredicate) {
result.push(context);
}
}
return result;
}
/**
* Evaluate the precedence predicates for the context and reduce the result.
*
* @param _parser The parser instance.
* @param _parserCallStack The current parser context object.
* @returns The simplified semantic context after precedence predicates are
* evaluated, which will be one of the following values.
* - {@link NONE}: if the predicate simplifies to `true` after
* precedence predicates are evaluated.
* - `null`: if the predicate simplifies to `false` after
* precedence predicates are evaluated.
* - `this`: if the semantic context is not changed as a result of
* precedence predicate evaluation.
* - A non-`null` {@link SemanticContext}: the new simplified
* semantic context after precedence predicates are evaluated.
*/
evalPrecedence(_parser, _parserCallStack) {
return this;
}
};
var AND = class _AND extends SemanticContext {
static {
__name(this, "AND");
}
operands;
/**
* A semantic context which is true whenever none of the contained contexts
* is false
*/
constructor(a, b) {
super();
const operands = new HashSet();
if (a instanceof _AND) {
a.operands.forEach((o) => {
operands.add(o);
});
} else {
operands.add(a);
}
if (b instanceof _AND) {
b.operands.forEach((o) => {
operands.add(o);
});
} else {
operands.add(b);
}
const precedencePredicates = SemanticContext.filterPrecedencePredicates(operands);
if (precedencePredicates.length > 0) {
let reduced = null;
precedencePredicates.forEach((p) => {
if (reduced === null || p.precedence < reduced.precedence) {
reduced = p;
}
});
if (reduced) {
operands.add(reduced);
}
}
this.operands = operands.toArray();
}
equals(other) {
if (this === other) {
return true;
}
if (!(other instanceof _AND)) {
return false;
}
return equalArrays(this.operands, other.operands);
}
hashCode() {
if (this.cachedHashCode === void 0) {
let hash = MurmurHash.initialize();
for (const operand of this.operands) {
hash = MurmurHash.updateFromComparable(hash, operand);
}
hash = MurmurHash.update(hash, 3813686060);
this.cachedHashCode = MurmurHash.finish(hash, this.operands.length + 1);
}
return this.cachedHashCode;
}
/**
* {@inheritDoc}
*
*
* The evaluation of predicates by this context is short-circuiting, but
* unordered.
*/
evaluate(parser, parserCallStack) {
for (const operand of this.operands) {
if (!operand.evaluate(parser, parserCallStack)) {
return false;
}
}
return true;
}
evalPrecedence(parser, parserCallStack) {
let differs = false;
const operands = [];
for (const context of this.operands) {
const evaluated = context.evalPrecedence(parser, parserCallStack);
differs ||= evaluated !== context;
if (evaluated === null) {
return null;
} else if (evaluated !== SemanticContext.NONE) {
operands.push(evaluated);
}
}
if (!differs) {
return this;
}
if (operands.length === 0) {
return SemanticContext.NONE;
}
let result = null;
operands.forEach((o) => {
result = result === null ? o : SemanticContext.andContext(result, o);
});
return result;
}
toString() {
const s = this.operands.map((o) => {
return o.toString();
});
return (s.length > 3 ? s.slice(3) : s).join("&&");
}
};
var OR = class _OR extends SemanticContext {
static {
__name(this, "OR");
}
operands;
/**
* A semantic context which is true whenever at least one of the contained
* contexts is true
*/
constructor(a, b) {
super();
const operands = new HashSet();
if (a instanceof _OR) {
a.operands.forEach((o) => {
operands.add(o);
});
} else {
operands.add(a);
}
if (b instanceof _OR) {
b.operands.forEach((o) => {
operands.add(o);
});
} else {
operands.add(b);
}
const precedencePredicates = SemanticContext.filterPrecedencePredicates(operands);
if (precedencePredicates.length > 0) {
const s = precedencePredicates.sort((a2, b2) => {
return a2.compareTo(b2);
});
const reduced = s[s.length - 1];
operands.add(reduced);
}
this.operands = operands.toArray();
}
equals(other) {
if (this === other) {
return true;
} else if (!(other instanceof _OR)) {
return false;
} else {
return equalArrays(this.operands, other.operands);
}
}
hashCode() {
if (this.cachedHashCode === void 0) {
let hash = MurmurHash.initialize();
for (const operand of this.operands) {
hash = MurmurHash.updateFromComparable(hash, operand);
}
hash = MurmurHash.update(hash, 3383313031);
this.cachedHashCode = MurmurHash.finish(hash, this.operands.length + 1);
}
return this.cachedHashCode;
}
/**
* The evaluation of predicates by this context is short-circuiting, but unordered.
*/
evaluate(parser, parserCallStack) {
for (const operand of this.operands) {
if (operand.evaluate(parser, parserCallStack)) {
return true;
}
}
return false;
}
evalPrecedence(parser, parserCallStack) {
let differs = false;
const operands = [];
for (const context of this.operands) {
const evaluated = context.evalPrecedence(parser, parserCallStack);
differs ||= evaluated !== context;
if (evaluated === SemanticContext.NONE) {
return SemanticContext.NONE;
} else if (evaluated !== null) {
operands.push(evaluated);
}
}
if (!differs) {
return this;
}
if (operands.length === 0) {
return null;
}
let result = null;
operands.forEach((o) => {
result = result === null ? o : SemanticContext.orContext(result, o);
});
return result;
}
toString() {
const s = this.operands.map((o) => {
return o.toString();
});
return (s.length > 3 ? s.slice(3) : s).join("||");
}
};
((SemanticContext2) => {
class Predicate extends SemanticContext2 {
static {
__name(this, "Predicate");
}
ruleIndex;
predIndex;
isCtxDependent;
// e.g., $i ref in pred
constructor(ruleIndex, predIndex, isCtxDependent) {
super();
this.ruleIndex = ruleIndex ?? -1;
this.predIndex = predIndex ?? -1;
this.isCtxDependent = isCtxDependent ?? false;
}
evaluate(parser, outerContext) {
const localctx = this.isCtxDependent ? outerContext : null;
return parser.sempred(localctx, this.ruleIndex, this.predIndex);
}
hashCode() {
if (this.cachedHashCode === void 0) {
let hashCode = MurmurHash.initialize();
hashCode = MurmurHash.update(hashCode, this.ruleIndex);
hashCode = MurmurHash.update(hashCode, this.predIndex);
hashCode = MurmurHash.update(hashCode, this.isCtxDependent ? 1 : 0);
hashCode = MurmurHash.finish(hashCode, 3);
this.cachedHashCode = hashCode;
}
return this.cachedHashCode;
}
equals(other) {
if (this === other) {
return true;
}
return this.ruleIndex === other.ruleIndex && this.predIndex === other.predIndex && this.isCtxDependent === other.isCtxDependent;
}
toString() {
return "{" + this.ruleIndex + ":" + this.predIndex + "}?";
}
}
SemanticContext2.Predicate = Predicate;
class PrecedencePredicate extends SemanticContext2 {
static {
__name(this, "PrecedencePredicate");
}
precedence;
constructor(precedence) {
super();
this.precedence = precedence ?? 0;
}
evaluate(parser, outerContext) {
return parser.precpred(outerContext, this.precedence);
}
evalPrecedence(parser, outerContext) {
if (parser.precpred(outerContext ?? null, this.precedence)) {
return SemanticContext2.NONE;
}
return null;
}
compareTo(other) {
return this.precedence - other.precedence;
}
hashCode() {
return 31 + this.precedence;
}
equals(other) {
if (this === other) {
return true;
}
return this.precedence === other.precedence;
}
toString() {
return "{" + this.precedence + ">=prec}?";
}
}
SemanticContext2.PrecedencePredicate = PrecedencePredicate;
SemanticContext2.NONE = new Predicate();
})(SemanticContext || (SemanticContext = {}));
// src/atn/ATNConfig.ts
var ATNConfig = class _ATNConfig {
static {
__name(this, "ATNConfig");
}
/** The ATN state associated with this configuration */
state;
/** What alt (or lexer rule) is predicted by this configuration */
alt;
/**
* We cannot execute predicates dependent upon local context unless
* we know for sure we are in the correct context. Because there is
* no way to do this efficiently, we simply cannot evaluate
* dependent predicates unless we are in the rule that initially
* invokes the ATN simulator.
*
* closure() tracks the depth of how far we dip into the outer context:
* depth > 0.
*/
reachesIntoOuterContext = false;
// Not used in hash code.
precedenceFilterSuppressed = false;
// Not used in hash code.
get semanticContext() {
return this.#semanticContext;
}
cachedHashCode;
// Shared with LexerATNConfig.
/**
* The syntactic context is a graph-structured stack node whose
* path(s) to the root is the rule invocation(s)
* chain used to arrive at the state. The semantic context is
* the tree of semantic predicates encountered before reaching
* an ATN state
*/
#context = null;
#semanticContext;
/** Never create config classes directly. Use the factory methods below. */
constructor(c, state, context, semanticContext) {
this.state = state;
this.alt = c.alt;
this.context = context;
this.#semanticContext = semanticContext ?? SemanticContext.NONE;
this.reachesIntoOuterContext = c.reachesIntoOuterContext;
if (c.precedenceFilterSuppressed !== void 0) {
this.precedenceFilterSuppressed = c.precedenceFilterSuppressed;
}
}
static duplicate(old, semanticContext) {
return new _ATNConfig(old, old.state, old.context, semanticContext ?? old.semanticContext);
}
static createWithContext(state, alt, context, semanticContext) {
return new _ATNConfig({ alt }, state, context, semanticContext);
}
static createWithConfig(state, config, context) {
return new _ATNConfig(config, state, context ?? config.context, config.semanticContext);
}
static createWithSemanticContext(state, c, semanticContext) {
return new _ATNConfig(c, state ?? c.state, c.context, semanticContext);
}
hashCode() {
if (this.cachedHashCode === void 0) {
let hashCode = MurmurHash.initialize(7);
hashCode = MurmurHash.update(hashCode, this.state.stateNumber);
hashCode = MurmurHash.update(hashCode, this.alt);
hashCode = MurmurHash.updateFromComparable(hashCode, this.#context);
hashCode = MurmurHash.updateFromComparable(hashCode, this.semanticContext);
hashCode = MurmurHash.finish(hashCode, 4);
this.cachedHashCode = hashCode;
}
return this.cachedHashCode;
}
/**
* The stack of invoking states leading to the rule/states associated
* with this config. We track only those contexts pushed during
* execution of the ATN simulator.
*/
get context() {
return this.#context;
}
set context(context) {
this.#context = context;
this.cachedHashCode = void 0;
}
/**
* An ATN configuration is equal to another if both have
* the same state, they predict the same alternative, and
* syntactic/semantic contexts are the same.
*/
equals(other) {
if (this === other) {
return true;
}
return this.state.stateNumber === other.state.stateNumber && this.alt === other.alt && (this.context === null ? other.context === null : this.context.equals(other.context)) && this.semanticContext.equals(other.semanticContext) && this.precedenceFilterSuppressed === other.precedenceFilterSuppressed;
}
toString(_recog, showAlt = true) {
let alt = "";
if (showAlt) {
alt = "," + this.alt;
}
return "(" + this.state + alt + (this.context !== null ? ",[" + this.context.toString() + "]" : "") + (this.semanticContext !== SemanticContext.NONE ? "," + this.semanticContext.toString() : "") + (this.reachesIntoOuterContext ? ",up=" + this.reachesIntoOuterContext : "") + ")";
}
};