Add SourceLocationMixin and SourceLocationBase.
This allows FileLocation to avoid extending SourceLocation at all, which
avoids unused line, column, and sourceUrl fields. This produces a speed
improvement of approximately 5% in the YAML parser, and will likely do
more in code that uses locations more heavily relative to spans.
R=rnystrom@google.com
Review URL: https://codereview.chromium.org//1307123004 .
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6bd18f1..ab13bda 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
# 1.2.0
+* **Deprecated:** Extending `SourceLocation` directly is deprecated. Instead,
+ extend the new `SourceLocationBase` class or mix in the new
+ `SourceLocationMixin` mixin.
+
* Dramatically improve the performance of `FileLocation`.
# 1.1.6
diff --git a/lib/source_span.dart b/lib/source_span.dart
index 89b1650..9666dc2 100644
--- a/lib/source_span.dart
+++ b/lib/source_span.dart
@@ -6,6 +6,7 @@
export "src/file.dart";
export "src/location.dart";
+export "src/location_mixin.dart";
export "src/span.dart";
export "src/span_exception.dart";
export "src/span_mixin.dart";
diff --git a/lib/src/file.dart b/lib/src/file.dart
index c2b97e7..95fa92c 100644
--- a/lib/src/file.dart
+++ b/lib/src/file.dart
@@ -8,6 +8,7 @@
import 'dart:typed_data';
import 'location.dart';
+import 'location_mixin.dart';
import 'span.dart';
import 'span_mixin.dart';
import 'span_with_context.dart';
@@ -212,17 +213,19 @@
/// and column values based on its offset and the contents of [file].
///
/// A [FileLocation] can be created using [SourceFile.location].
-class FileLocation extends SourceLocation {
+class FileLocation extends SourceLocationMixin implements SourceLocation {
/// The [file] that [this] belongs to.
final SourceFile file;
+ final int offset;
Uri get sourceUrl => file.url;
int get line => file.getLine(offset);
int get column => file.getColumn(offset);
- FileLocation._(this.file, int offset)
- : super(offset) {
- if (offset > file.length) {
+ FileLocation._(this.file, this.offset) {
+ if (offset < 0) {
+ throw new RangeError("Offset may not be negative, was $offset.");
+ } else if (offset > file.length) {
throw new RangeError("Offset $offset must not be greater than the number "
"of characters in the file, ${file.length}.");
}
diff --git a/lib/src/location.dart b/lib/src/location.dart
index 024c6e2..afb37c7 100644
--- a/lib/src/location.dart
+++ b/lib/src/location.dart
@@ -6,7 +6,13 @@
import 'span.dart';
-// A class that describes a single location within a source file.
+// TODO(nweiz): Use SourceLocationMixin once we decide to cut a release with
+// breaking changes. See SourceLocationMixin for details.
+
+/// A class that describes a single location within a source file.
+///
+/// This class should not be extended. Instead, [SourceLocationBase] should be
+/// extended instead.
class SourceLocation implements Comparable<SourceLocation> {
/// URL of the source containing this location.
///
@@ -85,3 +91,10 @@
String toString() => '<$runtimeType: $offset $toolString>';
}
+
+/// A base class for source locations with [offset], [line], and [column] known
+/// at construction time.
+class SourceLocationBase extends SourceLocation {
+ SourceLocationBase(int offset, {sourceUrl, int line, int column})
+ : super(offset, sourceUrl: sourceUrl, line: line, column: column);
+}
diff --git a/lib/src/location_mixin.dart b/lib/src/location_mixin.dart
new file mode 100644
index 0000000..5aa0de5
--- /dev/null
+++ b/lib/src/location_mixin.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2015, 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.
+
+library source_span.location_mixin;
+
+import 'location.dart';
+import 'span.dart';
+
+// Note: this class duplicates a lot of functionality of [SourceLocation]. This
+// is because in order for SourceLocation to use SourceLocationMixin,
+// SourceLocationMixin couldn't implement SourceLocation. In SourceSpan we
+// handle this by making the class itself non-extensible, but that would be a
+// breaking change for SourceLocation. So until we want to endure the pain of
+// cutting a release with breaking changes, we duplicate the code here.
+
+/// A mixin for easily implementing [SourceLocation].
+abstract class SourceLocationMixin implements SourceLocation {
+ String get toolString {
+ var source = sourceUrl == null ? 'unknown source' : sourceUrl;
+ return '$source:${line + 1}:${column + 1}';
+ }
+
+ int distance(SourceLocation other) {
+ if (sourceUrl != other.sourceUrl) {
+ throw new ArgumentError("Source URLs \"${sourceUrl}\" and "
+ "\"${other.sourceUrl}\" don't match.");
+ }
+ return (offset - other.offset).abs();
+ }
+
+ SourceSpan pointSpan() => new SourceSpan(this, this, "");
+
+ int compareTo(SourceLocation other) {
+ if (sourceUrl != other.sourceUrl) {
+ throw new ArgumentError("Source URLs \"${sourceUrl}\" and "
+ "\"${other.sourceUrl}\" don't match.");
+ }
+ return offset - other.offset;
+ }
+
+ bool operator ==(other) =>
+ other is SourceLocation &&
+ sourceUrl == other.sourceUrl &&
+ offset == other.offset;
+
+ int get hashCode => sourceUrl.hashCode + offset;
+
+ String toString() => '<$runtimeType: $offset $toolString>';
+}
+
diff --git a/pubspec.yaml b/pubspec.yaml
index 7ffbc64..25de799 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
name: source_span
-version: 1.2.0-dev
+version: 1.2.0
author: Dart Team <misc@dartlang.org>
description: A library for identifying source spans and locations.
homepage: https://github.com/dart-lang/source_span