// 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 = 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) => 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) => 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) => 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 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]'; }