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

Side by Side Diff: pkg/source_maps/lib/parser.dart

Issue 372153002: Moving logic for writing source maps from SourceMapBuilder into the Mapping class. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Mostly style updates addressing round 1 comments. Created 6 years, 5 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 | Annotate | Revision Log
« no previous file with comments | « pkg/source_maps/lib/builder.dart ('k') | pkg/source_maps/test/parser_test.dart » ('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) 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 /// Contains the top-level function to parse source maps version 3. 5 /// Contains the top-level function to parse source maps version 3.
6 library source_maps.parser; 6 library source_maps.parser;
7 7
8 import 'dart:collection';
8 import 'dart:convert'; 9 import 'dart:convert';
9 10
11 import 'builder.dart' as builder;
10 import 'span.dart'; 12 import 'span.dart';
11 import 'src/utils.dart'; 13 import 'src/utils.dart';
12 import 'src/vlq.dart'; 14 import 'src/vlq.dart';
13 15
14 /// Parses a source map directly from a json string. 16 /// Parses a source map directly from a json string.
15 // TODO(sigmund): evaluate whether other maps should have the json parsed, or 17 // TODO(sigmund): evaluate whether other maps should have the json parsed, or
16 // the string represenation. 18 // the string represenation.
17 Mapping parse(String jsonMap, {Map<String, Map> otherMaps}) => 19 Mapping parse(String jsonMap, {Map<String, Map> otherMaps}) =>
18 parseJson(JSON.decode(jsonMap), otherMaps: otherMaps); 20 parseJson(JSON.decode(jsonMap), otherMaps: otherMaps);
19 21
(...skipping 14 matching lines...) Expand all
34 map.containsKey('names')) { 36 map.containsKey('names')) {
35 throw new FormatException('map containing "sections" ' 37 throw new FormatException('map containing "sections" '
36 'cannot contain "mappings", "sources", or "names".'); 38 'cannot contain "mappings", "sources", or "names".');
37 } 39 }
38 return new MultiSectionMapping.fromJson(map['sections'], otherMaps); 40 return new MultiSectionMapping.fromJson(map['sections'], otherMaps);
39 } 41 }
40 return new SingleMapping.fromJson(map); 42 return new SingleMapping.fromJson(map);
41 } 43 }
42 44
43 45
44 /// A mapping parsed our of a source map. 46 /// A mapping parsed out of a source map.
45 abstract class Mapping { 47 abstract class Mapping {
46 Span spanFor(int line, int column, {Map<String, SourceFile> files}); 48 Span spanFor(int line, int column, {Map<String, SourceFile> files});
47 49
48 Span spanForLocation(Location loc, {Map<String, SourceFile> files}) { 50 Span spanForLocation(Location loc, {Map<String, SourceFile> files}) {
49 return spanFor(loc.line, loc.column, files: files); 51 return spanFor(loc.line, loc.column, files: files);
50 } 52 }
51 } 53 }
52 54
53 /// A meta-level map containing sections. 55 /// A meta-level map containing sections.
54 class MultiSectionMapping extends Mapping { 56 class MultiSectionMapping extends Mapping {
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 ..write(':') 126 ..write(':')
125 ..write(_maps[i]) 127 ..write(_maps[i])
126 ..write(')'); 128 ..write(')');
127 } 129 }
128 buff.write(']'); 130 buff.write(']');
129 return buff.toString(); 131 return buff.toString();
130 } 132 }
131 } 133 }
132 134
133 /// A map containing direct source mappings. 135 /// A map containing direct source mappings.
134 // TODO(sigmund): integrate mapping and sourcemap builder?
135 class SingleMapping extends Mapping { 136 class SingleMapping extends Mapping {
136 /// Url of the target file. 137 /// Url of the target file.
137 final String targetUrl; 138 final String targetUrl;
138 139
139 /// Source urls used in the mapping, indexed by id. 140 /// Source urls used in the mapping, indexed by id.
140 final List<String> urls; 141 final List<String> urls;
141 142
142 /// Source names used in the mapping, indexed by id. 143 /// Source names used in the mapping, indexed by id.
143 final List<String> names; 144 final List<String> names;
144 145
145 /// Entries indicating the beginning of each span. 146 /// Entries indicating the beginning of each span.
146 final List<TargetLineEntry> lines = <TargetLineEntry>[]; 147 final List<TargetLineEntry> lines;
148
149 SingleMapping._internal(this.targetUrl, this.urls, this.names, this.lines);
150
151 factory SingleMapping.fromEntries(
152 Iterable<builder.Entry> entries, [String fileUrl]) {
153 // The entries needs to be sorted by the target offsets.
154 var sourceEntries = new List.from(entries)..sort();
155 var lines = <TargetLineEntry>[];
156
157 // Indices associated with file urls that will be part of the source map. We
158 // use a linked hash-map so that `_urls.keys[_urls[u]] == u`
159 var urls = new LinkedHashMap<String, int>();
160
161 // Indices associated with identifiers that will be part of the source map.
162 // We use a linked hash-map so that `_names.keys[_names[n]] == n`
163 var names = new LinkedHashMap<String, int>();
164
165 var lineNum;
166 var targetEntries;
167 for (var sourceEntry in sourceEntries) {
168 if (lineNum == null || sourceEntry.target.line > lineNum) {
169 lineNum = sourceEntry.target.line;
170 targetEntries = <TargetEntry>[];
171 lines.add(new TargetLineEntry(lineNum, targetEntries));
172 }
173
174 if (sourceEntry.source == null) {
175 targetEntries.add(new TargetEntry(sourceEntry.target.column));
176 } else {
177 var urlId = urls.putIfAbsent(
178 sourceEntry.source.sourceUrl, () => urls.length);
179 var srcNameId = sourceEntry.identifierName == null ? null :
180 names.putIfAbsent(sourceEntry.identifierName, () => names.length);
181 targetEntries.add(new TargetEntry(
182 sourceEntry.target.column,
183 urlId,
184 sourceEntry.source.line,
185 sourceEntry.source.column,
186 srcNameId));
187 }
188 }
189 return new SingleMapping._internal(
190 fileUrl, urls.keys.toList(), names.keys.toList(), lines);
191 }
147 192
148 SingleMapping.fromJson(Map map) 193 SingleMapping.fromJson(Map map)
149 : targetUrl = map['file'], 194 : targetUrl = map['file'],
150 // TODO(sigmund): add support for 'sourceRoot' 195 // TODO(sigmund): add support for 'sourceRoot'
151 urls = map['sources'], 196 urls = map['sources'],
152 names = map['names'] { 197 names = map['names'],
198 lines = <TargetLineEntry>[] {
153 int line = 0; 199 int line = 0;
154 int column = 0; 200 int column = 0;
155 int srcUrlId = 0; 201 int srcUrlId = 0;
156 int srcLine = 0; 202 int srcLine = 0;
157 int srcColumn = 0; 203 int srcColumn = 0;
158 int srcNameId = 0; 204 int srcNameId = 0;
159 var tokenizer = new _MappingTokenizer(map['mappings']); 205 var tokenizer = new _MappingTokenizer(map['mappings']);
160 var entries = <TargetEntry>[]; 206 var entries = <TargetEntry>[];
161 207
162 while (tokenizer.hasTokens) { 208 while (tokenizer.hasTokens) {
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
208 srcNameId)); 254 srcNameId));
209 } 255 }
210 } 256 }
211 if (tokenizer.nextKind.isNewSegment) tokenizer._consumeNewSegment(); 257 if (tokenizer.nextKind.isNewSegment) tokenizer._consumeNewSegment();
212 } 258 }
213 if (!entries.isEmpty) { 259 if (!entries.isEmpty) {
214 lines.add(new TargetLineEntry(line, entries)); 260 lines.add(new TargetLineEntry(line, entries));
215 } 261 }
216 } 262 }
217 263
264 /// Encodes the Mapping mappings as a json map.
265 Map toJson() {
266 var buff = new StringBuffer();
267 var line = 0;
268 var column = 0;
269 var srcLine = 0;
270 var srcColumn = 0;
271 var srcUrlId = 0;
272 var srcNameId = 0;
273 var first = true;
274
275 for (var entry in lines) {
276 int nextLine = entry.line;
277 if (nextLine > line) {
278 for (int i = line; i < nextLine; ++i) {
279 buff.write(';');
280 }
281 line = nextLine;
282 column = 0;
283 first = true;
284 }
285
286 for (var segment in entry.entries) {
287 if (!first) buff.write(',');
288 first = false;
289 column = _append(buff, column, segment.column);
290
291 // Encoding can be just the column offset if there is no source
292 // information.
293 var newUrlId = segment.sourceUrlId;
294 if (newUrlId == null) continue;
295 srcUrlId = _append(buff, srcUrlId, newUrlId);
296 srcLine = _append(buff, srcLine, segment.sourceLine);
297 srcColumn = _append(buff, srcColumn, segment.sourceColumn);
298
299 if (segment.sourceNameId == null) continue;
300 srcNameId = _append(buff, srcNameId, segment.sourceNameId);
301 }
302 }
303
304 var result = {
305 'version': 3,
306 'sourceRoot': '',
307 'sources': urls,
308 'names' : names,
309 'mappings' : buff.toString()
310 };
311 if (targetUrl != null) {
312 result['file'] = targetUrl;
313 }
314 return result;
315 }
316
317 /// Appends to [buff] a VLQ encoding of [newValue] using the difference
318 /// between [oldValue] and [newValue]
319 static int _append(StringBuffer buff, int oldValue, int newValue) {
320 buff.writeAll(encodeVlq(newValue - oldValue));
321 return newValue;
322 }
323
218 _segmentError(int seen, int line) => new StateError( 324 _segmentError(int seen, int line) => new StateError(
219 'Invalid entry in sourcemap, expected 1, 4, or 5' 325 'Invalid entry in sourcemap, expected 1, 4, or 5'
220 ' values, but got $seen.\ntargeturl: $targetUrl, line: $line'); 326 ' values, but got $seen.\ntargeturl: $targetUrl, line: $line');
221 327
222 /// Returns [TargetLineEntry] which includes the location in the target [line] 328 /// Returns [TargetLineEntry] which includes the location in the target [line]
223 /// number. In particular, the resulting entry is the last entry whose line 329 /// number. In particular, the resulting entry is the last entry whose line
224 /// number is lower or equal to [line]. 330 /// number is lower or equal to [line].
225 TargetLineEntry _findLine(int line) { 331 TargetLineEntry _findLine(int line) {
226 int index = binarySearch(lines, (e) => e.line > line); 332 int index = binarySearch(lines, (e) => e.line > line);
227 return (index <= 0) ? null : lines[index - 1]; 333 return (index <= 0) ? null : lines[index - 1];
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
301 buff.write('\n'); 407 buff.write('\n');
302 } 408 }
303 } 409 }
304 return buff.toString(); 410 return buff.toString();
305 } 411 }
306 } 412 }
307 413
308 /// A line entry read from a source map. 414 /// A line entry read from a source map.
309 class TargetLineEntry { 415 class TargetLineEntry {
310 final int line; 416 final int line;
311 List<TargetEntry> entries = <TargetEntry>[]; 417 List<TargetEntry> entries;
312 TargetLineEntry(this.line, this.entries); 418 TargetLineEntry(this.line, this.entries);
313 419
314 String toString() => '$runtimeType: $line $entries'; 420 String toString() => '$runtimeType: $line $entries';
315 } 421 }
316 422
317 /// A target segment entry read from a source map 423 /// A target segment entry read from a source map
318 class TargetEntry { 424 class TargetEntry {
319 final int column; 425 final int column;
320 final int sourceUrlId; 426 final int sourceUrlId;
321 final int sourceLine; 427 final int sourceLine;
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
381 static const _TokenKind EOF = const _TokenKind(isEof: true); 487 static const _TokenKind EOF = const _TokenKind(isEof: true);
382 static const _TokenKind VALUE = const _TokenKind(); 488 static const _TokenKind VALUE = const _TokenKind();
383 final bool isNewLine; 489 final bool isNewLine;
384 final bool isNewSegment; 490 final bool isNewSegment;
385 final bool isEof; 491 final bool isEof;
386 bool get isValue => !isNewLine && !isNewSegment && !isEof; 492 bool get isValue => !isNewLine && !isNewSegment && !isEof;
387 493
388 const _TokenKind( 494 const _TokenKind(
389 {this.isNewLine: false, this.isNewSegment: false, this.isEof: false}); 495 {this.isNewLine: false, this.isNewSegment: false, this.isEof: false});
390 } 496 }
OLDNEW
« no previous file with comments | « pkg/source_maps/lib/builder.dart ('k') | pkg/source_maps/test/parser_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698