blob: 338ad7ad9fe770e982979eb3cf64ec1993278907 [file] [log] [blame]
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import "dart:math" as math;
/**
* A source range defines a range of characters within source code.
*/
class SourceRange {
/**
* An empty source range (a range with offset `0` and length `0`).
*/
static const SourceRange EMPTY = const SourceRange(0, 0);
/**
* The 0-based index of the first character of the source range.
*/
final int offset;
/**
* The number of characters in the source range.
*/
final int length;
/**
* Initialize a newly created source range using the given [offset] and
* [length].
*/
const SourceRange(this.offset, this.length);
/**
* Return the 0-based index of the character immediately after this source
* range.
*/
int get end => offset + length;
@override
int get hashCode => 31 * offset + length;
@override
bool operator ==(Object other) {
return other is SourceRange &&
other.offset == offset &&
other.length == length;
}
/**
* Return `true` if [x] is in the interval `[offset, offset + length)`.
*/
bool contains(int x) => offset <= x && x < offset + length;
/**
* Return `true` if [x] is in the interval `(offset, offset + length)`.
*/
bool containsExclusive(int x) => offset < x && x < offset + length;
/**
* Return `true` if the [otherRange] covers this source range.
*/
bool coveredBy(SourceRange otherRange) => otherRange.covers(this);
/**
* Return `true` if this source range covers the [otherRange].
*/
bool covers(SourceRange otherRange) =>
offset <= otherRange.offset && otherRange.end <= end;
/**
* Return `true` if this source range ends inside the [otherRange].
*/
bool endsIn(SourceRange otherRange) {
int thisEnd = end;
return otherRange.contains(thisEnd);
}
/**
* Return a source range covering [delta] characters before the start of this
* source range and [delta] characters after the end of this source range.
*/
SourceRange getExpanded(int delta) =>
new SourceRange(offset - delta, delta + length + delta);
/**
* Return a source range with the same offset as this source range but whose
* length is [delta] characters longer than this source range.
*/
SourceRange getMoveEnd(int delta) => new SourceRange(offset, length + delta);
/**
* Return a source range with the same length as this source range but whose
* offset is [delta] characters after the offset of this source range.
*/
SourceRange getTranslated(int delta) =>
new SourceRange(offset + delta, length);
/**
* Return the minimal source range that covers both this and the [otherRange].
*/
SourceRange getUnion(SourceRange otherRange) {
int newOffset = math.min(offset, otherRange.offset);
int newEnd =
math.max(offset + length, otherRange.offset + otherRange.length);
return new SourceRange(newOffset, newEnd - newOffset);
}
/**
* Return `true` if this source range intersects the [otherRange].
*/
bool intersects(SourceRange otherRange) {
if (otherRange == null) {
return false;
}
if (end <= otherRange.offset) {
return false;
}
if (offset >= otherRange.end) {
return false;
}
return true;
}
/**
* Return `true` if this source range starts in the [otherRange].
*/
bool startsIn(SourceRange otherRange) => otherRange.contains(offset);
@override
String toString() => '[offset=$offset, length=$length]';
}