package melnorme.lang.tooling.ast;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue;
import static melnorme.utilbox.core.CoreUtil.downCast;
import melnorme.utilbox.misc.NumberUtil;
public final class SourceRange implements Comparable<SourceRange> {
public final int offset;
public final int length;
public SourceRange(int offset, int length) {
assertTrue(offset >= 0);
assertTrue(length >= 0);
this.offset = offset;
this.length = length;
}
public static SourceRange srStartToEnd(int startPos, int endPos) {
assertTrue(startPos >= 0 && endPos >= startPos);
return new SourceRange(startPos, endPos - startPos);
}
public final int getOffset() {
return offset;
}
public final int getLength() {
return length;
}
public final int getStartPos() {
return getOffset();
}
public final int getEndPos() {
return getOffset() + getLength();
}
@Override
public final String toString() {
return "[" + offset + "+" + length + "]";
}
@Override
public final boolean equals(Object obj) {
if(!(obj instanceof SourceRange))
return false;
SourceRange other = downCast(obj);
return this.offset == other.offset && this.length == other.length;
}
@Override
public int compareTo(SourceRange other) {
if(offset == other.offset) {
return length - other.length;
}
return offset - other.offset;
}
/* ----------------- ----------------- */
public boolean contains(SourceRange other) {
return contains(other.getStartPos()) && contains(other.getEndPos());
}
public boolean contains(int otherOffset) {
return NumberUtil.isInRange(getStartPos(), otherOffset, getEndPos());
}
public boolean inclusiveContains(int otherOffset) {
return contains(otherOffset);
}
public boolean inclusiveContains(SourceRange other) {
return contains(other);
}
/* ----------------- ----------------- */
/** @return a substring of given source using the range of the receiver. */
public String getRangeSubString(String source) {
return source.substring(getStartPos(), getEndPos());
}
}