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/PredictionContextCache.ts
var PredictionContextCache_exports = {};
__export(PredictionContextCache_exports, {
  PredictionContextCache: () => PredictionContextCache
});
module.exports = __toCommonJS(PredictionContextCache_exports);

// 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/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/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/misc/MapKeyEqualityOperator.ts
var MapKeyEqualityComparator = class {
  static {
    __name(this, "MapKeyEqualityComparator");
  }
  keyComparator;
  constructor(keyComparator) {
    this.keyComparator = keyComparator;
  }
  hashCode(obj) {
    return this.keyComparator.hashCode(obj.key);
  }
  equals(a, b) {
    return this.keyComparator.equals(a.key, b.key);
  }
};

// src/misc/HashMap.ts
var HashMap = class _HashMap {
  static {
    __name(this, "HashMap");
  }
  backingStore;
  constructor(keyComparer) {
    if (keyComparer instanceof _HashMap) {
      this.backingStore = new HashSet(keyComparer.backingStore);
    } else {
      keyComparer = keyComparer ?? DefaultEqualityComparator.instance;
      this.backingStore = new HashSet(new MapKeyEqualityComparator(keyComparer));
    }
  }
  clear() {
    this.backingStore.clear();
  }
  containsKey(key) {
    return this.backingStore.contains({ key });
  }
  get(key) {
    const bucket = this.backingStore.get({ key });
    if (!bucket) {
      return void 0;
    }
    return bucket.value;
  }
  get isEmpty() {
    return this.backingStore.isEmpty;
  }
  /**
   * Sets the value for a key in the map. If the key is not present in the map, it is added.
   * If the key is present, the value is updated and the old value is returned.
   *
   * @param key The key to set.
   * @param value The value to set.
   *
   * @returns The old value for the key, if present.
   */
  set(key, value) {
    const element = this.backingStore.get({ key, value });
    let result;
    if (!element) {
      this.backingStore.add({ key, value });
    } else {
      result = element.value;
      element.value = value;
    }
    return result;
  }
  /**
   * Sets the value for a key in the map if the key is not already present. Otherwise the value is not changed and
   * the old value is returned.
   *
   * @param key The key to set.
   * @param value The value to set.
   *
   * @returns The current value for the key, if present.
   */
  setIfAbsent(key, value) {
    const element = this.backingStore.get({ key, value });
    let result;
    if (!element) {
      this.backingStore.add({ key, value });
    } else {
      result = element.value;
    }
    return result;
  }
  keys() {
    return this.backingStore.toArray().map((bucket) => {
      return bucket.key;
    });
  }
  values() {
    return this.backingStore.toArray().map((bucket) => {
      return bucket.value;
    });
  }
  get size() {
    return this.backingStore.size;
  }
  hashCode() {
    return this.backingStore.hashCode();
  }
  equals(o) {
    return this.backingStore.equals(o.backingStore);
  }
};

// src/atn/PredictionContext.ts
var PredictionContext = class _PredictionContext {
  static {
    __name(this, "PredictionContext");
  }
  /**
   * Represents `$` in an array in full context mode, when `$`
   * doesn't mean wildcard: `$ + x = [$,x]`. Here,
   * `$` = {@link EMPTY_RETURN_STATE}.
   */
  static EMPTY_RETURN_STATE = 2147483647;
  static traceATNSimulator = false;
  cachedHashCode;
  constructor(cachedHashCode) {
    this.cachedHashCode = cachedHashCode;
  }
  static calculateEmptyHashCode() {
    let hash = MurmurHash.initialize(31);
    hash = MurmurHash.finish(hash, 0);
    return hash;
  }
  static calculateHashCodeSingle(parent, returnState) {
    let hash = MurmurHash.initialize(31);
    hash = MurmurHash.updateFromComparable(hash, parent);
    hash = MurmurHash.update(hash, returnState);
    hash = MurmurHash.finish(hash, 2);
    return hash;
  }
  static calculateHashCodeList(parents, returnStates) {
    let hash = MurmurHash.initialize(31);
    for (const parent of parents) {
      hash = MurmurHash.updateFromComparable(hash, parent);
    }
    for (const returnState of returnStates) {
      hash = MurmurHash.update(hash, returnState);
    }
    hash = MurmurHash.finish(hash, 2 * parents.length);
    return hash;
  }
  isEmpty() {
    return false;
  }
  hasEmptyPath() {
    return this.getReturnState(this.length - 1) === _PredictionContext.EMPTY_RETURN_STATE;
  }
  hashCode() {
    return this.cachedHashCode;
  }
  toString(_recog) {
    return "";
  }
};

// src/atn/SingletonPredictionContext.ts
var SingletonPredictionContext = class _SingletonPredictionContext extends PredictionContext {
  static {
    __name(this, "SingletonPredictionContext");
  }
  parent;
  returnState;
  constructor(parent, returnState) {
    super(
      parent ? PredictionContext.calculateHashCodeSingle(parent, returnState) : PredictionContext.calculateEmptyHashCode()
    );
    this.parent = parent ?? null;
    this.returnState = returnState;
  }
  getParent(_index) {
    return this.parent;
  }
  getReturnState(_index) {
    return this.returnState;
  }
  equals(other) {
    if (this === other) {
      return true;
    }
    if (!(other instanceof _SingletonPredictionContext)) {
      return false;
    }
    if (this.hashCode() !== other.hashCode()) {
      return false;
    }
    if (this.returnState !== other.returnState) {
      return false;
    }
    if (this.parent == null) {
      return other.parent == null;
    }
    return this.parent.equals(other.parent);
  }
  toString() {
    const up = this.parent === null ? "" : this.parent.toString();
    if (up.length === 0) {
      if (this.returnState === PredictionContext.EMPTY_RETURN_STATE) {
        return "$";
      }
      return "" + this.returnState;
    } else {
      return "" + this.returnState + " " + up;
    }
  }
  get length() {
    return 1;
  }
};

// src/atn/EmptyPredictionContext.ts
var EmptyPredictionContext = class _EmptyPredictionContext extends SingletonPredictionContext {
  static {
    __name(this, "EmptyPredictionContext");
  }
  /**
   * Represents `$` in local context prediction, which means wildcard.
   * `*+x = *`.
   */
  static instance = new _EmptyPredictionContext();
  constructor() {
    super(void 0, PredictionContext.EMPTY_RETURN_STATE);
  }
  isEmpty() {
    return true;
  }
  getParent() {
    return null;
  }
  getReturnState() {
    return this.returnState;
  }
  equals(other) {
    return this === other;
  }
  toString() {
    return "$";
  }
};

// src/atn/PredictionContextCache.ts
var PredictionContextCache = class {
  static {
    __name(this, "PredictionContextCache");
  }
  cache = new HashMap(ObjectEqualityComparator.instance);
  /**
   * Add a context to the cache and return it. If the context already exists,
   * return that one instead and do not add a new context to the cache.
   * Protect shared cache from unsafe thread access.
   *
   * @param ctx tbd
   * @returns tbd
   */
  add(ctx) {
    if (ctx === EmptyPredictionContext.instance) {
      return ctx;
    }
    const existing = this.cache.get(ctx);
    if (existing) {
      return existing;
    }
    this.cache.set(ctx, ctx);
    return ctx;
  }
  get(ctx) {
    return this.cache.get(ctx);
  }
  get length() {
    return this.cache.size;
  }
};
