bitmark-grammar
Version:
687 lines (686 loc) • 24.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); }
};
exports.__esModule = true;
exports.IntervalSet = void 0;
// ConvertTo-TS run at 2016-10-04T11:26:40.8683480-07:00
var ArrayEqualityComparator_1 = require("./ArrayEqualityComparator");
var IntegerList_1 = require("./IntegerList");
var Interval_1 = require("./Interval");
var Lexer_1 = require("../Lexer");
var MurmurHash_1 = require("./MurmurHash");
var Decorators_1 = require("../Decorators");
var 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).
*/
var IntervalSet = /** @class */ (function () {
function IntervalSet(intervals) {
this.readonly = false;
if (intervals != null) {
this._intervals = intervals.slice(0);
}
else {
this._intervals = [];
}
}
Object.defineProperty(IntervalSet, "COMPLETE_CHAR_SET", {
get: function () {
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;
},
enumerable: false,
configurable: true
});
Object.defineProperty(IntervalSet, "EMPTY_SET", {
get: function () {
if (IntervalSet._EMPTY_SET == null) {
IntervalSet._EMPTY_SET = new IntervalSet();
IntervalSet._EMPTY_SET.setReadonly(true);
}
return IntervalSet._EMPTY_SET;
},
enumerable: false,
configurable: true
});
/**
* Create a set with all ints within range [a..b] (inclusive). If b is omitted, the set contains the single element
* a.
*/
IntervalSet.of = function (a, b) {
if (b === void 0) { b = a; }
var s = new IntervalSet();
s.add(a, b);
return s;
};
IntervalSet.prototype.clear = function () {
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}.
*/
IntervalSet.prototype.add = function (a, b) {
if (b === void 0) { b = a; }
this.addRange(Interval_1.Interval.of(a, b));
};
// copy on write so we can cache a..a intervals and sets of that
IntervalSet.prototype.addRange = function (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 (var i = 0; i < this._intervals.length; i++) {
var 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
var 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++;
var 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 */
IntervalSet.or = function (sets) {
var r = new IntervalSet();
for (var _i = 0, sets_1 = sets; _i < sets_1.length; _i++) {
var s = sets_1[_i];
r.addAll(s);
}
return r;
};
IntervalSet.prototype.addAll = function (set) {
if (set == null) {
return this;
}
if (set instanceof IntervalSet) {
var other = set;
// walk set and add each interval
var n = other._intervals.length;
for (var i = 0; i < n; i++) {
var I = other._intervals[i];
this.add(I.a, I.b);
}
}
else {
for (var _i = 0, _a = set.toArray(); _i < _a.length; _i++) {
var value = _a[_i];
this.add(value);
}
}
return this;
};
IntervalSet.prototype.complementRange = function (minElement, maxElement) {
return this.complement(IntervalSet.of(minElement, maxElement));
};
/** {@inheritDoc} */
IntervalSet.prototype.complement = function (vocabulary) {
if (vocabulary.isNil) {
// nothing in common with null set
return IntervalSet.EMPTY_SET;
}
var vocabularyIS;
if (vocabulary instanceof IntervalSet) {
vocabularyIS = vocabulary;
}
else {
vocabularyIS = new IntervalSet();
vocabularyIS.addAll(vocabulary);
}
return vocabularyIS.subtract(this);
};
IntervalSet.prototype.subtract = function (a) {
if (a == null || a.isNil) {
return new IntervalSet(this._intervals);
}
if (a instanceof IntervalSet) {
return IntervalSet.subtract(this, a);
}
var 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`.
*/
IntervalSet.subtract = function (left, right) {
if (left.isNil) {
return new IntervalSet();
}
var result = new IntervalSet(left._intervals);
if (right.isNil) {
// right set has no elements; just return the copy of the current set
return result;
}
var resultI = 0;
var rightI = 0;
while (resultI < result._intervals.length && rightI < right._intervals.length) {
var resultInterval = result._intervals[resultI];
var rightInterval = right._intervals[rightI];
// operation: (resultInterval - rightInterval) and update indexes
if (rightInterval.b < resultInterval.a) {
rightI++;
continue;
}
if (rightInterval.a > resultInterval.b) {
resultI++;
continue;
}
var beforeCurrent = void 0;
var afterCurrent = void 0;
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;
};
IntervalSet.prototype.or = function (a) {
var o = new IntervalSet();
o.addAll(this);
o.addAll(a);
return o;
};
/** {@inheritDoc} */
IntervalSet.prototype.and = function (other) {
if (other.isNil) { //|| !(other instanceof IntervalSet) ) {
// nothing in common with null set
return new IntervalSet();
}
var myIntervals = this._intervals;
var theirIntervals = other._intervals;
var intersection;
var mySize = myIntervals.length;
var theirSize = theirIntervals.length;
var i = 0;
var j = 0;
// iterate down both interval lists looking for nondisjoint intervals
while (i < mySize && j < theirSize) {
var mine = myIntervals[i];
var 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} */
IntervalSet.prototype.contains = function (el) {
var n = this._intervals.length;
var l = 0;
var r = n - 1;
// Binary search for the element in the (sorted, disjoint) array of intervals.
while (l <= r) {
var m = (l + r) >> 1;
var I = this._intervals[m];
var a = I.a;
var 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;
};
Object.defineProperty(IntervalSet.prototype, "isNil", {
/** {@inheritDoc} */
get: function () {
return this._intervals == null || this._intervals.length === 0;
},
enumerable: false,
configurable: true
});
Object.defineProperty(IntervalSet.prototype, "maxElement", {
/**
* 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: function () {
if (this.isNil) {
throw new RangeError("set is empty");
}
var last = this._intervals[this._intervals.length - 1];
return last.b;
},
enumerable: false,
configurable: true
});
Object.defineProperty(IntervalSet.prototype, "minElement", {
/**
* 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: function () {
if (this.isNil) {
throw new RangeError("set is empty");
}
return this._intervals[0].a;
},
enumerable: false,
configurable: true
});
Object.defineProperty(IntervalSet.prototype, "intervals", {
/** Return a list of Interval objects. */
get: function () {
return this._intervals;
},
enumerable: false,
configurable: true
});
IntervalSet.prototype.hashCode = function () {
var hash = MurmurHash_1.MurmurHash.initialize();
for (var _i = 0, _a = this._intervals; _i < _a.length; _i++) {
var I = _a[_i];
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.
*/
IntervalSet.prototype.equals = function (o) {
if (o == null || !(o instanceof IntervalSet)) {
return false;
}
return ArrayEqualityComparator_1.ArrayEqualityComparator.INSTANCE.equals(this._intervals, o._intervals);
};
IntervalSet.prototype.toString = function (elemAreChar) {
if (elemAreChar === void 0) { elemAreChar = false; }
var buf = "";
if (this._intervals == null || this._intervals.length === 0) {
return "{}";
}
if (this.size > 1) {
buf += "{";
}
var first = true;
for (var _i = 0, _a = this._intervals; _i < _a.length; _i++) {
var I = _a[_i];
if (first) {
first = false;
}
else {
buf += ", ";
}
var a = I.a;
var 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;
};
IntervalSet.prototype.toStringVocabulary = function (vocabulary) {
if (this._intervals == null || this._intervals.length === 0) {
return "{}";
}
var buf = "";
if (this.size > 1) {
buf += "{";
}
var first = true;
for (var _i = 0, _a = this._intervals; _i < _a.length; _i++) {
var I = _a[_i];
if (first) {
first = false;
}
else {
buf += ", ";
}
var a = I.a;
var b = I.b;
if (a === b) {
buf += this.elementName(vocabulary, a);
}
else {
for (var i = a; i <= b; i++) {
if (i > a) {
buf += ", ";
}
buf += this.elementName(vocabulary, i);
}
}
}
if (this.size > 1) {
buf += "}";
}
return buf;
};
IntervalSet.prototype.elementName = function (vocabulary, a) {
if (a === Token_1.Token.EOF) {
return "<EOF>";
}
else if (a === Token_1.Token.EPSILON) {
return "<EPSILON>";
}
else {
return vocabulary.getDisplayName(a);
}
};
Object.defineProperty(IntervalSet.prototype, "size", {
get: function () {
var n = 0;
var numIntervals = this._intervals.length;
if (numIntervals === 1) {
var firstInterval = this._intervals[0];
return firstInterval.b - firstInterval.a + 1;
}
for (var i = 0; i < numIntervals; i++) {
var I = this._intervals[i];
n += (I.b - I.a + 1);
}
return n;
},
enumerable: false,
configurable: true
});
IntervalSet.prototype.toIntegerList = function () {
var values = new IntegerList_1.IntegerList(this.size);
var n = this._intervals.length;
for (var i = 0; i < n; i++) {
var I = this._intervals[i];
var a = I.a;
var b = I.b;
for (var v = a; v <= b; v++) {
values.add(v);
}
}
return values;
};
IntervalSet.prototype.toSet = function () {
var s = new Set();
for (var _i = 0, _a = this._intervals; _i < _a.length; _i++) {
var I = _a[_i];
var a = I.a;
var b = I.b;
for (var v = a; v <= b; v++) {
s.add(v);
}
}
return s;
};
IntervalSet.prototype.toArray = function () {
var values = new Array();
var n = this._intervals.length;
for (var i = 0; i < n; i++) {
var I = this._intervals[i];
var a = I.a;
var b = I.b;
for (var v = a; v <= b; v++) {
values.push(v);
}
}
return values;
};
IntervalSet.prototype.remove = function (el) {
if (this.readonly) {
throw new Error("can't alter readonly IntervalSet");
}
var n = this._intervals.length;
for (var i = 0; i < n; i++) {
var I = this._intervals[i];
var a = I.a;
var 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
var 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]
}
}
};
Object.defineProperty(IntervalSet.prototype, "isReadonly", {
get: function () {
return this.readonly;
},
enumerable: false,
configurable: true
});
IntervalSet.prototype.setReadonly = function (readonly) {
if (this.readonly && !readonly) {
throw new Error("can't alter readonly IntervalSet");
}
this.readonly = readonly;
};
__decorate([
Decorators_1.Override
], IntervalSet.prototype, "addAll");
__decorate([
Decorators_1.Override
], IntervalSet.prototype, "complement");
__decorate([
Decorators_1.Override
], IntervalSet.prototype, "subtract");
__decorate([
Decorators_1.Override
], IntervalSet.prototype, "or");
__decorate([
Decorators_1.Override
], IntervalSet.prototype, "and");
__decorate([
Decorators_1.Override
], IntervalSet.prototype, "contains");
__decorate([
Decorators_1.Override
], IntervalSet.prototype, "isNil");
__decorate([
Decorators_1.Override
], IntervalSet.prototype, "hashCode");
__decorate([
Decorators_1.Override
], IntervalSet.prototype, "equals");
__decorate([
__param(0, Decorators_1.NotNull)
], IntervalSet.prototype, "toStringVocabulary");
__decorate([
Decorators_1.NotNull,
__param(0, Decorators_1.NotNull)
], IntervalSet.prototype, "elementName");
__decorate([
Decorators_1.Override
], IntervalSet.prototype, "size");
__decorate([
Decorators_1.Override
], IntervalSet.prototype, "remove");
__decorate([
Decorators_1.NotNull
], IntervalSet, "of");
__decorate([
Decorators_1.NotNull
], IntervalSet, "subtract");
return IntervalSet;
}());
exports.IntervalSet = IntervalSet;