OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 sourcemap.helper; | 5 library sourcemap.helper; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:io'; | 8 import 'dart:io'; |
9 import 'package:compiler/compiler_new.dart'; | 9 import 'package:compiler/compiler_new.dart'; |
10 import 'package:compiler/src/apiimpl.dart' as api; | 10 import 'package:compiler/src/apiimpl.dart' as api; |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
70 @override | 70 @override |
71 EventSink<String> createEventSink(String name, String extension) { | 71 EventSink<String> createEventSink(String name, String extension) { |
72 return createSourceFileSink(name, extension); | 72 return createSourceFileSink(name, extension); |
73 } | 73 } |
74 } | 74 } |
75 | 75 |
76 class CloningOutputProvider extends OutputProvider { | 76 class CloningOutputProvider extends OutputProvider { |
77 RandomAccessFileOutputProvider outputProvider; | 77 RandomAccessFileOutputProvider outputProvider; |
78 | 78 |
79 CloningOutputProvider(Uri jsUri, Uri jsMapUri) | 79 CloningOutputProvider(Uri jsUri, Uri jsMapUri) |
80 : outputProvider = new RandomAccessFileOutputProvider(jsUri, jsMapUri); | 80 : outputProvider = new RandomAccessFileOutputProvider(jsUri, jsMapUri); |
81 | 81 |
82 @override | 82 @override |
83 EventSink<String> createEventSink(String name, String extension) { | 83 EventSink<String> createEventSink(String name, String extension) { |
84 EventSink<String> output = outputProvider(name, extension); | 84 EventSink<String> output = outputProvider(name, extension); |
85 return new CloningEventSink( | 85 return new CloningEventSink( |
86 [output, createSourceFileSink(name, extension)]); | 86 [output, createSourceFileSink(name, extension)]); |
87 } | 87 } |
88 } | 88 } |
89 | 89 |
90 abstract class SourceFileManager { | 90 abstract class SourceFileManager { |
(...skipping 16 matching lines...) Expand all Loading... |
107 } | 107 } |
108 } | 108 } |
109 | 109 |
110 class RecordingPrintingContext extends LenientPrintingContext { | 110 class RecordingPrintingContext extends LenientPrintingContext { |
111 CodePositionListener listener; | 111 CodePositionListener listener; |
112 Map<js.Node, CodePosition> codePositions = <js.Node, CodePosition>{}; | 112 Map<js.Node, CodePosition> codePositions = <js.Node, CodePosition>{}; |
113 | 113 |
114 RecordingPrintingContext(this.listener); | 114 RecordingPrintingContext(this.listener); |
115 | 115 |
116 @override | 116 @override |
117 void exitNode(js.Node node, | 117 void exitNode( |
118 int startPosition, | 118 js.Node node, int startPosition, int endPosition, int closingPosition) { |
119 int endPosition, | |
120 int closingPosition) { | |
121 codePositions[node] = | 119 codePositions[node] = |
122 new CodePosition(startPosition, endPosition, closingPosition); | 120 new CodePosition(startPosition, endPosition, closingPosition); |
123 listener.onPositions( | 121 listener.onPositions(node, startPosition, endPosition, closingPosition); |
124 node, startPosition, endPosition, closingPosition); | |
125 } | 122 } |
126 } | 123 } |
127 | 124 |
128 /// A [SourceMapper] that records the source locations on each node. | 125 /// A [SourceMapper] that records the source locations on each node. |
129 class RecordingSourceMapper implements SourceMapper { | 126 class RecordingSourceMapper implements SourceMapper { |
130 final SourceMapper sourceMapper; | 127 final SourceMapper sourceMapper; |
131 final _LocationRecorder nodeToSourceLocationsMap; | 128 final _LocationRecorder nodeToSourceLocationsMap; |
132 | 129 |
133 RecordingSourceMapper(this.sourceMapper, this.nodeToSourceLocationsMap); | 130 RecordingSourceMapper(this.sourceMapper, this.nodeToSourceLocationsMap); |
134 | 131 |
135 @override | 132 @override |
136 void register(js.Node node, int codeOffset, SourceLocation sourceLocation) { | 133 void register(js.Node node, int codeOffset, SourceLocation sourceLocation) { |
137 nodeToSourceLocationsMap.register(node, codeOffset, sourceLocation); | 134 nodeToSourceLocationsMap.register(node, codeOffset, sourceLocation); |
138 sourceMapper.register(node, codeOffset, sourceLocation); | 135 sourceMapper.register(node, codeOffset, sourceLocation); |
139 } | 136 } |
140 } | 137 } |
141 | 138 |
142 /// A wrapper of [SourceInformationProcessor] that records source locations and | 139 /// A wrapper of [SourceInformationProcessor] that records source locations and |
143 /// code positions. | 140 /// code positions. |
144 class RecordingSourceInformationProcessor | 141 class RecordingSourceInformationProcessor |
145 implements SourceInformationProcessor { | 142 implements SourceInformationProcessor { |
146 final RecordingSourceInformationStrategy wrapper; | 143 final RecordingSourceInformationStrategy wrapper; |
147 final SourceInformationProcessor processor; | 144 final SourceInformationProcessor processor; |
148 final CodePositionRecorder codePositions; | 145 final CodePositionRecorder codePositions; |
149 final LocationMap nodeToSourceLocationsMap; | 146 final LocationMap nodeToSourceLocationsMap; |
150 | 147 |
151 RecordingSourceInformationProcessor( | 148 RecordingSourceInformationProcessor(this.wrapper, this.processor, |
152 this.wrapper, | 149 this.codePositions, this.nodeToSourceLocationsMap); |
153 this.processor, | |
154 this.codePositions, | |
155 this.nodeToSourceLocationsMap); | |
156 | 150 |
157 @override | 151 @override |
158 void onPositions(js.Node node, | 152 void onPositions( |
159 int startPosition, | 153 js.Node node, int startPosition, int endPosition, int closingPosition) { |
160 int endPosition, | |
161 int closingPosition) { | |
162 codePositions.registerPositions( | 154 codePositions.registerPositions( |
163 node, startPosition, endPosition, closingPosition); | 155 node, startPosition, endPosition, closingPosition); |
164 processor.onPositions(node, startPosition, endPosition, closingPosition); | 156 processor.onPositions(node, startPosition, endPosition, closingPosition); |
165 } | 157 } |
166 | 158 |
167 @override | 159 @override |
168 void process(js.Node node, BufferedCodeOutput code) { | 160 void process(js.Node node, BufferedCodeOutput code) { |
169 processor.process(node, code); | 161 processor.process(node, code); |
170 wrapper.registerProcess( | 162 wrapper.registerProcess( |
171 node, code, codePositions, nodeToSourceLocationsMap); | 163 node, code, codePositions, nodeToSourceLocationsMap); |
172 } | 164 } |
173 } | 165 } |
174 | 166 |
175 /// Information recording for a use of [SourceInformationProcessor]. | 167 /// Information recording for a use of [SourceInformationProcessor]. |
176 class RecordedSourceInformationProcess { | 168 class RecordedSourceInformationProcess { |
177 final js.Node root; | 169 final js.Node root; |
178 final String code; | 170 final String code; |
179 final CodePositionRecorder codePositions; | 171 final CodePositionRecorder codePositions; |
180 final LocationMap nodeToSourceLocationsMap; | 172 final LocationMap nodeToSourceLocationsMap; |
181 | 173 |
182 RecordedSourceInformationProcess( | 174 RecordedSourceInformationProcess( |
183 this.root, | 175 this.root, this.code, this.codePositions, this.nodeToSourceLocationsMap); |
184 this.code, | |
185 this.codePositions, | |
186 this.nodeToSourceLocationsMap); | |
187 } | 176 } |
188 | 177 |
189 | |
190 /// A wrapper of [JavaScriptSourceInformationStrategy] that records | 178 /// A wrapper of [JavaScriptSourceInformationStrategy] that records |
191 /// [RecordedSourceInformationProcess]. | 179 /// [RecordedSourceInformationProcess]. |
192 class RecordingSourceInformationStrategy | 180 class RecordingSourceInformationStrategy |
193 extends JavaScriptSourceInformationStrategy { | 181 extends JavaScriptSourceInformationStrategy { |
194 final JavaScriptSourceInformationStrategy strategy; | 182 final JavaScriptSourceInformationStrategy strategy; |
195 final Map<RecordedSourceInformationProcess, js.Node> processMap = | 183 final Map<RecordedSourceInformationProcess, js.Node> processMap = |
196 <RecordedSourceInformationProcess, js.Node>{}; | 184 <RecordedSourceInformationProcess, js.Node>{}; |
197 final Map<js.Node, RecordedSourceInformationProcess> nodeMap = | 185 final Map<js.Node, RecordedSourceInformationProcess> nodeMap = |
198 <js.Node, RecordedSourceInformationProcess>{}; | 186 <js.Node, RecordedSourceInformationProcess>{}; |
199 | 187 |
200 RecordingSourceInformationStrategy(this.strategy); | 188 RecordingSourceInformationStrategy(this.strategy); |
201 | 189 |
202 @override | 190 @override |
203 SourceInformationBuilder createBuilderForContext(ResolvedAst resolvedAst) { | 191 SourceInformationBuilder createBuilderForContext(ResolvedAst resolvedAst) { |
204 return strategy.createBuilderForContext(resolvedAst); | 192 return strategy.createBuilderForContext(resolvedAst); |
205 } | 193 } |
206 | 194 |
207 @override | 195 @override |
208 SourceInformationProcessor createProcessor(SourceMapper sourceMapper) { | 196 SourceInformationProcessor createProcessor(SourceMapper sourceMapper) { |
209 LocationMap nodeToSourceLocationsMap = | 197 LocationMap nodeToSourceLocationsMap = new _LocationRecorder(); |
210 new _LocationRecorder(); | |
211 CodePositionRecorder codePositions = new CodePositionRecorder(); | 198 CodePositionRecorder codePositions = new CodePositionRecorder(); |
212 return new RecordingSourceInformationProcessor( | 199 return new RecordingSourceInformationProcessor( |
213 this, | 200 this, |
214 strategy.createProcessor(new RecordingSourceMapper( | 201 strategy.createProcessor( |
215 sourceMapper, nodeToSourceLocationsMap)), | 202 new RecordingSourceMapper(sourceMapper, nodeToSourceLocationsMap)), |
216 codePositions, nodeToSourceLocationsMap); | 203 codePositions, |
| 204 nodeToSourceLocationsMap); |
217 } | 205 } |
218 | 206 |
219 void registerProcess(js.Node root, | 207 void registerProcess( |
220 BufferedCodeOutput code, | 208 js.Node root, |
221 CodePositionRecorder codePositions, | 209 BufferedCodeOutput code, |
222 LocationMap nodeToSourceLocationsMap) { | 210 CodePositionRecorder codePositions, |
| 211 LocationMap nodeToSourceLocationsMap) { |
223 RecordedSourceInformationProcess subProcess = | 212 RecordedSourceInformationProcess subProcess = |
224 new RecordedSourceInformationProcess( | 213 new RecordedSourceInformationProcess( |
225 root, code.getText(), codePositions, nodeToSourceLocationsMap); | 214 root, code.getText(), codePositions, nodeToSourceLocationsMap); |
226 processMap[subProcess] = root; | 215 processMap[subProcess] = root; |
227 } | 216 } |
228 | 217 |
229 RecordedSourceInformationProcess subProcessForNode(js.Node node) { | 218 RecordedSourceInformationProcess subProcessForNode(js.Node node) { |
230 return nodeMap.putIfAbsent(node, () { | 219 return nodeMap.putIfAbsent(node, () { |
231 for (RecordedSourceInformationProcess subProcess in processMap.keys) { | 220 for (RecordedSourceInformationProcess subProcess in processMap.keys) { |
232 js.Node root = processMap[subProcess]; | 221 js.Node root = processMap[subProcess]; |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 | 284 |
296 /// Creates a processor for the Dart file [filename]. | 285 /// Creates a processor for the Dart file [filename]. |
297 SourceMapProcessor(String filename, {this.outputToFile: false}) { | 286 SourceMapProcessor(String filename, {this.outputToFile: false}) { |
298 inputUri = Uri.base.resolve(nativeToUriPath(filename)); | 287 inputUri = Uri.base.resolve(nativeToUriPath(filename)); |
299 jsPath = 'out.js'; | 288 jsPath = 'out.js'; |
300 targetUri = Uri.base.resolve(jsPath); | 289 targetUri = Uri.base.resolve(jsPath); |
301 sourceMapFileUri = Uri.base.resolve('${jsPath}.map'); | 290 sourceMapFileUri = Uri.base.resolve('${jsPath}.map'); |
302 } | 291 } |
303 | 292 |
304 /// Computes the [SourceMapInfo] for the compiled elements. | 293 /// Computes the [SourceMapInfo] for the compiled elements. |
305 Future<SourceMaps> process( | 294 Future<SourceMaps> process(List<String> options, |
306 List<String> options, | 295 {bool verbose: true, bool perElement: true, bool forMain: false}) async { |
307 {bool verbose: true, | |
308 bool perElement: true, | |
309 bool forMain: false}) async { | |
310 OutputProvider outputProvider = outputToFile | 296 OutputProvider outputProvider = outputToFile |
311 ? new CloningOutputProvider(targetUri, sourceMapFileUri) | 297 ? new CloningOutputProvider(targetUri, sourceMapFileUri) |
312 : new OutputProvider(); | 298 : new OutputProvider(); |
313 if (options.contains(Flags.useNewSourceInfo)) { | 299 if (options.contains(Flags.useNewSourceInfo)) { |
314 if (verbose) print('Using the new source information system.'); | 300 if (verbose) print('Using the new source information system.'); |
315 } | 301 } |
316 if (options.contains(Flags.disableInlining)) { | 302 if (options.contains(Flags.disableInlining)) { |
317 if (verbose) print('Inlining disabled'); | 303 if (verbose) print('Inlining disabled'); |
318 } | 304 } |
319 api.CompilerImpl compiler = await compilerFor( | 305 api.CompilerImpl compiler = await compilerFor( |
320 outputProvider: outputProvider, | 306 outputProvider: outputProvider, |
321 // TODO(johnniwinther): Use [verbose] to avoid showing diagnostics. | 307 // TODO(johnniwinther): Use [verbose] to avoid showing diagnostics. |
322 options: ['--out=$targetUri', '--source-map=$sourceMapFileUri'] | 308 options: ['--out=$targetUri', '--source-map=$sourceMapFileUri'] |
323 ..addAll(options)); | 309 ..addAll(options)); |
324 | 310 |
325 JavaScriptBackend backend = compiler.backend; | 311 JavaScriptBackend backend = compiler.backend; |
326 var handler = compiler.handler; | 312 var handler = compiler.handler; |
327 SourceFileProvider sourceFileProvider = handler.provider; | 313 SourceFileProvider sourceFileProvider = handler.provider; |
328 sourceFileManager = new ProviderSourceFileManager( | 314 sourceFileManager = |
329 sourceFileProvider, | 315 new ProviderSourceFileManager(sourceFileProvider, outputProvider); |
330 outputProvider); | |
331 RecordingSourceInformationStrategy strategy = | 316 RecordingSourceInformationStrategy strategy = |
332 new RecordingSourceInformationStrategy(backend.sourceInformationStrategy
); | 317 new RecordingSourceInformationStrategy( |
| 318 backend.sourceInformationStrategy); |
333 backend.sourceInformationStrategy = strategy; | 319 backend.sourceInformationStrategy = strategy; |
334 await compiler.run(inputUri); | 320 await compiler.run(inputUri); |
335 | 321 |
336 SourceMapInfo mainSourceMapInfo; | 322 SourceMapInfo mainSourceMapInfo; |
337 Map<Element, SourceMapInfo> elementSourceMapInfos = | 323 Map<Element, SourceMapInfo> elementSourceMapInfos = |
338 <Element, SourceMapInfo>{}; | 324 <Element, SourceMapInfo>{}; |
339 if (perElement) { | 325 if (perElement) { |
340 backend.generatedCode.forEach((Element element, js.Expression node) { | 326 backend.generatedCode.forEach((Element element, js.Expression node) { |
341 RecordedSourceInformationProcess subProcess = | 327 RecordedSourceInformationProcess subProcess = |
342 strategy.subProcessForNode(node); | 328 strategy.subProcessForNode(node); |
343 if (subProcess == null) { | 329 if (subProcess == null) { |
344 // TODO(johnniwinther): Find out when this is happening and if it | 330 // TODO(johnniwinther): Find out when this is happening and if it |
345 // is benign. (Known to happen for `bool#fromString`) | 331 // is benign. (Known to happen for `bool#fromString`) |
346 print('No subProcess found for $element'); | 332 print('No subProcess found for $element'); |
347 return; | 333 return; |
348 } | 334 } |
349 LocationMap nodeMap = subProcess.nodeToSourceLocationsMap; | 335 LocationMap nodeMap = subProcess.nodeToSourceLocationsMap; |
350 String code = subProcess.code; | 336 String code = subProcess.code; |
351 CodePositionRecorder codePositions = subProcess.codePositions; | 337 CodePositionRecorder codePositions = subProcess.codePositions; |
352 CodePointComputer visitor = | 338 CodePointComputer visitor = |
353 new CodePointComputer(sourceFileManager, code, nodeMap); | 339 new CodePointComputer(sourceFileManager, code, nodeMap); |
354 new JavaScriptTracer(codePositions, [visitor]).apply(node); | 340 new JavaScriptTracer(codePositions, [visitor]).apply(node); |
355 List<CodePoint> codePoints = visitor.codePoints; | 341 List<CodePoint> codePoints = visitor.codePoints; |
356 elementSourceMapInfos[element] = new SourceMapInfo( | 342 elementSourceMapInfos[element] = new SourceMapInfo( |
357 element, | 343 element, code, node, codePoints, codePositions, nodeMap); |
358 code, | |
359 node, | |
360 codePoints, | |
361 codePositions, | |
362 nodeMap); | |
363 }); | 344 }); |
364 } | 345 } |
365 if (forMain) { | 346 if (forMain) { |
366 // TODO(johnniwinther): Supported multiple output units. | 347 // TODO(johnniwinther): Supported multiple output units. |
367 RecordedSourceInformationProcess process = strategy.processMap.keys.first; | 348 RecordedSourceInformationProcess process = strategy.processMap.keys.first; |
368 js.Node node = strategy.processMap[process]; | 349 js.Node node = strategy.processMap[process]; |
369 String code; | 350 String code; |
370 LocationMap nodeMap; | 351 LocationMap nodeMap; |
371 CodePositionRecorder codePositions; | 352 CodePositionRecorder codePositions; |
372 nodeMap = process.nodeToSourceLocationsMap; | 353 nodeMap = process.nodeToSourceLocationsMap; |
373 code = process.code; | 354 code = process.code; |
374 codePositions = process.codePositions; | 355 codePositions = process.codePositions; |
375 CodePointComputer visitor = | 356 CodePointComputer visitor = |
376 new CodePointComputer(sourceFileManager, code, nodeMap); | 357 new CodePointComputer(sourceFileManager, code, nodeMap); |
377 new JavaScriptTracer(codePositions, [visitor]).apply(node); | 358 new JavaScriptTracer(codePositions, [visitor]).apply(node); |
378 List<CodePoint> codePoints = visitor.codePoints; | 359 List<CodePoint> codePoints = visitor.codePoints; |
379 mainSourceMapInfo = new SourceMapInfo( | 360 mainSourceMapInfo = new SourceMapInfo( |
380 null, code, node, | 361 null, code, node, codePoints, codePositions, nodeMap); |
381 codePoints, | |
382 codePositions, | |
383 nodeMap); | |
384 } | 362 } |
385 | 363 |
386 return new SourceMaps( | 364 return new SourceMaps( |
387 compiler, | 365 compiler, sourceFileManager, mainSourceMapInfo, elementSourceMapInfos); |
388 sourceFileManager, | |
389 mainSourceMapInfo, | |
390 elementSourceMapInfos); | |
391 } | 366 } |
392 } | 367 } |
393 | 368 |
394 class SourceMaps { | 369 class SourceMaps { |
395 final api.CompilerImpl compiler; | 370 final api.CompilerImpl compiler; |
396 final SourceFileManager sourceFileManager; | 371 final SourceFileManager sourceFileManager; |
397 // TODO(johnniwinther): Supported multiple output units. | 372 // TODO(johnniwinther): Supported multiple output units. |
398 final SourceMapInfo mainSourceMapInfo; | 373 final SourceMapInfo mainSourceMapInfo; |
399 final Map<Element, SourceMapInfo> elementSourceMapInfos; | 374 final Map<Element, SourceMapInfo> elementSourceMapInfos; |
400 | 375 |
401 SourceMaps( | 376 SourceMaps(this.compiler, this.sourceFileManager, this.mainSourceMapInfo, |
402 this.compiler, | 377 this.elementSourceMapInfos); |
403 this.sourceFileManager, | |
404 this.mainSourceMapInfo, | |
405 this.elementSourceMapInfos); | |
406 } | 378 } |
407 | 379 |
408 /// Source mapping information for the JavaScript code of an [Element]. | 380 /// Source mapping information for the JavaScript code of an [Element]. |
409 class SourceMapInfo { | 381 class SourceMapInfo { |
410 final String name; | 382 final String name; |
411 final Element element; | 383 final Element element; |
412 final String code; | 384 final String code; |
413 final js.Node node; | 385 final js.Node node; |
414 final List<CodePoint> codePoints; | 386 final List<CodePoint> codePoints; |
415 final CodePositionMap jsCodePositions; | 387 final CodePositionMap jsCodePositions; |
416 final LocationMap nodeMap; | 388 final LocationMap nodeMap; |
417 | 389 |
418 SourceMapInfo( | 390 SourceMapInfo(Element element, this.code, this.node, this.codePoints, |
419 Element element, | 391 this.jsCodePositions, this.nodeMap) |
420 this.code, | |
421 this.node, | |
422 this.codePoints, | |
423 this.jsCodePositions, | |
424 this.nodeMap) | |
425 : this.name = | 392 : this.name = |
426 element != null ? computeElementNameForSourceMaps(element) : '', | 393 element != null ? computeElementNameForSourceMaps(element) : '', |
427 this.element = element; | 394 this.element = element; |
428 | 395 |
429 String toString() { | 396 String toString() { |
430 return '$name:$element'; | 397 return '$name:$element'; |
431 } | 398 } |
432 } | 399 } |
433 | 400 |
434 /// Collection of JavaScript nodes with their source mapped target offsets | 401 /// Collection of JavaScript nodes with their source mapped target offsets |
435 /// and source locations. | 402 /// and source locations. |
436 abstract class LocationMap { | 403 abstract class LocationMap { |
437 Iterable<js.Node> get nodes; | 404 Iterable<js.Node> get nodes; |
438 | 405 |
439 Map<int, List<SourceLocation>> operator[] (js.Node node); | 406 Map<int, List<SourceLocation>> operator [](js.Node node); |
440 | 407 |
441 factory LocationMap.recorder() = _LocationRecorder; | 408 factory LocationMap.recorder() = _LocationRecorder; |
442 | 409 |
443 factory LocationMap.filter(Set<js.Node> nodes, LocationMap map) = | 410 factory LocationMap.filter(Set<js.Node> nodes, LocationMap map) = |
444 _FilteredLocationMap; | 411 _FilteredLocationMap; |
445 | |
446 } | 412 } |
447 | 413 |
448 class _LocationRecorder | 414 class _LocationRecorder implements SourceMapper, LocationMap { |
449 implements SourceMapper, LocationMap { | |
450 final Map<js.Node, Map<int, List<SourceLocation>>> _nodeMap = {}; | 415 final Map<js.Node, Map<int, List<SourceLocation>>> _nodeMap = {}; |
451 | 416 |
452 @override | 417 @override |
453 void register(js.Node node, int codeOffset, SourceLocation sourceLocation) { | 418 void register(js.Node node, int codeOffset, SourceLocation sourceLocation) { |
454 _nodeMap.putIfAbsent(node, () => {}) | 419 _nodeMap |
| 420 .putIfAbsent(node, () => {}) |
455 .putIfAbsent(codeOffset, () => []) | 421 .putIfAbsent(codeOffset, () => []) |
456 .add(sourceLocation); | 422 .add(sourceLocation); |
457 } | 423 } |
458 | 424 |
459 Iterable<js.Node> get nodes => _nodeMap.keys; | 425 Iterable<js.Node> get nodes => _nodeMap.keys; |
460 | 426 |
461 Map<int, List<SourceLocation>> operator[] (js.Node node) { | 427 Map<int, List<SourceLocation>> operator [](js.Node node) { |
462 return _nodeMap[node]; | 428 return _nodeMap[node]; |
463 } | 429 } |
464 } | 430 } |
465 | 431 |
466 class _FilteredLocationMap implements LocationMap { | 432 class _FilteredLocationMap implements LocationMap { |
467 final Set<js.Node> _nodes; | 433 final Set<js.Node> _nodes; |
468 final LocationMap map; | 434 final LocationMap map; |
469 | 435 |
470 _FilteredLocationMap(this._nodes, this.map); | 436 _FilteredLocationMap(this._nodes, this.map); |
471 | 437 |
472 Iterable<js.Node> get nodes => map.nodes.where((n) => _nodes.contains(n)); | 438 Iterable<js.Node> get nodes => map.nodes.where((n) => _nodes.contains(n)); |
473 | 439 |
474 Map<int, List<SourceLocation>> operator[] (js.Node node) { | 440 Map<int, List<SourceLocation>> operator [](js.Node node) { |
475 return map[node]; | 441 return map[node]; |
476 } | 442 } |
477 } | 443 } |
478 | 444 |
479 | |
480 /// Visitor that computes the [CodePoint]s for source mapping locations. | 445 /// Visitor that computes the [CodePoint]s for source mapping locations. |
481 class CodePointComputer extends TraceListener { | 446 class CodePointComputer extends TraceListener { |
482 final SourceFileManager sourceFileManager; | 447 final SourceFileManager sourceFileManager; |
483 final String code; | 448 final String code; |
484 final LocationMap nodeMap; | 449 final LocationMap nodeMap; |
485 List<CodePoint> codePoints = []; | 450 List<CodePoint> codePoints = []; |
486 | 451 |
487 CodePointComputer(this.sourceFileManager, this.code, this.nodeMap); | 452 CodePointComputer(this.sourceFileManager, this.code, this.nodeMap); |
488 | 453 |
489 String nodeToString(js.Node node) { | 454 String nodeToString(js.Node node) { |
(...skipping 14 matching lines...) Expand all Loading... |
504 return line; | 469 return line; |
505 } | 470 } |
506 | 471 |
507 /// Called when [node] defines a step of the given [kind] at the given | 472 /// Called when [node] defines a step of the given [kind] at the given |
508 /// [offset] when the generated JavaScript code. | 473 /// [offset] when the generated JavaScript code. |
509 void onStep(js.Node node, Offset offset, StepKind kind) { | 474 void onStep(js.Node node, Offset offset, StepKind kind) { |
510 register(kind, node); | 475 register(kind, node); |
511 } | 476 } |
512 | 477 |
513 void register(StepKind kind, js.Node node, {bool expectInfo: true}) { | 478 void register(StepKind kind, js.Node node, {bool expectInfo: true}) { |
514 | |
515 String dartCodeFromSourceLocation(SourceLocation sourceLocation) { | 479 String dartCodeFromSourceLocation(SourceLocation sourceLocation) { |
516 SourceFile sourceFile = | 480 SourceFile sourceFile = |
517 sourceFileManager.getSourceFile(sourceLocation.sourceUri); | 481 sourceFileManager.getSourceFile(sourceLocation.sourceUri); |
518 if (sourceFile == null) { | 482 if (sourceFile == null) { |
519 return sourceLocation.shortText; | 483 return sourceLocation.shortText; |
520 } | 484 } |
521 return sourceFile.getLineText(sourceLocation.line) | 485 return sourceFile |
522 .substring(sourceLocation.column).trim(); | 486 .getLineText(sourceLocation.line) |
| 487 .substring(sourceLocation.column) |
| 488 .trim(); |
523 } | 489 } |
524 | 490 |
525 void addLocation(SourceLocation sourceLocation, String jsCode) { | 491 void addLocation(SourceLocation sourceLocation, String jsCode) { |
526 if (sourceLocation == null) { | 492 if (sourceLocation == null) { |
527 if (expectInfo) { | 493 if (expectInfo) { |
528 SourceInformation sourceInformation = node.sourceInformation; | 494 SourceInformation sourceInformation = node.sourceInformation; |
529 SourceLocation sourceLocation; | 495 SourceLocation sourceLocation; |
530 String dartCode; | 496 String dartCode; |
531 if (sourceInformation != null) { | 497 if (sourceInformation != null) { |
532 sourceLocation = sourceInformation.sourceLocations.first; | 498 sourceLocation = sourceInformation.sourceLocations.first; |
533 dartCode = dartCodeFromSourceLocation(sourceLocation); | 499 dartCode = dartCodeFromSourceLocation(sourceLocation); |
534 } | 500 } |
535 codePoints.add(new CodePoint( | 501 codePoints.add(new CodePoint(kind, jsCode, sourceLocation, dartCode, |
536 kind, jsCode, sourceLocation, dartCode, isMissing: true)); | 502 isMissing: true)); |
537 } | 503 } |
538 } else { | 504 } else { |
539 codePoints.add(new CodePoint(kind, jsCode, sourceLocation, | 505 codePoints.add(new CodePoint(kind, jsCode, sourceLocation, |
540 dartCodeFromSourceLocation(sourceLocation))); | 506 dartCodeFromSourceLocation(sourceLocation))); |
541 } | 507 } |
542 } | 508 } |
543 | 509 |
544 Map<int, List<SourceLocation>> locationMap = nodeMap[node]; | 510 Map<int, List<SourceLocation>> locationMap = nodeMap[node]; |
545 if (locationMap == null) { | 511 if (locationMap == null) { |
546 addLocation(null, nodeToString(node)); | 512 addLocation(null, nodeToString(node)); |
547 } else { | 513 } else { |
548 locationMap.forEach((int targetOffset, List<SourceLocation> locations) { | 514 locationMap.forEach((int targetOffset, List<SourceLocation> locations) { |
549 String jsCode = nodeToString(node); | 515 String jsCode = nodeToString(node); |
550 for (SourceLocation location in locations) { | 516 for (SourceLocation location in locations) { |
551 addLocation(location, jsCode); | 517 addLocation(location, jsCode); |
552 } | 518 } |
553 }); | 519 }); |
554 } | 520 } |
555 } | 521 } |
556 } | 522 } |
557 | 523 |
558 /// A JavaScript code point and its mapped dart source location. | 524 /// A JavaScript code point and its mapped dart source location. |
559 class CodePoint { | 525 class CodePoint { |
560 final StepKind kind; | 526 final StepKind kind; |
561 final String jsCode; | 527 final String jsCode; |
562 final SourceLocation sourceLocation; | 528 final SourceLocation sourceLocation; |
563 final String dartCode; | 529 final String dartCode; |
564 final bool isMissing; | 530 final bool isMissing; |
565 | 531 |
566 CodePoint( | 532 CodePoint(this.kind, this.jsCode, this.sourceLocation, this.dartCode, |
567 this.kind, | |
568 this.jsCode, | |
569 this.sourceLocation, | |
570 this.dartCode, | |
571 {this.isMissing: false}); | 533 {this.isMissing: false}); |
572 | 534 |
573 String toString() { | 535 String toString() { |
574 return 'CodePoint[kind=$kind,js=$jsCode,dart=$dartCode,' | 536 return 'CodePoint[kind=$kind,js=$jsCode,dart=$dartCode,' |
575 'location=$sourceLocation]'; | 537 'location=$sourceLocation]'; |
576 } | 538 } |
577 } | 539 } |
578 | 540 |
579 class IOSourceFileManager implements SourceFileManager { | 541 class IOSourceFileManager implements SourceFileManager { |
580 final Uri base; | 542 final Uri base; |
581 | 543 |
582 Map<Uri, SourceFile> sourceFiles = <Uri, SourceFile>{}; | 544 Map<Uri, SourceFile> sourceFiles = <Uri, SourceFile>{}; |
583 | 545 |
584 IOSourceFileManager(this.base); | 546 IOSourceFileManager(this.base); |
585 | 547 |
586 SourceFile getSourceFile(var uri) { | 548 SourceFile getSourceFile(var uri) { |
587 Uri absoluteUri; | 549 Uri absoluteUri; |
588 if (uri is Uri) { | 550 if (uri is Uri) { |
589 absoluteUri = base.resolveUri(uri); | 551 absoluteUri = base.resolveUri(uri); |
590 } else { | 552 } else { |
591 absoluteUri = base.resolve(uri); | 553 absoluteUri = base.resolve(uri); |
592 } | 554 } |
593 return sourceFiles.putIfAbsent(absoluteUri, () { | 555 return sourceFiles.putIfAbsent(absoluteUri, () { |
594 String text = new File.fromUri(absoluteUri).readAsStringSync(); | 556 String text = new File.fromUri(absoluteUri).readAsStringSync(); |
595 return new StringSourceFile.fromUri(absoluteUri, text); | 557 return new StringSourceFile.fromUri(absoluteUri, text); |
596 }); | 558 }); |
597 } | 559 } |
598 } | 560 } |
OLD | NEW |