| 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 |