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