antlr4ts
Version:
ANTLR 4 runtime for JavaScript written in Typescript
645 lines • 22.7 kB
JavaScript
"use strict";
/*!
* Copyright 2016 The ANTLR Project. All rights reserved.
* Licensed under the BSD-3-Clause license. See LICENSE file in the project root for license information.
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.IntervalSet = void 0;
// ConvertTo-TS run at 2016-10-04T11:26:40.8683480-07:00
const ArrayEqualityComparator_1 = require("./ArrayEqualityComparator");
const IntegerList_1 = require("./IntegerList");
const Interval_1 = require("./Interval");
const Lexer_1 = require("../Lexer");
const MurmurHash_1 = require("./MurmurHash");
const Decorators_1 = require("../Decorators");
const Token_1 = require("../Token");
/**
* This class implements the {@link IntSet} backed by a sorted array of
* non-overlapping intervals. It is particularly efficient for representing
* large collections of numbers, where the majority of elements appear as part
* of a sequential range of numbers that are all part of the set. For example,
* the set { 1, 2, 3, 4, 7, 8 } may be represented as { [1, 4], [7, 8] }.
*
* This class is able to represent sets containing any combination of values in
* the range {@link Integer#MIN_VALUE} to {@link Integer#MAX_VALUE}
* (inclusive).
*/
class IntervalSet {
constructor(intervals) {
this.readonly = false;
if (intervals != null) {
this._intervals = intervals.slice(0);
}
else {
this._intervals = [];
}
}
static get COMPLETE_CHAR_SET() {
if (IntervalSet._COMPLETE_CHAR_SET === undefined) {
IntervalSet._COMPLETE_CHAR_SET = IntervalSet.of(Lexer_1.Lexer.MIN_CHAR_VALUE, Lexer_1.Lexer.MAX_CHAR_VALUE);
IntervalSet._COMPLETE_CHAR_SET.setReadonly(true);
}
return IntervalSet._COMPLETE_CHAR_SET;
}
static get EMPTY_SET() {
if (IntervalSet._EMPTY_SET == null) {
IntervalSet._EMPTY_SET = new IntervalSet();
IntervalSet._EMPTY_SET.setReadonly(true);
}
return IntervalSet._EMPTY_SET;
}
/**
* Create a set with all ints within range [a..b] (inclusive). If b is omitted, the set contains the single element
* a.
*/
static of(a, b = a) {
let s = new IntervalSet();
s.add(a, b);
return s;
}
clear() {
if (this.readonly) {
throw new Error("can't alter readonly IntervalSet");
}
this._intervals.length = 0;
}
/** Add interval; i.e., add all integers from a to b to set.
* If b<a, do nothing.
* Keep list in sorted order (by left range value).
* If overlap, combine ranges. For example,
* If this is {1..5, 10..20}, adding 6..7 yields
* {1..5, 6..7, 10..20}. Adding 4..8 yields {1..8, 10..20}.
*/
add(a, b = a) {
this.addRange(Interval_1.Interval.of(a, b));
}
// copy on write so we can cache a..a intervals and sets of that
addRange(addition) {
if (this.readonly) {
throw new Error("can't alter readonly IntervalSet");
}
//System.out.println("add "+addition+" to "+intervals.toString());
if (addition.b < addition.a) {
return;
}
// find position in list
// Use iterators as we modify list in place
for (let i = 0; i < this._intervals.length; i++) {
let r = this._intervals[i];
if (addition.equals(r)) {
return;
}
if (addition.adjacent(r) || !addition.disjoint(r)) {
// next to each other, make a single larger interval
let bigger = addition.union(r);
this._intervals[i] = bigger;
// make sure we didn't just create an interval that
// should be merged with next interval in list
while (i < this._intervals.length - 1) {
i++;
let next = this._intervals[i];
if (!bigger.adjacent(next) && bigger.disjoint(next)) {
break;
}
// if we bump up against or overlap next, merge
// remove this one
this._intervals.splice(i, 1);
i--;
// move backwards to what we just set
this._intervals[i] = bigger.union(next);
// set to 3 merged ones
}
// first call to next after previous duplicates the result
return;
}
if (addition.startsBeforeDisjoint(r)) {
// insert before r
this._intervals.splice(i, 0, addition);
return;
}
// if disjoint and after r, a future iteration will handle it
}
// ok, must be after last interval (and disjoint from last interval)
// just add it
this._intervals.push(addition);
}
/** combine all sets in the array returned the or'd value */
static or(sets) {
let r = new IntervalSet();
for (let s of sets) {
r.addAll(s);
}
return r;
}
addAll(set) {
if (set == null) {
return this;
}
if (set instanceof IntervalSet) {
let other = set;
// walk set and add each interval
let n = other._intervals.length;
for (let i = 0; i < n; i++) {
let I = other._intervals[i];
this.add(I.a, I.b);
}
}
else {
for (let value of set.toArray()) {
this.add(value);
}
}
return this;
}
complementRange(minElement, maxElement) {
return this.complement(IntervalSet.of(minElement, maxElement));
}
/** {@inheritDoc} */
complement(vocabulary) {
if (vocabulary.isNil) {
// nothing in common with null set
return IntervalSet.EMPTY_SET;
}
let vocabularyIS;
if (vocabulary instanceof IntervalSet) {
vocabularyIS = vocabulary;
}
else {
vocabularyIS = new IntervalSet();
vocabularyIS.addAll(vocabulary);
}
return vocabularyIS.subtract(this);
}
subtract(a) {
if (a == null || a.isNil) {
return new IntervalSet(this._intervals);
}
if (a instanceof IntervalSet) {
return IntervalSet.subtract(this, a);
}
let other = new IntervalSet();
other.addAll(a);
return IntervalSet.subtract(this, other);
}
/**
* Compute the set difference between two interval sets. The specific
* operation is `left - right`.
*/
static subtract(left, right) {
if (left.isNil) {
return new IntervalSet();
}
let result = new IntervalSet(left._intervals);
if (right.isNil) {
// right set has no elements; just return the copy of the current set
return result;
}
let resultI = 0;
let rightI = 0;
while (resultI < result._intervals.length && rightI < right._intervals.length) {
let resultInterval = result._intervals[resultI];
let rightInterval = right._intervals[rightI];
// operation: (resultInterval - rightInterval) and update indexes
if (rightInterval.b < resultInterval.a) {
rightI++;
continue;
}
if (rightInterval.a > resultInterval.b) {
resultI++;
continue;
}
let beforeCurrent;
let afterCurrent;
if (rightInterval.a > resultInterval.a) {
beforeCurrent = new Interval_1.Interval(resultInterval.a, rightInterval.a - 1);
}
if (rightInterval.b < resultInterval.b) {
afterCurrent = new Interval_1.Interval(rightInterval.b + 1, resultInterval.b);
}
if (beforeCurrent) {
if (afterCurrent) {
// split the current interval into two
result._intervals[resultI] = beforeCurrent;
result._intervals.splice(resultI + 1, 0, afterCurrent);
resultI++;
rightI++;
continue;
}
else {
// replace the current interval
result._intervals[resultI] = beforeCurrent;
resultI++;
continue;
}
}
else {
if (afterCurrent) {
// replace the current interval
result._intervals[resultI] = afterCurrent;
rightI++;
continue;
}
else {
// remove the current interval (thus no need to increment resultI)
result._intervals.splice(resultI, 1);
continue;
}
}
}
// If rightI reached right.intervals.size, no more intervals to subtract from result.
// If resultI reached result.intervals.size, we would be subtracting from an empty set.
// Either way, we are done.
return result;
}
or(a) {
let o = new IntervalSet();
o.addAll(this);
o.addAll(a);
return o;
}
/** {@inheritDoc} */
and(other) {
if (other.isNil) { //|| !(other instanceof IntervalSet) ) {
// nothing in common with null set
return new IntervalSet();
}
let myIntervals = this._intervals;
let theirIntervals = other._intervals;
let intersection;
let mySize = myIntervals.length;
let theirSize = theirIntervals.length;
let i = 0;
let j = 0;
// iterate down both interval lists looking for nondisjoint intervals
while (i < mySize && j < theirSize) {
let mine = myIntervals[i];
let theirs = theirIntervals[j];
//System.out.println("mine="+mine+" and theirs="+theirs);
if (mine.startsBeforeDisjoint(theirs)) {
// move this iterator looking for interval that might overlap
i++;
}
else if (theirs.startsBeforeDisjoint(mine)) {
// move other iterator looking for interval that might overlap
j++;
}
else if (mine.properlyContains(theirs)) {
// overlap, add intersection, get next theirs
if (!intersection) {
intersection = new IntervalSet();
}
intersection.addRange(mine.intersection(theirs));
j++;
}
else if (theirs.properlyContains(mine)) {
// overlap, add intersection, get next mine
if (!intersection) {
intersection = new IntervalSet();
}
intersection.addRange(mine.intersection(theirs));
i++;
}
else if (!mine.disjoint(theirs)) {
// overlap, add intersection
if (!intersection) {
intersection = new IntervalSet();
}
intersection.addRange(mine.intersection(theirs));
// Move the iterator of lower range [a..b], but not
// the upper range as it may contain elements that will collide
// with the next iterator. So, if mine=[0..115] and
// theirs=[115..200], then intersection is 115 and move mine
// but not theirs as theirs may collide with the next range
// in thisIter.
// move both iterators to next ranges
if (mine.startsAfterNonDisjoint(theirs)) {
j++;
}
else if (theirs.startsAfterNonDisjoint(mine)) {
i++;
}
}
}
if (!intersection) {
return new IntervalSet();
}
return intersection;
}
/** {@inheritDoc} */
contains(el) {
let n = this._intervals.length;
let l = 0;
let r = n - 1;
// Binary search for the element in the (sorted, disjoint) array of intervals.
while (l <= r) {
let m = (l + r) >> 1;
let I = this._intervals[m];
let a = I.a;
let b = I.b;
if (b < el) {
l = m + 1;
}
else if (a > el) {
r = m - 1;
}
else {
// el >= a && el <= b
return true;
}
}
return false;
}
/** {@inheritDoc} */
get isNil() {
return this._intervals == null || this._intervals.length === 0;
}
/**
* Returns the maximum value contained in the set if not isNil.
*
* @return the maximum value contained in the set.
* @throws RangeError if set is empty
*/
get maxElement() {
if (this.isNil) {
throw new RangeError("set is empty");
}
let last = this._intervals[this._intervals.length - 1];
return last.b;
}
/**
* Returns the minimum value contained in the set if not isNil.
*
* @return the minimum value contained in the set.
* @throws RangeError if set is empty
*/
get minElement() {
if (this.isNil) {
throw new RangeError("set is empty");
}
return this._intervals[0].a;
}
/** Return a list of Interval objects. */
get intervals() {
return this._intervals;
}
hashCode() {
let hash = MurmurHash_1.MurmurHash.initialize();
for (let I of this._intervals) {
hash = MurmurHash_1.MurmurHash.update(hash, I.a);
hash = MurmurHash_1.MurmurHash.update(hash, I.b);
}
hash = MurmurHash_1.MurmurHash.finish(hash, this._intervals.length * 2);
return hash;
}
/** Are two IntervalSets equal? Because all intervals are sorted
* and disjoint, equals is a simple linear walk over both lists
* to make sure they are the same. Interval.equals() is used
* by the List.equals() method to check the ranges.
*/
equals(o) {
if (o == null || !(o instanceof IntervalSet)) {
return false;
}
return ArrayEqualityComparator_1.ArrayEqualityComparator.INSTANCE.equals(this._intervals, o._intervals);
}
toString(elemAreChar = false) {
let buf = "";
if (this._intervals == null || this._intervals.length === 0) {
return "{}";
}
if (this.size > 1) {
buf += "{";
}
let first = true;
for (let I of this._intervals) {
if (first) {
first = false;
}
else {
buf += ", ";
}
let a = I.a;
let b = I.b;
if (a === b) {
if (a === Token_1.Token.EOF) {
buf += "<EOF>";
}
else if (elemAreChar) {
buf += "'" + String.fromCodePoint(a) + "'";
}
else {
buf += a;
}
}
else {
if (elemAreChar) {
buf += "'" + String.fromCodePoint(a) + "'..'" + String.fromCodePoint(b) + "'";
}
else {
buf += a + ".." + b;
}
}
}
if (this.size > 1) {
buf += "}";
}
return buf;
}
toStringVocabulary(vocabulary) {
if (this._intervals == null || this._intervals.length === 0) {
return "{}";
}
let buf = "";
if (this.size > 1) {
buf += "{";
}
let first = true;
for (let I of this._intervals) {
if (first) {
first = false;
}
else {
buf += ", ";
}
let a = I.a;
let b = I.b;
if (a === b) {
buf += this.elementName(vocabulary, a);
}
else {
for (let i = a; i <= b; i++) {
if (i > a) {
buf += ", ";
}
buf += this.elementName(vocabulary, i);
}
}
}
if (this.size > 1) {
buf += "}";
}
return buf;
}
elementName(vocabulary, a) {
if (a === Token_1.Token.EOF) {
return "<EOF>";
}
else if (a === Token_1.Token.EPSILON) {
return "<EPSILON>";
}
else {
return vocabulary.getDisplayName(a);
}
}
get size() {
let n = 0;
let numIntervals = this._intervals.length;
if (numIntervals === 1) {
let firstInterval = this._intervals[0];
return firstInterval.b - firstInterval.a + 1;
}
for (let i = 0; i < numIntervals; i++) {
let I = this._intervals[i];
n += (I.b - I.a + 1);
}
return n;
}
toIntegerList() {
let values = new IntegerList_1.IntegerList(this.size);
let n = this._intervals.length;
for (let i = 0; i < n; i++) {
let I = this._intervals[i];
let a = I.a;
let b = I.b;
for (let v = a; v <= b; v++) {
values.add(v);
}
}
return values;
}
toSet() {
let s = new Set();
for (let I of this._intervals) {
let a = I.a;
let b = I.b;
for (let v = a; v <= b; v++) {
s.add(v);
}
}
return s;
}
toArray() {
let values = new Array();
let n = this._intervals.length;
for (let i = 0; i < n; i++) {
let I = this._intervals[i];
let a = I.a;
let b = I.b;
for (let v = a; v <= b; v++) {
values.push(v);
}
}
return values;
}
remove(el) {
if (this.readonly) {
throw new Error("can't alter readonly IntervalSet");
}
let n = this._intervals.length;
for (let i = 0; i < n; i++) {
let I = this._intervals[i];
let a = I.a;
let b = I.b;
if (el < a) {
break; // list is sorted and el is before this interval; not here
}
// if whole interval x..x, rm
if (el === a && el === b) {
this._intervals.splice(i, 1);
break;
}
// if on left edge x..b, adjust left
if (el === a) {
this._intervals[i] = Interval_1.Interval.of(I.a + 1, I.b);
break;
}
// if on right edge a..x, adjust right
if (el === b) {
this._intervals[i] = Interval_1.Interval.of(I.a, I.b - 1);
break;
}
// if in middle a..x..b, split interval
if (el > a && el < b) { // found in this interval
let oldb = I.b;
this._intervals[i] = Interval_1.Interval.of(I.a, el - 1); // [a..x-1]
this.add(el + 1, oldb); // add [x+1..b]
}
}
}
get isReadonly() {
return this.readonly;
}
setReadonly(readonly) {
if (this.readonly && !readonly) {
throw new Error("can't alter readonly IntervalSet");
}
this.readonly = readonly;
}
}
__decorate([
Decorators_1.Override
], IntervalSet.prototype, "addAll", null);
__decorate([
Decorators_1.Override
], IntervalSet.prototype, "complement", null);
__decorate([
Decorators_1.Override
], IntervalSet.prototype, "subtract", null);
__decorate([
Decorators_1.Override
], IntervalSet.prototype, "or", null);
__decorate([
Decorators_1.Override
], IntervalSet.prototype, "and", null);
__decorate([
Decorators_1.Override
], IntervalSet.prototype, "contains", null);
__decorate([
Decorators_1.Override
], IntervalSet.prototype, "isNil", null);
__decorate([
Decorators_1.Override
], IntervalSet.prototype, "hashCode", null);
__decorate([
Decorators_1.Override
], IntervalSet.prototype, "equals", null);
__decorate([
__param(0, Decorators_1.NotNull)
], IntervalSet.prototype, "toStringVocabulary", null);
__decorate([
Decorators_1.NotNull,
__param(0, Decorators_1.NotNull)
], IntervalSet.prototype, "elementName", null);
__decorate([
Decorators_1.Override
], IntervalSet.prototype, "size", null);
__decorate([
Decorators_1.Override
], IntervalSet.prototype, "remove", null);
__decorate([
Decorators_1.NotNull
], IntervalSet, "of", null);
__decorate([
Decorators_1.NotNull
], IntervalSet, "subtract", null);
exports.IntervalSet = IntervalSet;
//# sourceMappingURL=IntervalSet.js.map