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

Side by Side Diff: lib/span.dart

Issue 12937009: renaming File to Source (Closed) Base URL: git@github.com:dart-lang/source-maps.git@master
Patch Set: Created 7 years, 9 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
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 /// Dart classes representing the souce spans and source files. 5 /// Dart classes representing the souce spans and source files.
6 library source_maps.span; 6 library source_maps.span;
7 7
8 import 'dart:utf' show stringToCodepoints, codepointsToString; 8 import 'dart:utf' show stringToCodepoints, codepointsToString;
9 import 'dart:math' show min; 9 import 'dart:math' show min;
10 10
11 import 'src/utils.dart'; 11 import 'src/utils.dart';
12 12
13 /// A simple class that describe a segment of source text. 13 /// A simple class that describe a segment of source text.
14 abstract class Span implements Comparable { 14 abstract class Span implements Comparable {
15 /// The start location of this span. 15 /// The start location of this span.
16 final Location start; 16 final Location start;
17 17
18 /// The end location of this span, exclusive. 18 /// The end location of this span, exclusive.
19 final Location end; 19 final Location end;
20 20
21 /// Url of the file containing this span. 21 /// Url of the source (typically a file) containing this span.
22 String get sourceUrl => start.sourceUrl; 22 String get sourceUrl => start.sourceUrl;
23 23
24 /// The length of this span, in characters. 24 /// The length of this span, in characters.
25 int get length => end.offset - start.offset; 25 int get length => end.offset - start.offset;
26 26
27 /// The source text for this span, if available. 27 /// The source text for this span, if available.
28 String get text; 28 String get text;
29 29
30 /// Whether [text] corresponds to an identifier symbol. 30 /// Whether [text] corresponds to an identifier symbol.
31 final bool isIdentifier; 31 final bool isIdentifier;
32 32
33 Span(this.start, this.end, bool isIdentifier) 33 Span(this.start, this.end, bool isIdentifier)
34 : isIdentifier = isIdentifier != null ? isIdentifier : false { 34 : isIdentifier = isIdentifier != null ? isIdentifier : false {
35 _checkRange(); 35 _checkRange();
36 } 36 }
37 37
38 /// Creates a new source span that is the union of two existing spans [start] 38 /// Creates a new span that is the union of two existing spans [start] and
39 /// and [end]. Note that the resulting span might contain some positions that 39 /// [end]. Note that the resulting span might contain some positions that were
40 /// were not in either of the original spans if [start] and [end] are 40 /// not in either of the original spans if [start] and [end] are disjoint.
41 /// disjoint.
42 Span.union(Span start, Span end) 41 Span.union(Span start, Span end)
43 : start = start.start, end = end.end, isIdentifier = false { 42 : start = start.start, end = end.end, isIdentifier = false {
44 _checkRange(); 43 _checkRange();
45 } 44 }
46 45
47 void _checkRange() { 46 void _checkRange() {
48 if (start.offset < 0) throw new ArgumentError('start $start must be >= 0'); 47 if (start.offset < 0) throw new ArgumentError('start $start must be >= 0');
49 if (end.offset < start.offset) { 48 if (end.offset < start.offset) {
50 throw new ArgumentError('end $end must be >= start $start'); 49 throw new ArgumentError('end $end must be >= start $start');
51 } 50 }
52 } 51 }
53 52
54 /// Compares two source spans. If the spans are not in the same file, this 53 /// Compares two spans. If the spans are not in the same source, this method
55 /// method generates an error. 54 /// generates an error.
56 int compareTo(Span other) { 55 int compareTo(Span other) {
57 int d = start.compareTo(other.start); 56 int d = start.compareTo(other.start);
58 return d == 0 ? end.compareTo(other.end) : d; 57 return d == 0 ? end.compareTo(other.end) : d;
59 } 58 }
60 59
61 /// Gets the location in standard printed form `filename:line:column`, where 60 /// Gets the location in standard printed form `filename:line:column`, where
62 /// line and column are adjusted by 1 to match the convention in editors. 61 /// line and column are adjusted by 1 to match the convention in editors.
63 String get formatLocation => start.formatString; 62 String get formatLocation => start.formatString;
64 63
65 String getLocationMessage(String message, 64 String getLocationMessage(String message,
66 {bool useColors: false, String color}) { 65 {bool useColors: false, String color}) {
67 return '$formatLocation: $message'; 66 return '$formatLocation: $message';
68 } 67 }
69 68
70 bool operator ==(Span other) => 69 bool operator ==(Span other) =>
71 sourceUrl == other.sourceUrl && start == other.start && end == other.end; 70 sourceUrl == other.sourceUrl && start == other.start && end == other.end;
72 71
73 String toString() => '<$runtimeType: $start $end $formatLocation $text>'; 72 String toString() => '<$runtimeType: $start $end $formatLocation $text>';
74 } 73 }
75 74
76 /// A location in the source text 75 /// A location in the source text
77 abstract class Location implements Comparable { 76 abstract class Location implements Comparable {
78 /// Url of the file containing this span. 77 /// Url of the source containing this span.
79 String get sourceUrl; 78 String get sourceUrl;
80 79
81 /// The offset of this location, 0-based. 80 /// The offset of this location, 0-based.
82 final int offset; 81 final int offset;
83 82
84 /// The 0-based line in the file where of this location. 83 /// The 0-based line in the source of this location.
85 int get line; 84 int get line;
86 85
87 /// The 0-based column in the file of this location. 86 /// The 0-based column in the source of this location.
88 int get column; 87 int get column;
89 88
90 Location(this.offset); 89 Location(this.offset);
91 90
92 /// Compares two source locations. If the locations are not in the same file, 91 /// Compares two locations. If the locations are not in the same source, this
93 /// this method generates an error. 92 /// method generates an error.
94 int compareTo(Location other) { 93 int compareTo(Location other) {
95 if (sourceUrl != other.sourceUrl) { 94 if (sourceUrl != other.sourceUrl) {
96 throw new ArgumentError('can only compare locations of the same file'); 95 throw new ArgumentError('can only compare locations of the same source');
97 } 96 }
98 return offset - other.offset; 97 return offset - other.offset;
99 } 98 }
100 99
101 String toString() => '(Location $offset)'; 100 String toString() => '(Location $offset)';
102 String get formatString => '$sourceUrl:${line + 1}:${column + 1}'; 101 String get formatString => '$sourceUrl:${line + 1}:${column + 1}';
103 } 102 }
104 103
105 /// Implementation of [Location] with fixed values given at allocation time. 104 /// Implementation of [Location] with fixed values given at allocation time.
106 class FixedLocation extends Location { 105 class FixedLocation extends Location {
107 final String sourceUrl; 106 final String sourceUrl;
108 final int line; 107 final int line;
109 final int column; 108 final int column;
110 109
111 FixedLocation(int offset, this.sourceUrl, this.line, this.column) 110 FixedLocation(int offset, this.sourceUrl, this.line, this.column)
112 : super(offset); 111 : super(offset);
113 } 112 }
114 113
115 /// Implementation of [Span] where all the values are given at allocation time. 114 /// Implementation of [Span] where all the values are given at allocation time.
116 class FixedSpan extends Span { 115 class FixedSpan extends Span {
117 /// The source text for this span, if available. 116 /// The source text for this span, if available.
118 final String text; 117 final String text;
119 118
120 /// Creates a span which starts and end in the same line. 119 /// Creates a span which starts and end in the same line.
121 FixedSpan(String sourceUrl, int start, int line, int column, 120 FixedSpan(String sourceUrl, int start, int line, int column,
122 {String text: '', bool isIdentifier: false}) 121 {String text: '', bool isIdentifier: false})
123 : this.text = text, 122 : text = text, super(new FixedLocation(start, sourceUrl, line, column),
124 super(new FixedLocation(start, sourceUrl, line, column),
125 new FixedLocation(start + text.length, sourceUrl, line, 123 new FixedLocation(start + text.length, sourceUrl, line,
126 column + text.length), 124 column + text.length),
127 isIdentifier); 125 isIdentifier);
128 } 126 }
129 127
130 /// Implementation of [Location] with values computed from an underling [File]. 128 /// [Location] with values computed from an underling [SourceFile].
131 class FileLocation extends Location { 129 class FileLocation extends Location {
132 /// The file containing this location. 130 /// The source file containing this location.
133 final File file; 131 final SourceFile file;
134 132
135 String get sourceUrl => file.url; 133 String get sourceUrl => file.url;
136 int get line => file.getLine(offset); 134 int get line => file.getLine(offset);
137 int get column => file.getColumn(line, offset); 135 int get column => file.getColumn(line, offset);
138 136
139 FileLocation(this.file, int offset): super(offset); 137 FileLocation(this.file, int offset): super(offset);
140 } 138 }
141 139
142 /// Implementation of [Span] where values are computed from an underling [File]. 140 /// [Span] where values are computed from an underling [SourceFile].
143 class FileSpan extends Span { 141 class FileSpan extends Span {
144 /// The file containing this span. 142 /// The source file containing this span.
145 final File file; 143 final SourceFile file;
146 144
147 /// The source text for this span, if available. 145 /// The source text for this span, if available.
148 String get text => file.getText(start.offset, end.offset); 146 String get text => file.getText(start.offset, end.offset);
149 147
150 factory FileSpan(File file, int start, 148 factory FileSpan(SourceFile file, int start,
151 [int end, bool isIdentifier = false]) { 149 [int end, bool isIdentifier = false]) {
152 var startLoc = new FileLocation(file, start); 150 var startLoc = new FileLocation(file, start);
153 var endLoc = end == null ? startLoc : new FileLocation(file, end); 151 var endLoc = end == null ? startLoc : new FileLocation(file, end);
154 return new FileSpan.locations(startLoc, endLoc, isIdentifier); 152 return new FileSpan.locations(startLoc, endLoc, isIdentifier);
155 } 153 }
156 154
157 FileSpan.locations(FileLocation start, FileLocation end, bool isIdentifier) 155 FileSpan.locations(FileLocation start, FileLocation end,
158 : this.file = start.file, super(start, end, isIdentifier); 156 bool isIdentifier)
157 : file = start.file, super(start, end, isIdentifier);
159 158
160 /// Creates a new source span that is the union of two existing spans [start] 159 /// Creates a new span that is the union of two existing spans [start] and
161 /// and [end]. Note that the resulting span might contain some positions that 160 /// [end]. Note that the resulting span might contain some positions that were
162 /// were not in either of the original spans if [start] and [end] are 161 /// not in either of the original spans if [start] and [end] are disjoint.
163 /// disjoint.
164 FileSpan.union(FileSpan start, FileSpan end) 162 FileSpan.union(FileSpan start, FileSpan end)
165 : file = start.file, super.union(start, end) { 163 : file = start.file, super.union(start, end) {
166 if (start.file != end.file) { 164 if (start.file != end.file) {
167 throw new ArgumentError('start and end must be from the same file'); 165 throw new ArgumentError('start and end must be from the same file');
168 } 166 }
169 } 167 }
170 168
171 String getLocationMessage(String message, 169 String getLocationMessage(String message,
172 {bool useColors: false, String color}) { 170 {bool useColors: false, String color}) {
173 return file.getLocationMessage(message, start.offset, end.offset, 171 return file.getLocationMessage(message, start.offset, end.offset,
174 useColors: useColors, color: color); 172 useColors: useColors, color: color);
175 } 173 }
176 } 174 }
177 175
178 // Constants to determine end-of-lines. 176 // Constants to determine end-of-lines.
179 const int _LF = 10; 177 const int _LF = 10;
180 const int _CR = 13; 178 const int _CR = 13;
181 179
182 // Color constants used for generating messages. 180 // Color constants used for generating messages.
183 const String _RED_COLOR = '\u001b[31m'; 181 const String _RED_COLOR = '\u001b[31m';
184 const String _NO_COLOR = '\u001b[0m'; 182 const String _NO_COLOR = '\u001b[0m';
185 183
186 /// Stores information about a source file, to permit computation of the line 184 /// Stores information about a source file, to permit computation of the line
187 /// and column. Also contains a nice default error message highlighting the code 185 /// and column. Also contains a nice default error message highlighting the code
188 /// location. 186 /// location.
189 class File { 187 class SourceFile {
190 /// Url where the file is located. 188 /// Url where the source file is located.
191 final String url; 189 final String url;
192 final List<int> _lineStarts; 190 final List<int> _lineStarts;
193 final List<int> _decodedChars; 191 final List<int> _decodedChars;
194 192
195 File(this.url, this._lineStarts, this._decodedChars); 193 SourceFile(this.url, this._lineStarts, this._decodedChars);
196 194
197 File.text(this.url, String text) 195 SourceFile.text(this.url, String text)
198 : _lineStarts = <int>[0], 196 : _lineStarts = <int>[0],
199 _decodedChars = stringToCodepoints(text) { 197 _decodedChars = stringToCodepoints(text) {
200 for (int i = 0; i < _decodedChars.length; i++) { 198 for (int i = 0; i < _decodedChars.length; i++) {
201 var c = _decodedChars[i]; 199 var c = _decodedChars[i];
202 if (c == _CR) { 200 if (c == _CR) {
203 // Return not followed by newline is treated as a newline 201 // Return not followed by newline is treated as a newline
204 int j = i + 1; 202 int j = i + 1;
205 if (j >= _decodedChars.length || _decodedChars[j] != _LF) { 203 if (j >= _decodedChars.length || _decodedChars[j] != _LF) {
206 c = _LF; 204 c = _LF;
207 } 205 }
208 } 206 }
209 if (c == _LF) _lineStarts.add(i + 1); 207 if (c == _LF) _lineStarts.add(i + 1);
210 } 208 }
211 } 209 }
212 210
213 /// Returns a span in this file with the given offsets. 211 /// Returns a span in this [SourceFile] with the given offsets.
214 Span span(int start, [int end, bool isIdentifier = false]) => 212 Span span(int start, [int end, bool isIdentifier = false]) =>
215 new FileSpan(this, start, end, isIdentifier); 213 new FileSpan(this, start, end, isIdentifier);
216 214
217 /// Returns a location in this file with the given offset. 215 /// Returns a location in this [SourceFile] with the given offset.
218 Location location(int offset) => new FileLocation(this, offset); 216 Location location(int offset) => new FileLocation(this, offset);
219 217
220 /// Gets the 0-based line in the file for this offset. 218 /// Gets the 0-based line corresponding to an offset.
221 int getLine(int offset) { 219 int getLine(int offset) {
222 return binarySearch(_lineStarts, (o) => o > offset) - 1; 220 return binarySearch(_lineStarts, (o) => o > offset) - 1;
223 } 221 }
224 222
225 /// Gets the 0-based column in the file for this offset. 223 /// Gets the 0-based column corresponding to an offset.
226 int getColumn(int line, int offset) { 224 int getColumn(int line, int offset) {
227 return offset - _lineStarts[line]; 225 return offset - _lineStarts[line];
228 } 226 }
229 227
230 /// Get the offset for a given line and column 228 /// Get the offset for a given line and column
231 int getOffset(int line, int column) { 229 int getOffset(int line, int column) {
232 return _lineStarts[min(line, _lineStarts.length - 1)] + column; 230 return _lineStarts[min(line, _lineStarts.length - 1)] + column;
233 } 231 }
234 232
235 /// Gets the text at the given offsets. 233 /// Gets the text at the given offsets.
236 String getText(int start, [int end]) { 234 String getText(int start, [int end]) {
237 return codepointsToString(_decodedChars.sublist(start, end)); 235 return codepointsToString(_decodedChars.sublist(start, end));
238 } 236 }
239 237
240 /// Create a pretty string representation from a span in the file. 238 /// Create a pretty string representation from a span.
241 String getLocationMessage(String message, int start, int end, 239 String getLocationMessage(String message, int start, int end,
242 {bool useColors: false, String color}) { 240 {bool useColors: false, String color}) {
243 // TODO(jmesserly): it would be more useful to pass in an object that 241 // TODO(jmesserly): it would be more useful to pass in an object that
244 // controls how the errors are printed. This method is a bit too smart. 242 // controls how the errors are printed. This method is a bit too smart.
245 var line = getLine(start); 243 var line = getLine(start);
246 var column = getColumn(line, start); 244 var column = getColumn(line, start);
247 245
248 var source = url == null ? '' : url; 246 var src = url == null ? '' : url;
249 var msg = '$source:${line + 1}:${column + 1}: $message'; 247 var msg = '$src:${line + 1}:${column + 1}: $message';
250 248
251 if (_decodedChars == null) { 249 if (_decodedChars == null) {
252 // We don't have any text to include, so exit. 250 // We don't have any text to include, so exit.
253 return msg; 251 return msg;
254 } 252 }
255 253
256 var buf = new StringBuffer(msg); 254 var buf = new StringBuffer(msg);
257 buf.write('\n'); 255 buf.write('\n');
258 var textLine; 256 var textLine;
259 257
260 // +1 for 0-indexing, +1 again to avoid the last line of the file 258 // +1 for 0-indexing, +1 again to avoid the last line
261 if ((line + 2) < _lineStarts.length) { 259 if ((line + 2) < _lineStarts.length) {
262 textLine = getText(_lineStarts[line], _lineStarts[line + 1]); 260 textLine = getText(_lineStarts[line], _lineStarts[line + 1]);
263 } else { 261 } else {
264 textLine = getText(_lineStarts[line]); 262 textLine = getText(_lineStarts[line]);
265 textLine = '$textLine\n'; 263 textLine = '$textLine\n';
266 } 264 }
267 265
268 int toColumn = min(column + end - start, textLine.length); 266 int toColumn = min(column + end - start, textLine.length);
269 if (useColors) { 267 if (useColors) {
270 if (color == null) { 268 if (color == null) {
(...skipping 15 matching lines...) Expand all
286 284
287 if (useColors) buf.write(color); 285 if (useColors) buf.write(color);
288 for (; i < toColumn; i++) { 286 for (; i < toColumn; i++) {
289 buf.write('^'); 287 buf.write('^');
290 } 288 }
291 if (useColors) buf.write(_NO_COLOR); 289 if (useColors) buf.write(_NO_COLOR);
292 return buf.toString(); 290 return buf.toString();
293 } 291 }
294 } 292 }
295 293
296 /// A convenience type to treat a code segment as if it were a separate file. An 294 /// A convenience type to treat a code segment as if it were a separate
297 /// [FileSegment] shifts all locations by an offset, which allows you to set 295 /// [SourceFile]. A [SourceFileSegment] shifts all locations by an offset, which
298 /// source-map locations based on the locations relative to the start of the 296 /// allows you to set source-map locations based on the locations relative to
299 /// segment, but that get translated to absolute locations in the original file. 297 /// the start of the segment, but that get translated to absolute locations in
300 class FileSegment extends File { 298 /// the original source file.
299 class SourceFileSegment extends SourceFile {
301 final int _baseOffset; 300 final int _baseOffset;
302 final int _baseLine; 301 final int _baseLine;
303 final int _baseColumn; 302 final int _baseColumn;
304 303
305 FileSegment(String url, String segment, Location startOffset) 304 SourceFileSegment(String url, String textSegment, Location startOffset)
306 : _baseOffset = startOffset.offset, 305 : _baseOffset = startOffset.offset,
307 _baseLine = startOffset.line, 306 _baseLine = startOffset.line,
308 _baseColumn = startOffset.column, 307 _baseColumn = startOffset.column,
309 super.text(url, segment); 308 super.text(url, textSegment);
310 309
311 Span span(int start, [int end, bool isIdentifier = false]) => 310 Span span(int start, [int end, bool isIdentifier = false]) =>
312 super.span(start + _baseOffset, 311 super.span(start + _baseOffset,
313 end == null ? null : end + _baseOffset, isIdentifier); 312 end == null ? null : end + _baseOffset, isIdentifier);
314 313
315 Location location(int offset) => super.location(offset + _baseOffset); 314 Location location(int offset) => super.location(offset + _baseOffset);
316 315
317 int getLine(int offset) => 316 int getLine(int offset) =>
318 super.getLine(offset - _baseOffset) + _baseLine; 317 super.getLine(offset - _baseOffset) + _baseLine;
319 318
320 int getColumn(int line, int offset) { 319 int getColumn(int line, int offset) {
321 var col = super.getColumn(line - _baseLine, offset - _baseOffset); 320 var col = super.getColumn(line - _baseLine, offset - _baseOffset);
322 return line == _baseLine ? col + _baseColumn : col; 321 return line == _baseLine ? col + _baseColumn : col;
323 } 322 }
324 323
325 int getOffset(int line, int column) => 324 int getOffset(int line, int column) =>
326 super.getOffset(line - _baseLine, 325 super.getOffset(line - _baseLine,
327 line == _baseLine ? column - _baseColumn : column) + _baseOffset; 326 line == _baseLine ? column - _baseColumn : column) + _baseOffset;
328 327
329 String getText(int start, [int end]) => 328 String getText(int start, [int end]) =>
330 super.getText(start - _baseOffset, end - _baseOffset); 329 super.getText(start - _baseOffset, end - _baseOffset);
331 } 330 }
OLDNEW
« lib/source_maps.dart ('K') | « lib/source_maps.dart ('k') | pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698