refactored IntervalSet.js to use es6 classes

use const/let for better scoping
This commit is contained in:
Camilo Roca 2020-03-15 16:29:28 +01:00
parent 23351cadc4
commit a3c380d7d4
1 changed files with 258 additions and 261 deletions

View File

@ -3,296 +3,293 @@
* can be found in the LICENSE.txt file in the project root.
*/
/*jslint smarttabs:true */
var Token = require('./Token').Token;
const {Token} = require('./Token');
/* stop is not included! */
function Interval(start, stop) {
this.start = start;
this.stop = stop;
return this;
}
Interval.prototype.contains = function(item) {
return item >= this.start && item < this.stop;
};
Interval.prototype.toString = function() {
if(this.start===this.stop-1) {
return this.start.toString();
} else {
return this.start.toString() + ".." + (this.stop-1).toString();
class Interval {
constructor(start, stop) {
this.start = start;
this.stop = stop;
}
};
contains(item) {
return item >= this.start && item < this.stop;
}
Object.defineProperty(Interval.prototype, "length", {
get : function() {
toString() {
if(this.start===this.stop-1) {
return this.start.toString();
} else {
return this.start.toString() + ".." + (this.stop-1).toString();
}
}
get length(){
return this.stop - this.start;
}
});
function IntervalSet() {
this.intervals = null;
this.readOnly = false;
}
IntervalSet.prototype.first = function(v) {
if (this.intervals === null || this.intervals.length===0) {
return Token.INVALID_TYPE;
} else {
return this.intervals[0].start;
class IntervalSet {
constructor() {
this.intervals = null;
this.readOnly = false;
}
};
IntervalSet.prototype.addOne = function(v) {
this.addInterval(new Interval(v, v + 1));
};
first(v) {
if (this.intervals === null || this.intervals.length===0) {
return Token.INVALID_TYPE;
} else {
return this.intervals[0].start;
}
}
IntervalSet.prototype.addRange = function(l, h) {
this.addInterval(new Interval(l, h + 1));
};
addOne(v) {
this.addInterval(new Interval(v, v + 1));
}
IntervalSet.prototype.addInterval = function(v) {
if (this.intervals === null) {
this.intervals = [];
this.intervals.push(v);
} else {
// find insert pos
for (var k = 0; k < this.intervals.length; k++) {
var i = this.intervals[k];
// distinct range -> insert
if (v.stop < i.start) {
this.intervals.splice(k, 0, v);
return;
addRange(l, h) {
this.addInterval(new Interval(l, h + 1));
}
addInterval(v) {
if (this.intervals === null) {
this.intervals = [];
this.intervals.push(v);
} else {
// find insert pos
for (let k = 0; k < this.intervals.length; k++) {
const i = this.intervals[k];
// distinct range -> insert
if (v.stop < i.start) {
this.intervals.splice(k, 0, v);
return;
}
// contiguous range -> adjust
else if (v.stop === i.start) {
this.intervals[k].start = v.start;
return;
}
// overlapping range -> adjust and reduce
else if (v.start <= i.stop) {
this.intervals[k] = new Interval(Math.min(i.start, v.start), Math.max(i.stop, v.stop));
this.reduce(k);
return;
}
}
// contiguous range -> adjust
else if (v.stop === i.start) {
this.intervals[k].start = v.start;
return;
// greater than any existing
this.intervals.push(v);
}
}
addSet(other) {
if (other.intervals !== null) {
for (let k = 0; k < other.intervals.length; k++) {
const i = other.intervals[k];
this.addInterval(new Interval(i.start, i.stop));
}
// overlapping range -> adjust and reduce
else if (v.start <= i.stop) {
this.intervals[k] = new Interval(Math.min(i.start, v.start), Math.max(i.stop, v.stop));
}
return this;
}
reduce(k) {
// only need to reduce if k is not the last
if (k < this.intervalslength - 1) {
const l = this.intervals[k];
const r = this.intervals[k + 1];
// if r contained in l
if (l.stop >= r.stop) {
this.intervals.pop(k + 1);
this.reduce(k);
return;
} else if (l.stop >= r.start) {
this.intervals[k] = new Interval(l.start, r.stop);
this.intervals.pop(k + 1);
}
}
// greater than any existing
this.intervals.push(v);
}
};
IntervalSet.prototype.addSet = function(other) {
if (other.intervals !== null) {
for (var k = 0; k < other.intervals.length; k++) {
var i = other.intervals[k];
this.addInterval(new Interval(i.start, i.stop));
complement(start, stop) {
const result = new IntervalSet();
result.addInterval(new Interval(start,stop+1));
for(let i=0; i<this.intervals.length; i++) {
result.removeRange(this.intervals[i]);
}
return result;
}
contains(item) {
if (this.intervals === null) {
return false;
} else {
for (let k = 0; k < this.intervals.length; k++) {
if(this.intervals[k].contains(item)) {
return true;
}
}
return false;
}
}
return this;
};
IntervalSet.prototype.reduce = function(k) {
// only need to reduce if k is not the last
if (k < this.intervalslength - 1) {
var l = this.intervals[k];
var r = this.intervals[k + 1];
// if r contained in l
if (l.stop >= r.stop) {
this.intervals.pop(k + 1);
this.reduce(k);
} else if (l.stop >= r.start) {
this.intervals[k] = new Interval(l.start, r.stop);
this.intervals.pop(k + 1);
}
}
};
IntervalSet.prototype.complement = function(start, stop) {
var result = new IntervalSet();
result.addInterval(new Interval(start,stop+1));
for(var i=0; i<this.intervals.length; i++) {
result.removeRange(this.intervals[i]);
}
return result;
};
IntervalSet.prototype.contains = function(item) {
if (this.intervals === null) {
return false;
} else {
for (var k = 0; k < this.intervals.length; k++) {
if(this.intervals[k].contains(item)) {
return true;
removeRange(v) {
if(v.start===v.stop-1) {
this.removeOne(v.start);
} else if (this.intervals!==null) {
let k = 0;
for(let n=0; n<this.intervals.length; n++) {
const i = this.intervals[k];
// intervals are ordered
if (v.stop<=i.start) {
return;
}
// check for including range, split it
else if(v.start>i.start && v.stop<i.stop) {
this.intervals[k] = new Interval(i.start, v.start);
const x = new Interval(v.stop, i.stop);
this.intervals.splice(k, 0, x);
return;
}
// check for included range, remove it
else if(v.start<=i.start && v.stop>=i.stop) {
this.intervals.splice(k, 1);
k = k - 1; // need another pass
}
// check for lower boundary
else if(v.start<i.stop) {
this.intervals[k] = new Interval(i.start, v.start);
}
// check for upper boundary
else if(v.stop<i.stop) {
this.intervals[k] = new Interval(v.stop, i.stop);
}
k += 1;
}
}
return false;
}
};
Object.defineProperty(IntervalSet.prototype, "length", {
get : function() {
var len = 0;
removeOne(v) {
if (this.intervals !== null) {
for (let k = 0; k < this.intervals.length; k++) {
const i = this.intervals[k];
// intervals is ordered
if (v < i.start) {
return;
}
// check for single value range
else if (v === i.start && v === i.stop - 1) {
this.intervals.splice(k, 1);
return;
}
// check for lower boundary
else if (v === i.start) {
this.intervals[k] = new Interval(i.start + 1, i.stop);
return;
}
// check for upper boundary
else if (v === i.stop - 1) {
this.intervals[k] = new Interval(i.start, i.stop - 1);
return;
}
// split existing range
else if (v < i.stop - 1) {
const x = new Interval(i.start, v);
i.start = v + 1;
this.intervals.splice(k, 0, x);
return;
}
}
}
}
toString(literalNames, symbolicNames, elemsAreChar) {
literalNames = literalNames || null;
symbolicNames = symbolicNames || null;
elemsAreChar = elemsAreChar || false;
if (this.intervals === null) {
return "{}";
} else if(literalNames!==null || symbolicNames!==null) {
return this.toTokenString(literalNames, symbolicNames);
} else if(elemsAreChar) {
return this.toCharString();
} else {
return this.toIndexString();
}
}
toCharString() {
const names = [];
for (let i = 0; i < this.intervals.length; i++) {
const v = this.intervals[i];
if(v.stop===v.start+1) {
if ( v.start===Token.EOF ) {
names.push("<EOF>");
} else {
names.push("'" + String.fromCharCode(v.start) + "'");
}
} else {
names.push("'" + String.fromCharCode(v.start) + "'..'" + String.fromCharCode(v.stop-1) + "'");
}
}
if (names.length > 1) {
return "{" + names.join(", ") + "}";
} else {
return names[0];
}
}
toIndexString() {
const names = [];
for (let i = 0; i < this.intervals.length; i++) {
const v = this.intervals[i];
if(v.stop===v.start+1) {
if ( v.start===Token.EOF ) {
names.push("<EOF>");
} else {
names.push(v.start.toString());
}
} else {
names.push(v.start.toString() + ".." + (v.stop-1).toString());
}
}
if (names.length > 1) {
return "{" + names.join(", ") + "}";
} else {
return names[0];
}
}
toTokenString(literalNames, symbolicNames) {
const names = [];
for (let i = 0; i < this.intervals.length; i++) {
const v = this.intervals[i];
for (let j = v.start; j < v.stop; j++) {
names.push(this.elementName(literalNames, symbolicNames, j));
}
}
if (names.length > 1) {
return "{" + names.join(", ") + "}";
} else {
return names[0];
}
}
elementName(literalNames, symbolicNames, a) {
if (a === Token.EOF) {
return "<EOF>";
} else if (a === Token.EPSILON) {
return "<EPSILON>";
} else {
return literalNames[a] || symbolicNames[a];
}
}
get length(){
let len = 0;
this.intervals.map(function(i) {len += i.length;});
return len;
}
});
}
IntervalSet.prototype.removeRange = function(v) {
if(v.start===v.stop-1) {
this.removeOne(v.start);
} else if (this.intervals!==null) {
var k = 0;
for(var n=0; n<this.intervals.length; n++) {
var i = this.intervals[k];
// intervals are ordered
if (v.stop<=i.start) {
return;
}
// check for including range, split it
else if(v.start>i.start && v.stop<i.stop) {
this.intervals[k] = new Interval(i.start, v.start);
var x = new Interval(v.stop, i.stop);
this.intervals.splice(k, 0, x);
return;
}
// check for included range, remove it
else if(v.start<=i.start && v.stop>=i.stop) {
this.intervals.splice(k, 1);
k = k - 1; // need another pass
}
// check for lower boundary
else if(v.start<i.stop) {
this.intervals[k] = new Interval(i.start, v.start);
}
// check for upper boundary
else if(v.stop<i.stop) {
this.intervals[k] = new Interval(v.stop, i.stop);
}
k += 1;
}
}
module.exports = {
Interval,
IntervalSet
};
IntervalSet.prototype.removeOne = function(v) {
if (this.intervals !== null) {
for (var k = 0; k < this.intervals.length; k++) {
var i = this.intervals[k];
// intervals is ordered
if (v < i.start) {
return;
}
// check for single value range
else if (v === i.start && v === i.stop - 1) {
this.intervals.splice(k, 1);
return;
}
// check for lower boundary
else if (v === i.start) {
this.intervals[k] = new Interval(i.start + 1, i.stop);
return;
}
// check for upper boundary
else if (v === i.stop - 1) {
this.intervals[k] = new Interval(i.start, i.stop - 1);
return;
}
// split existing range
else if (v < i.stop - 1) {
var x = new Interval(i.start, v);
i.start = v + 1;
this.intervals.splice(k, 0, x);
return;
}
}
}
};
IntervalSet.prototype.toString = function(literalNames, symbolicNames, elemsAreChar) {
literalNames = literalNames || null;
symbolicNames = symbolicNames || null;
elemsAreChar = elemsAreChar || false;
if (this.intervals === null) {
return "{}";
} else if(literalNames!==null || symbolicNames!==null) {
return this.toTokenString(literalNames, symbolicNames);
} else if(elemsAreChar) {
return this.toCharString();
} else {
return this.toIndexString();
}
};
IntervalSet.prototype.toCharString = function() {
var names = [];
for (var i = 0; i < this.intervals.length; i++) {
var v = this.intervals[i];
if(v.stop===v.start+1) {
if ( v.start===Token.EOF ) {
names.push("<EOF>");
} else {
names.push("'" + String.fromCharCode(v.start) + "'");
}
} else {
names.push("'" + String.fromCharCode(v.start) + "'..'" + String.fromCharCode(v.stop-1) + "'");
}
}
if (names.length > 1) {
return "{" + names.join(", ") + "}";
} else {
return names[0];
}
};
IntervalSet.prototype.toIndexString = function() {
var names = [];
for (var i = 0; i < this.intervals.length; i++) {
var v = this.intervals[i];
if(v.stop===v.start+1) {
if ( v.start===Token.EOF ) {
names.push("<EOF>");
} else {
names.push(v.start.toString());
}
} else {
names.push(v.start.toString() + ".." + (v.stop-1).toString());
}
}
if (names.length > 1) {
return "{" + names.join(", ") + "}";
} else {
return names[0];
}
};
IntervalSet.prototype.toTokenString = function(literalNames, symbolicNames) {
var names = [];
for (var i = 0; i < this.intervals.length; i++) {
var v = this.intervals[i];
for (var j = v.start; j < v.stop; j++) {
names.push(this.elementName(literalNames, symbolicNames, j));
}
}
if (names.length > 1) {
return "{" + names.join(", ") + "}";
} else {
return names[0];
}
};
IntervalSet.prototype.elementName = function(literalNames, symbolicNames, a) {
if (a === Token.EOF) {
return "<EOF>";
} else if (a === Token.EPSILON) {
return "<EPSILON>";
} else {
return literalNames[a] || symbolicNames[a];
}
};
exports.Interval = Interval;
exports.IntervalSet = IntervalSet;