Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(654)

Side by Side Diff: lib/src/file.dart

Issue 1298093002: Support external implementations of FileSpan. (Closed) Base URL: git@github.com:dart-lang/source_span@master
Patch Set: Code review changes Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « CHANGELOG.md ('k') | pubspec.yaml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library source_span.file; 5 library source_span.file;
6 6
7 import 'dart:math' as math; 7 import 'dart:math' as math;
8 import 'dart:typed_data'; 8 import 'dart:typed_data';
9 9
10 import 'package:path/path.dart' as p;
11
12 import 'colors.dart' as colors;
13 import 'location.dart'; 10 import 'location.dart';
14 import 'span.dart'; 11 import 'span.dart';
15 import 'span_mixin.dart'; 12 import 'span_mixin.dart';
16 import 'span_with_context.dart'; 13 import 'span_with_context.dart';
17 import 'utils.dart'; 14 import 'utils.dart';
18 15
19 // Constants to determine end-of-lines. 16 // Constants to determine end-of-lines.
20 const int _LF = 10; 17 const int _LF = 10;
21 const int _CR = 13; 18 const int _CR = 13;
22 19
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 } 64 }
68 if (c == _LF) _lineStarts.add(i + 1); 65 if (c == _LF) _lineStarts.add(i + 1);
69 } 66 }
70 } 67 }
71 68
72 /// Returns a span in [this] from [start] to [end] (exclusive). 69 /// Returns a span in [this] from [start] to [end] (exclusive).
73 /// 70 ///
74 /// If [end] isn't passed, it defaults to the end of the file. 71 /// If [end] isn't passed, it defaults to the end of the file.
75 FileSpan span(int start, [int end]) { 72 FileSpan span(int start, [int end]) {
76 if (end == null) end = length - 1; 73 if (end == null) end = length - 1;
77 return new FileSpan._(this, start, end); 74 return new _FileSpan(this, start, end);
78 } 75 }
79 76
80 /// Returns a location in [this] at [offset]. 77 /// Returns a location in [this] at [offset].
81 FileLocation location(int offset) => new FileLocation._(this, offset); 78 FileLocation location(int offset) => new FileLocation._(this, offset);
82 79
83 /// Gets the 0-based line corresponding to [offset]. 80 /// Gets the 0-based line corresponding to [offset].
84 int getLine(int offset) { 81 int getLine(int offset) {
85 if (offset < 0) { 82 if (offset < 0) {
86 throw new RangeError("Offset may not be negative, was $offset."); 83 throw new RangeError("Offset may not be negative, was $offset.");
87 } else if (offset > length) { 84 } else if (offset > length) {
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
166 int get column => file.getColumn(offset); 163 int get column => file.getColumn(offset);
167 164
168 FileLocation._(this.file, int offset) 165 FileLocation._(this.file, int offset)
169 : super(offset) { 166 : super(offset) {
170 if (offset > file.length) { 167 if (offset > file.length) {
171 throw new RangeError("Offset $offset must not be greater than the number " 168 throw new RangeError("Offset $offset must not be greater than the number "
172 "of characters in the file, ${file.length}."); 169 "of characters in the file, ${file.length}.");
173 } 170 }
174 } 171 }
175 172
176 FileSpan pointSpan() => new FileSpan._(file, offset, offset); 173 FileSpan pointSpan() => new _FileSpan(file, offset, offset);
177 } 174 }
178 175
179 /// A [SourceSpan] within a [SourceFile]. 176 /// A [SourceSpan] within a [SourceFile].
180 /// 177 ///
181 /// Unlike the base [SourceSpan], [FileSpan] lazily computes its line and column 178 /// Unlike the base [SourceSpan], [FileSpan] lazily computes its line and column
182 /// values based on its offset and the contents of [file]. [FileSpan.message] is 179 /// values based on its offset and the contents of [file]. [FileSpan.message] is
183 /// also able to provide more context then [SourceSpan.message], and 180 /// also able to provide more context then [SourceSpan.message], and
184 /// [FileSpan.union] will return a [FileSpan] if possible. 181 /// [FileSpan.union] will return a [FileSpan] if possible.
185 /// 182 ///
186 /// A [FileSpan] can be created using [SourceFile.span]. 183 /// A [FileSpan] can be created using [SourceFile.span].
187 class FileSpan extends SourceSpanMixin implements SourceSpanWithContext { 184 abstract class FileSpan implements SourceSpanWithContext {
188 /// The [file] that [this] belongs to. 185 /// The [file] that [this] belongs to.
186 SourceFile get file;
187
188 /// Returns a new span that covers both [this] and [other].
189 ///
190 /// Unlike [union], [other] may be disjoint from [this]. If it is, the text
191 /// between the two will be covered by the returned span.
192 FileSpan expand(FileSpan other);
193 }
194
195 /// The implementation of [FileSpan].
196 ///
197 /// This is split into a separate class so that `is _FileSpan` checks can be run
198 /// to make certain operations more efficient. If we used `is FileSpan`, that
199 /// would break if external classes implemented the interface.
200 class _FileSpan extends SourceSpanMixin implements FileSpan {
189 final SourceFile file; 201 final SourceFile file;
190 202
191 /// The offset of the beginning of the span. 203 /// The offset of the beginning of the span.
192 /// 204 ///
193 /// [start] is lazily generated from this to avoid allocating unnecessary 205 /// [start] is lazily generated from this to avoid allocating unnecessary
194 /// objects. 206 /// objects.
195 final int _start; 207 final int _start;
196 208
197 /// The offset of the end of the span. 209 /// The offset of the end of the span.
198 /// 210 ///
199 /// [end] is lazily generated from this to avoid allocating unnecessary 211 /// [end] is lazily generated from this to avoid allocating unnecessary
200 /// objects. 212 /// objects.
201 final int _end; 213 final int _end;
202 214
203 Uri get sourceUrl => file.url; 215 Uri get sourceUrl => file.url;
204 int get length => _end - _start; 216 int get length => _end - _start;
205 FileLocation get start => new FileLocation._(file, _start); 217 FileLocation get start => new FileLocation._(file, _start);
206 FileLocation get end => new FileLocation._(file, _end); 218 FileLocation get end => new FileLocation._(file, _end);
207 String get text => file.getText(_start, _end); 219 String get text => file.getText(_start, _end);
208 String get context => file.getText(file.getOffset(start.line), 220 String get context => file.getText(file.getOffset(start.line),
209 end.line == file.lines - 1 ? null : file.getOffset(end.line + 1)); 221 end.line == file.lines - 1 ? null : file.getOffset(end.line + 1));
210 222
211 FileSpan._(this.file, this._start, this._end) { 223 _FileSpan(this.file, this._start, this._end) {
212 if (_end < _start) { 224 if (_end < _start) {
213 throw new ArgumentError('End $_end must come after start $_start.'); 225 throw new ArgumentError('End $_end must come after start $_start.');
214 } else if (_end > file.length) { 226 } else if (_end > file.length) {
215 throw new RangeError("End $_end must not be greater than the number " 227 throw new RangeError("End $_end must not be greater than the number "
216 "of characters in the file, ${file.length}."); 228 "of characters in the file, ${file.length}.");
217 } else if (_start < 0) { 229 } else if (_start < 0) {
218 throw new RangeError("Start may not be negative, was $_start."); 230 throw new RangeError("Start may not be negative, was $_start.");
219 } 231 }
220 } 232 }
221 233
222 int compareTo(SourceSpan other) { 234 int compareTo(SourceSpan other) {
223 if (other is! FileSpan) return super.compareTo(other); 235 if (other is! _FileSpan) return super.compareTo(other);
224 236
225 FileSpan otherFile = other; 237 _FileSpan otherFile = other;
226 var result = _start.compareTo(otherFile._start); 238 var result = _start.compareTo(otherFile._start);
227 return result == 0 ? _end.compareTo(otherFile._end) : result; 239 return result == 0 ? _end.compareTo(otherFile._end) : result;
228 } 240 }
229 241
230 SourceSpan union(SourceSpan other) { 242 SourceSpan union(SourceSpan other) {
231 if (other is! FileSpan) return super.union(other); 243 if (other is! FileSpan) return super.union(other);
232 244
233 var span = expand(other); 245 _FileSpan span = expand(other);
234 var beginSpan = span._start == _start ? this : other; 246 var beginSpan = span._start == _start ? this : other;
235 var endSpan = span._end == _end ? this : other; 247 var endSpan = span._end == _end ? this : other;
236 248
237 if (beginSpan._end < endSpan._start) { 249 if (beginSpan._end < endSpan._start) {
238 throw new ArgumentError("Spans $this and $other are disjoint."); 250 throw new ArgumentError("Spans $this and $other are disjoint.");
239 } 251 }
240 252
241 return span; 253 return span;
242 } 254 }
243 255
244 bool operator ==(other) { 256 bool operator ==(other) {
245 if (other is! FileSpan) return super == other; 257 if (other is! FileSpan) return super == other;
258 if (other is! _FileSpan) {
259 return super == other && sourceUrl == other.sourceUrl;
260 }
261
246 return _start == other._start && _end == other._end && 262 return _start == other._start && _end == other._end &&
247 sourceUrl == other.sourceUrl; 263 sourceUrl == other.sourceUrl;
248 } 264 }
249 265
250 int get hashCode => _start.hashCode + 5 * _end.hashCode +
251 7 * sourceUrl.hashCode;
252
253 /// Returns a new span that covers both [this] and [other]. 266 /// Returns a new span that covers both [this] and [other].
254 /// 267 ///
255 /// Unlike [union], [other] may be disjoint from [this]. If it is, the text 268 /// Unlike [union], [other] may be disjoint from [this]. If it is, the text
256 /// between the two will be covered by the returned span. 269 /// between the two will be covered by the returned span.
257 FileSpan expand(FileSpan other) { 270 FileSpan expand(FileSpan other) {
258 if (sourceUrl != other.sourceUrl) { 271 if (sourceUrl != other.sourceUrl) {
259 throw new ArgumentError("Source URLs \"${sourceUrl}\" and " 272 throw new ArgumentError("Source URLs \"${sourceUrl}\" and "
260 " \"${other.sourceUrl}\" don't match."); 273 " \"${other.sourceUrl}\" don't match.");
261 } 274 }
262 275
263 var start = math.min(this._start, other._start); 276 if (other is _FileSpan) {
264 var end = math.max(this._end, other._end); 277 var start = math.min(this._start, other._start);
265 return new FileSpan._(file, start, end); 278 var end = math.max(this._end, other._end);
279 return new _FileSpan(file, start, end);
280 } else {
281 var start = math.min(this._start, other.start.offset);
282 var end = math.max(this._end, other.end.offset);
283 return new _FileSpan(file, start, end);
284 }
266 } 285 }
267 } 286 }
OLDNEW
« no previous file with comments | « CHANGELOG.md ('k') | pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698