Chromium Code Reviews| 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 'package:compiler/compiler_new.dart'; | 8 import 'package:compiler/compiler_new.dart'; |
| 9 import 'package:compiler/src/apiimpl.dart' as api; | 9 import 'package:compiler/src/apiimpl.dart' as api; |
| 10 import 'package:compiler/src/null_compiler_output.dart' show NullSink; | 10 import 'package:compiler/src/null_compiler_output.dart' show NullSink; |
| 11 import 'package:compiler/src/elements/elements.dart'; | 11 import 'package:compiler/src/elements/elements.dart'; |
| 12 import 'package:compiler/src/helpers/helpers.dart'; | 12 import 'package:compiler/src/helpers/helpers.dart'; |
| 13 import 'package:compiler/src/filenames.dart'; | 13 import 'package:compiler/src/filenames.dart'; |
| 14 import 'package:compiler/src/io/code_output.dart'; | |
| 14 import 'package:compiler/src/io/source_file.dart'; | 15 import 'package:compiler/src/io/source_file.dart'; |
| 15 import 'package:compiler/src/io/source_information.dart'; | 16 import 'package:compiler/src/io/source_information.dart'; |
| 17 import 'package:compiler/src/io/position_information.dart'; | |
| 16 import 'package:compiler/src/js/js.dart' as js; | 18 import 'package:compiler/src/js/js.dart' as js; |
| 17 import 'package:compiler/src/js/js_debug.dart'; | 19 import 'package:compiler/src/js/js_debug.dart'; |
| 18 import 'package:compiler/src/js/js_source_mapping.dart'; | 20 import 'package:compiler/src/js/js_source_mapping.dart'; |
| 19 import 'package:compiler/src/js_backend/js_backend.dart'; | 21 import 'package:compiler/src/js_backend/js_backend.dart'; |
| 20 import 'package:compiler/src/source_file_provider.dart'; | 22 import 'package:compiler/src/source_file_provider.dart'; |
| 21 import '../memory_compiler.dart'; | 23 import '../memory_compiler.dart'; |
| 22 import '../output_collector.dart'; | 24 import '../output_collector.dart'; |
| 23 | 25 |
| 26 class SourceFileSink implements EventSink<String> { | |
| 27 final String filename; | |
| 28 StringBuffer sb = new StringBuffer(); | |
| 29 SourceFile sourceFile; | |
| 30 | |
| 31 SourceFileSink(this.filename); | |
| 32 | |
| 33 @override | |
| 34 void add(String event) { | |
| 35 sb.write(event); | |
| 36 } | |
| 37 | |
| 38 @override | |
| 39 void addError(errorEvent, [StackTrace stackTrace]) { | |
| 40 // Ignore. | |
| 41 } | |
| 42 | |
| 43 @override | |
| 44 void close() { | |
| 45 sourceFile = new StringSourceFile.fromName(filename, sb.toString()); | |
| 46 } | |
| 47 } | |
| 48 | |
| 24 class OutputProvider implements CompilerOutput { | 49 class OutputProvider implements CompilerOutput { |
| 25 BufferedEventSink jsMapOutput; | 50 Map<Uri, SourceFileSink> outputMap = <Uri, SourceFileSink>{}; |
| 51 | |
| 52 SourceFile getSourceFile(Uri uri) { | |
| 53 SourceFileSink sink = outputMap[uri]; | |
| 54 if (sink != null) { | |
| 55 return sink.sourceFile; | |
| 56 } | |
| 57 return null; | |
| 58 } | |
| 59 | |
| 60 SourceFileSink createSourceFileSink(String name, String extension) { | |
| 61 String filename = '$name.$extension'; | |
| 62 SourceFileSink sink = new SourceFileSink(filename); | |
| 63 Uri uri = Uri.parse(filename); | |
| 64 outputMap[uri] = sink; | |
| 65 return sink; | |
| 66 } | |
| 26 | 67 |
| 27 @override | 68 @override |
| 28 EventSink<String> createEventSink(String name, String extension) { | 69 EventSink<String> createEventSink(String name, String extension) { |
| 29 if (extension == 'js.map') { | 70 return createSourceFileSink(name, extension); |
| 30 return jsMapOutput = new BufferedEventSink(); | |
| 31 } | |
| 32 return new NullSink('$name.$extension'); | |
| 33 } | 71 } |
| 34 } | 72 } |
| 35 | 73 |
| 36 class CloningOutputProvider extends OutputProvider { | 74 class CloningOutputProvider extends OutputProvider { |
| 37 RandomAccessFileOutputProvider outputProvider; | 75 RandomAccessFileOutputProvider outputProvider; |
| 38 | 76 |
| 39 CloningOutputProvider(Uri jsUri, Uri jsMapUri) | 77 CloningOutputProvider(Uri jsUri, Uri jsMapUri) |
| 40 : outputProvider = new RandomAccessFileOutputProvider(jsUri, jsMapUri); | 78 : outputProvider = new RandomAccessFileOutputProvider(jsUri, jsMapUri); |
| 41 | 79 |
| 42 @override | 80 @override |
| 43 EventSink<String> createEventSink(String name, String extension) { | 81 EventSink<String> createEventSink(String name, String extension) { |
| 44 EventSink<String> output = outputProvider(name, extension); | 82 EventSink<String> output = outputProvider(name, extension); |
| 45 if (extension == 'js.map') { | 83 return new CloningEventSink( |
| 46 output = new CloningEventSink( | 84 [output, createSourceFileSink(name, extension)]); |
| 47 [output, jsMapOutput = new BufferedEventSink()]); | |
| 48 } | |
| 49 return output; | |
| 50 } | 85 } |
| 51 } | 86 } |
| 52 | 87 |
| 53 abstract class SourceFileManager { | 88 abstract class SourceFileManager { |
| 54 SourceFile getSourceFile(var uri); | 89 SourceFile getSourceFile(var uri); |
| 55 } | 90 } |
| 56 | 91 |
| 57 class ProviderSourceFileManager implements SourceFileManager { | 92 class ProviderSourceFileManager implements SourceFileManager { |
| 58 final SourceFileProvider sourceFileProvider; | 93 final SourceFileProvider sourceFileProvider; |
| 94 final OutputProvider outputProvider; | |
| 59 | 95 |
| 60 ProviderSourceFileManager(this.sourceFileProvider); | 96 ProviderSourceFileManager(this.sourceFileProvider, this.outputProvider); |
| 61 | 97 |
| 62 @override | 98 @override |
| 63 SourceFile getSourceFile(uri) { | 99 SourceFile getSourceFile(uri) { |
| 64 return sourceFileProvider.getSourceFile(uri); | 100 SourceFile sourceFile = sourceFileProvider.getSourceFile(uri); |
| 101 if (sourceFile == null) { | |
| 102 sourceFile = outputProvider.getSourceFile(uri); | |
| 103 } | |
| 104 return sourceFile; | |
| 65 } | 105 } |
| 66 } | 106 } |
| 67 | 107 |
| 68 class RecordingPrintingContext extends LenientPrintingContext { | 108 class RecordingPrintingContext extends LenientPrintingContext { |
| 69 CodePositionListener listener; | 109 CodePositionListener listener; |
| 110 Map<js.Node, CodePosition> codePositions = <js.Node, CodePosition>{}; | |
| 70 | 111 |
| 71 RecordingPrintingContext(this.listener); | 112 RecordingPrintingContext(this.listener); |
| 72 | 113 |
| 73 @override | 114 @override |
| 74 void exitNode(js.Node node, | 115 void exitNode(js.Node node, |
| 75 int startPosition, | 116 int startPosition, |
| 76 int endPosition, | 117 int endPosition, |
| 77 int closingPosition) { | 118 int closingPosition) { |
| 119 codePositions[node] = | |
| 120 new CodePosition(startPosition, endPosition, closingPosition); | |
| 78 listener.onPositions( | 121 listener.onPositions( |
| 79 node, startPosition, endPosition, closingPosition); | 122 node, startPosition, endPosition, closingPosition); |
| 80 } | 123 } |
| 81 } | 124 } |
| 82 | 125 |
| 126 class SourceMapperWrapper implements SourceMapper { | |
|
Siggi Cherem (dart-lang)
2016/01/21 18:18:34
+ dartdoc, maybe rename to something more descript
Johnni Winther
2016/01/22 15:12:39
Done.
| |
| 127 final SourceMapper sourceMapper; | |
| 128 final NodeToSourceLocationRecorder nodeToSourceLocationsMap; | |
| 129 | |
| 130 SourceMapperWrapper(this.sourceMapper, this.nodeToSourceLocationsMap); | |
| 131 | |
| 132 @override | |
| 133 void register(js.Node node, int codeOffset, SourceLocation sourceLocation) { | |
| 134 nodeToSourceLocationsMap.register(node, codeOffset, sourceLocation); | |
| 135 sourceMapper.register(node, codeOffset, sourceLocation); | |
| 136 } | |
| 137 } | |
| 138 | |
| 139 class SourceInformationProcessorWrapper implements SourceInformationProcessor { | |
| 140 final SourceInformationStrategyWrapper wrapper; | |
| 141 final SourceInformationProcessor processor; | |
| 142 final CodePositionRecorder codePositions; | |
| 143 final NodeToSourceLocationsMap nodeToSourceLocationsMap; | |
| 144 | |
| 145 SourceInformationProcessorWrapper( | |
| 146 this.wrapper, | |
| 147 this.processor, | |
| 148 this.codePositions, | |
| 149 this.nodeToSourceLocationsMap); | |
| 150 | |
| 151 @override | |
| 152 void onPositions(js.Node node, | |
| 153 int startPosition, | |
| 154 int endPosition, | |
| 155 int closingPosition) { | |
| 156 codePositions.registerPositions( | |
| 157 node, startPosition, endPosition, closingPosition); | |
| 158 processor.onPositions(node, startPosition, endPosition, closingPosition); | |
| 159 } | |
| 160 | |
| 161 @override | |
| 162 void process(js.Node node, BufferedCodeOutput code) { | |
| 163 processor.process(node, code); | |
| 164 wrapper.registerProcess( | |
| 165 node, code, codePositions, nodeToSourceLocationsMap); | |
| 166 } | |
| 167 } | |
| 168 | |
| 169 class SourceInformationSubProcess { | |
|
Siggi Cherem (dart-lang)
2016/01/21 18:18:35
rename? SubProcess really makes me think that you
Johnni Winther
2016/01/22 15:12:39
Renamed to 'RecordedSourceInformationProcess'.
| |
| 170 final js.Node root; | |
| 171 final String code; | |
| 172 final CodePositionRecorder codePositions; | |
| 173 final NodeToSourceLocationsMap nodeToSourceLocationsMap; | |
| 174 | |
| 175 SourceInformationSubProcess( | |
| 176 this.root, | |
| 177 this.code, | |
| 178 this.codePositions, | |
| 179 this.nodeToSourceLocationsMap); | |
| 180 } | |
| 181 | |
| 182 | |
| 183 class SourceInformationStrategyWrapper | |
|
Siggi Cherem (dart-lang)
2016/01/21 18:18:35
it took me some time to figure out what these wrap
Johnni Winther
2016/01/22 15:12:38
It's (only) per element (also) output units. Updat
| |
| 184 extends JavaScriptSourceInformationStrategy { | |
| 185 final JavaScriptSourceInformationStrategy strategy; | |
| 186 final Map<SourceInformationSubProcess, js.Node> processMap = | |
| 187 <SourceInformationSubProcess, js.Node>{}; | |
| 188 final Map<js.Node, SourceInformationSubProcess> nodeMap = | |
| 189 <js.Node, SourceInformationSubProcess>{}; | |
| 190 | |
| 191 SourceInformationStrategyWrapper(this.strategy); | |
| 192 | |
| 193 @override | |
| 194 SourceInformationBuilder createBuilderForContext(AstElement element) { | |
| 195 return strategy.createBuilderForContext(element); | |
| 196 } | |
| 197 | |
| 198 @override | |
| 199 SourceInformationProcessor createProcessor(SourceMapper sourceMapper) { | |
| 200 NodeToSourceLocationsMap nodeToSourceLocationsMap = | |
| 201 new NodeToSourceLocationRecorder(); | |
| 202 CodePositionRecorder codePositions = new CodePositionRecorder(); | |
| 203 return new SourceInformationProcessorWrapper( | |
| 204 this, | |
| 205 strategy.createProcessor(new SourceMapperWrapper( | |
| 206 sourceMapper, nodeToSourceLocationsMap)), | |
| 207 codePositions, nodeToSourceLocationsMap); | |
| 208 } | |
| 209 | |
| 210 void registerProcess(js.Node root, | |
| 211 BufferedCodeOutput code, | |
| 212 CodePositionRecorder codePositions, | |
| 213 NodeToSourceLocationsMap nodeToSourceLocationsMap) { | |
| 214 SourceInformationSubProcess subProcess = new SourceInformationSubProcess( | |
| 215 root, code.getText(), codePositions, nodeToSourceLocationsMap); | |
| 216 processMap[subProcess] = root; | |
| 217 } | |
| 218 | |
| 219 SourceInformationSubProcess subProcessForNode(js.Node node) { | |
| 220 return nodeMap.putIfAbsent(node, () { | |
| 221 for (SourceInformationSubProcess subProcess in processMap.keys) { | |
| 222 js.Node root = processMap[subProcess]; | |
| 223 FindVisitor visitor = new FindVisitor(node); | |
| 224 root.accept(visitor); | |
| 225 if (visitor.found) { | |
| 226 return new SourceInformationSubProcess( | |
| 227 node, | |
| 228 subProcess.code, | |
| 229 subProcess.codePositions, | |
| 230 new NodeToSourceLocationsMapWrapper( | |
| 231 visitor.nodes, subProcess.nodeToSourceLocationsMap)); | |
| 232 } | |
| 233 return null; | |
| 234 } | |
| 235 }); | |
| 236 } | |
| 237 } | |
| 238 | |
| 239 class FindVisitor extends js.BaseVisitor { | |
|
Siggi Cherem (dart-lang)
2016/01/21 18:18:34
+dartdoc:
/// Visitor that collects all nodes tha
| |
| 240 final js.Node soughtNode; | |
| 241 bool found = false; | |
| 242 bool add = false; | |
| 243 final Set<js.Node> nodes = new Set<js.Node>(); | |
| 244 | |
| 245 FindVisitor(this.soughtNode); | |
| 246 | |
| 247 visitNode(js.Node node) { | |
| 248 if (node == soughtNode) { | |
| 249 found = true; | |
| 250 add = true; | |
| 251 } | |
| 252 if (add) { | |
| 253 nodes.add(node); | |
| 254 } | |
| 255 node.visitChildren(this); | |
| 256 if (node == soughtNode) { | |
| 257 add = false; | |
| 258 } | |
| 259 } | |
| 260 } | |
| 261 | |
| 262 const String USE_NEW_SOURCE_INFO = '--use-new-source-info'; | |
| 263 const String DISABLE_INLINING = '--disable-inlining'; | |
| 264 | |
| 83 /// Processor that computes [SourceMapInfo] for the JavaScript compiled for a | 265 /// Processor that computes [SourceMapInfo] for the JavaScript compiled for a |
| 84 /// given Dart file. | 266 /// given Dart file. |
| 85 class SourceMapProcessor { | 267 class SourceMapProcessor { |
| 86 /// If `true` the output from the compilation is written to files. | 268 /// If `true` the output from the compilation is written to files. |
| 87 final bool outputToFile; | 269 final bool outputToFile; |
| 88 | 270 |
| 89 /// The [Uri] of the Dart entrypoint. | 271 /// The [Uri] of the Dart entrypoint. |
| 90 Uri inputUri; | 272 Uri inputUri; |
| 91 | 273 |
| 92 /// The name of the JavaScript output file. | 274 /// The name of the JavaScript output file. |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 105 SourceMapProcessor(String filename, {this.outputToFile: false}) { | 287 SourceMapProcessor(String filename, {this.outputToFile: false}) { |
| 106 inputUri = Uri.base.resolve(nativeToUriPath(filename)); | 288 inputUri = Uri.base.resolve(nativeToUriPath(filename)); |
| 107 jsPath = 'out.js'; | 289 jsPath = 'out.js'; |
| 108 targetUri = Uri.base.resolve(jsPath); | 290 targetUri = Uri.base.resolve(jsPath); |
| 109 sourceMapFileUri = Uri.base.resolve('${jsPath}.map'); | 291 sourceMapFileUri = Uri.base.resolve('${jsPath}.map'); |
| 110 } | 292 } |
| 111 | 293 |
| 112 /// Computes the [SourceMapInfo] for the compiled elements. | 294 /// Computes the [SourceMapInfo] for the compiled elements. |
| 113 Future<List<SourceMapInfo>> process( | 295 Future<List<SourceMapInfo>> process( |
| 114 List<String> options, | 296 List<String> options, |
| 115 {bool verbose: true}) async { | 297 {bool verbose: true, |
| 298 bool perElement: true}) async { | |
| 116 OutputProvider outputProvider = outputToFile | 299 OutputProvider outputProvider = outputToFile |
| 117 ? new OutputProvider() | 300 ? new CloningOutputProvider(targetUri, sourceMapFileUri) |
| 118 : new CloningOutputProvider(targetUri, sourceMapFileUri); | 301 : new OutputProvider(); |
| 119 if (options.contains('--use-new-source-info')) { | 302 if (options.contains(USE_NEW_SOURCE_INFO)) { |
| 120 if (verbose) print('Using the new source information system.'); | 303 if (verbose) print('Using the new source information system.'); |
| 121 useNewSourceInfo = true; | 304 useNewSourceInfo = true; |
| 122 } | 305 } |
| 123 api.CompilerImpl compiler = await compilerFor( | 306 api.CompilerImpl compiler = await compilerFor( |
| 124 outputProvider: outputProvider, | 307 outputProvider: outputProvider, |
| 125 // TODO(johnniwinther): Use [verbose] to avoid showing diagnostics. | 308 // TODO(johnniwinther): Use [verbose] to avoid showing diagnostics. |
| 126 options: ['--out=$targetUri', '--source-map=$sourceMapFileUri'] | 309 options: ['--out=$targetUri', '--source-map=$sourceMapFileUri'] |
| 127 ..addAll(options)); | 310 ..addAll(options)); |
| 128 if (options.contains('--disable-inlining')) { | 311 if (options.contains(DISABLE_INLINING)) { |
| 129 if (verbose) print('Inlining disabled'); | 312 if (verbose) print('Inlining disabled'); |
| 130 compiler.disableInlining = true; | 313 compiler.disableInlining = true; |
| 131 } | 314 } |
| 132 | 315 |
| 133 JavaScriptBackend backend = compiler.backend; | 316 JavaScriptBackend backend = compiler.backend; |
| 134 var handler = compiler.handler; | 317 var handler = compiler.handler; |
| 135 SourceFileProvider sourceFileProvider = handler.provider; | 318 SourceFileProvider sourceFileProvider = handler.provider; |
| 136 sourceFileManager = new ProviderSourceFileManager(sourceFileProvider); | 319 sourceFileManager = new ProviderSourceFileManager( |
| 320 sourceFileProvider, | |
| 321 outputProvider); | |
| 322 SourceInformationStrategyWrapper strategy = | |
| 323 new SourceInformationStrategyWrapper(backend.sourceInformationStrategy); | |
| 324 backend.sourceInformationStrategy = strategy; | |
| 137 await compiler.run(inputUri); | 325 await compiler.run(inputUri); |
| 138 | 326 |
| 139 List<SourceMapInfo> infoList = <SourceMapInfo>[]; | 327 List<SourceMapInfo> infoList = <SourceMapInfo>[]; |
| 140 backend.generatedCode.forEach((Element element, js.Expression node) { | 328 if (perElement) { |
| 141 js.JavaScriptPrintingOptions options = | 329 backend.generatedCode.forEach((Element element, js.Expression node) { |
| 142 new js.JavaScriptPrintingOptions(); | 330 SourceInformationSubProcess subProcess = |
| 143 JavaScriptSourceInformationStrategy sourceInformationStrategy = | 331 strategy.subProcessForNode(node); |
| 144 compiler.backend.sourceInformationStrategy; | 332 if (subProcess == null) { |
| 145 NodeToSourceLocationsMap nodeMap = new NodeToSourceLocationsMap(); | 333 // TODO(johnniwinther): Find out when this is happening and if it |
| 146 SourceInformationProcessor sourceInformationProcessor = | 334 // is benign. (Known to happen for `bool#fromString`) |
| 147 sourceInformationStrategy.createProcessor(nodeMap); | 335 print('No subProcess found for $element'); |
| 148 RecordingPrintingContext printingContext = | 336 return; |
| 149 new RecordingPrintingContext(sourceInformationProcessor); | 337 } |
| 150 new js.Printer(options, printingContext).visit(node); | 338 NodeToSourceLocationsMap nodeMap = subProcess.nodeToSourceLocationsMap; |
| 151 sourceInformationProcessor.process(node); | 339 String code = subProcess.code; |
| 152 | 340 CodePositionRecorder codePositions = subProcess.codePositions; |
| 153 String code = printingContext.getText(); | 341 CodePointComputer visitor = |
| 342 new CodePointComputer(sourceFileManager, code, nodeMap); | |
| 343 visitor.apply(node); | |
| 344 List<CodePoint> codePoints = visitor.codePoints; | |
| 345 infoList.add(new SourceMapInfo( | |
| 346 element, code, node, | |
| 347 codePoints, | |
| 348 codePositions/*strategy.codePositions*/, | |
| 349 nodeMap)); | |
| 350 }); | |
| 351 } else { | |
| 352 // TODO(johnniwinther): Supported multiple output units. | |
| 353 SourceInformationSubProcess process = strategy.processMap.keys.first; | |
| 354 js.Node node = strategy.processMap[process]; | |
| 355 String code; | |
| 356 NodeToSourceLocationsMap nodeMap; | |
| 357 CodePositionRecorder codePositions; | |
| 358 nodeMap = process.nodeToSourceLocationsMap; | |
| 359 code = process.code; | |
| 360 codePositions = process.codePositions; | |
| 154 CodePointComputer visitor = | 361 CodePointComputer visitor = |
| 155 new CodePointComputer(sourceFileManager, code, nodeMap); | 362 new CodePointComputer(sourceFileManager, code, nodeMap); |
| 156 visitor.apply(node); | 363 visitor.apply(node); |
| 157 List<CodePoint> codePoints = visitor.codePoints; | 364 List<CodePoint> codePoints = visitor.codePoints; |
| 158 infoList.add(new SourceMapInfo(element, code, node, codePoints, nodeMap)); | 365 infoList.add(new SourceMapInfo( |
| 159 }); | 366 null, code, node, |
| 367 codePoints, | |
| 368 codePositions, | |
| 369 nodeMap)); | |
| 370 } | |
| 160 | 371 |
| 161 return infoList; | 372 return infoList; |
| 162 } | 373 } |
| 163 } | 374 } |
| 164 | 375 |
| 165 /// Source mapping information for the JavaScript code of an [Element]. | 376 /// Source mapping information for the JavaScript code of an [Element]. |
| 166 class SourceMapInfo { | 377 class SourceMapInfo { |
| 167 final String name; | 378 final String name; |
| 168 final Element element; | 379 final Element element; |
| 169 final String code; | 380 final String code; |
| 170 final js.Expression node; | 381 final js.Node node; |
| 171 final List<CodePoint> codePoints; | 382 final List<CodePoint> codePoints; |
| 383 final CodePositionMap jsCodePositions; | |
| 172 final NodeToSourceLocationsMap nodeMap; | 384 final NodeToSourceLocationsMap nodeMap; |
| 173 | 385 |
| 174 SourceMapInfo( | 386 SourceMapInfo( |
| 175 Element element, this.code, this.node, this.codePoints, this.nodeMap) | 387 Element element, |
| 176 : this.name = computeElementNameForSourceMaps(element), | 388 this.code, |
| 389 this.node, | |
| 390 this.codePoints, | |
| 391 this.jsCodePositions, | |
| 392 this.nodeMap) | |
| 393 : this.name = | |
| 394 element != null ? computeElementNameForSourceMaps(element) : '', | |
| 177 this.element = element; | 395 this.element = element; |
| 396 | |
| 397 String toString() { | |
| 398 return '$name:$element'; | |
| 399 } | |
| 178 } | 400 } |
| 179 | 401 |
| 180 /// Collection of JavaScript nodes with their source mapped target offsets | 402 /// Collection of JavaScript nodes with their source mapped target offsets |
| 181 /// and source locations. | 403 /// and source locations. |
| 182 class NodeToSourceLocationsMap implements SourceMapper { | 404 abstract class NodeToSourceLocationsMap { |
| 405 Iterable<js.Node> get nodes; | |
| 406 | |
| 407 Map<int, List<SourceLocation>> operator[] (js.Node node); | |
| 408 } | |
| 409 | |
| 410 class NodeToSourceLocationRecorder | |
| 411 implements SourceMapper, NodeToSourceLocationsMap { | |
| 183 final Map<js.Node, Map<int, List<SourceLocation>>> _nodeMap = {}; | 412 final Map<js.Node, Map<int, List<SourceLocation>>> _nodeMap = {}; |
| 184 | 413 |
| 185 @override | 414 @override |
| 186 void register(js.Node node, int codeOffset, SourceLocation sourceLocation) { | 415 void register(js.Node node, int codeOffset, SourceLocation sourceLocation) { |
| 187 _nodeMap.putIfAbsent(node, () => {}) | 416 _nodeMap.putIfAbsent(node, () => {}) |
| 188 .putIfAbsent(codeOffset, () => []) | 417 .putIfAbsent(codeOffset, () => []) |
| 189 .add(sourceLocation); | 418 .add(sourceLocation); |
| 190 } | 419 } |
| 191 | 420 |
| 192 Iterable<js.Node> get nodes => _nodeMap.keys; | 421 Iterable<js.Node> get nodes => _nodeMap.keys; |
| 193 | 422 |
| 194 Map<int, List<SourceLocation>> operator[] (js.Node node) { | 423 Map<int, List<SourceLocation>> operator[] (js.Node node) { |
| 195 return _nodeMap[node]; | 424 return _nodeMap[node]; |
| 196 } | 425 } |
| 197 } | 426 } |
| 198 | 427 |
| 428 class NodeToSourceLocationsMapWrapper implements NodeToSourceLocationsMap { | |
|
Siggi Cherem (dart-lang)
2016/01/21 18:18:35
nits/ideas:
- rename to PerElementNodeToSourceLoc
| |
| 429 final Set<js.Node> _nodes; | |
| 430 final NodeToSourceLocationsMap map; | |
| 431 | |
| 432 NodeToSourceLocationsMapWrapper(this._nodes, this.map); | |
| 433 | |
| 434 Iterable<js.Node> get nodes => map.nodes.where((n) => _nodes.contains(n)); | |
| 435 | |
| 436 Map<int, List<SourceLocation>> operator[] (js.Node node) { | |
| 437 return map[node]; | |
| 438 } | |
| 439 } | |
| 440 | |
| 441 | |
| 199 /// Visitor that computes the [CodePoint]s for source mapping locations. | 442 /// Visitor that computes the [CodePoint]s for source mapping locations. |
| 200 class CodePointComputer extends js.BaseVisitor { | 443 class CodePointComputer extends js.BaseVisitor { |
| 201 final SourceFileManager sourceFileManager; | 444 final SourceFileManager sourceFileManager; |
| 202 final String code; | 445 final String code; |
| 203 final NodeToSourceLocationsMap nodeMap; | 446 final NodeToSourceLocationsMap nodeMap; |
| 204 List<CodePoint> codePoints = []; | 447 List<CodePoint> codePoints = []; |
| 205 | 448 |
| 206 CodePointComputer(this.sourceFileManager, this.code, this.nodeMap); | 449 CodePointComputer(this.sourceFileManager, this.code, this.nodeMap); |
| 207 | 450 |
| 208 String nodeToString(js.Node node) { | 451 String nodeToString(js.Node node) { |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 329 this.jsCode, | 572 this.jsCode, |
| 330 this.sourceLocation, | 573 this.sourceLocation, |
| 331 this.dartCode, | 574 this.dartCode, |
| 332 {this.isMissing: false}); | 575 {this.isMissing: false}); |
| 333 | 576 |
| 334 String toString() { | 577 String toString() { |
| 335 return 'CodePoint[kind=$kind,js=$jsCode,dart=$dartCode,' | 578 return 'CodePoint[kind=$kind,js=$jsCode,dart=$dartCode,' |
| 336 'location=$sourceLocation]'; | 579 'location=$sourceLocation]'; |
| 337 } | 580 } |
| 338 } | 581 } |
| OLD | NEW |