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 /// A [SourceMapper] that records the source locations on each node. |
| 127 class RecordingSourceMapper implements SourceMapper { |
| 128 final SourceMapper sourceMapper; |
| 129 final _LocationRecorder nodeToSourceLocationsMap; |
| 130 |
| 131 RecordingSourceMapper(this.sourceMapper, this.nodeToSourceLocationsMap); |
| 132 |
| 133 @override |
| 134 void register(js.Node node, int codeOffset, SourceLocation sourceLocation) { |
| 135 nodeToSourceLocationsMap.register(node, codeOffset, sourceLocation); |
| 136 sourceMapper.register(node, codeOffset, sourceLocation); |
| 137 } |
| 138 } |
| 139 |
| 140 /// A wrapper of [SourceInformationProcessor] that records source locations and |
| 141 /// code positions. |
| 142 class RecordingSourceInformationProcessor |
| 143 implements SourceInformationProcessor { |
| 144 final RecordingSourceInformationStrategy wrapper; |
| 145 final SourceInformationProcessor processor; |
| 146 final CodePositionRecorder codePositions; |
| 147 final LocationMap nodeToSourceLocationsMap; |
| 148 |
| 149 RecordingSourceInformationProcessor( |
| 150 this.wrapper, |
| 151 this.processor, |
| 152 this.codePositions, |
| 153 this.nodeToSourceLocationsMap); |
| 154 |
| 155 @override |
| 156 void onPositions(js.Node node, |
| 157 int startPosition, |
| 158 int endPosition, |
| 159 int closingPosition) { |
| 160 codePositions.registerPositions( |
| 161 node, startPosition, endPosition, closingPosition); |
| 162 processor.onPositions(node, startPosition, endPosition, closingPosition); |
| 163 } |
| 164 |
| 165 @override |
| 166 void process(js.Node node, BufferedCodeOutput code) { |
| 167 processor.process(node, code); |
| 168 wrapper.registerProcess( |
| 169 node, code, codePositions, nodeToSourceLocationsMap); |
| 170 } |
| 171 } |
| 172 |
| 173 /// Information recording for a use of [SourceInformationProcessor]. |
| 174 class RecordedSourceInformationProcess { |
| 175 final js.Node root; |
| 176 final String code; |
| 177 final CodePositionRecorder codePositions; |
| 178 final LocationMap nodeToSourceLocationsMap; |
| 179 |
| 180 RecordedSourceInformationProcess( |
| 181 this.root, |
| 182 this.code, |
| 183 this.codePositions, |
| 184 this.nodeToSourceLocationsMap); |
| 185 } |
| 186 |
| 187 |
| 188 /// A wrapper of [JavaScriptSourceInformationStrategy] that records |
| 189 /// [RecordedSourceInformationProcess]. |
| 190 class RecordingSourceInformationStrategy |
| 191 extends JavaScriptSourceInformationStrategy { |
| 192 final JavaScriptSourceInformationStrategy strategy; |
| 193 final Map<RecordedSourceInformationProcess, js.Node> processMap = |
| 194 <RecordedSourceInformationProcess, js.Node>{}; |
| 195 final Map<js.Node, RecordedSourceInformationProcess> nodeMap = |
| 196 <js.Node, RecordedSourceInformationProcess>{}; |
| 197 |
| 198 RecordingSourceInformationStrategy(this.strategy); |
| 199 |
| 200 @override |
| 201 SourceInformationBuilder createBuilderForContext(AstElement element) { |
| 202 return strategy.createBuilderForContext(element); |
| 203 } |
| 204 |
| 205 @override |
| 206 SourceInformationProcessor createProcessor(SourceMapper sourceMapper) { |
| 207 LocationMap nodeToSourceLocationsMap = |
| 208 new _LocationRecorder(); |
| 209 CodePositionRecorder codePositions = new CodePositionRecorder(); |
| 210 return new RecordingSourceInformationProcessor( |
| 211 this, |
| 212 strategy.createProcessor(new RecordingSourceMapper( |
| 213 sourceMapper, nodeToSourceLocationsMap)), |
| 214 codePositions, nodeToSourceLocationsMap); |
| 215 } |
| 216 |
| 217 void registerProcess(js.Node root, |
| 218 BufferedCodeOutput code, |
| 219 CodePositionRecorder codePositions, |
| 220 LocationMap nodeToSourceLocationsMap) { |
| 221 RecordedSourceInformationProcess subProcess = |
| 222 new RecordedSourceInformationProcess( |
| 223 root, code.getText(), codePositions, nodeToSourceLocationsMap); |
| 224 processMap[subProcess] = root; |
| 225 } |
| 226 |
| 227 RecordedSourceInformationProcess subProcessForNode(js.Node node) { |
| 228 return nodeMap.putIfAbsent(node, () { |
| 229 for (RecordedSourceInformationProcess subProcess in processMap.keys) { |
| 230 js.Node root = processMap[subProcess]; |
| 231 FindVisitor visitor = new FindVisitor(node); |
| 232 root.accept(visitor); |
| 233 if (visitor.found) { |
| 234 return new RecordedSourceInformationProcess( |
| 235 node, |
| 236 subProcess.code, |
| 237 subProcess.codePositions, |
| 238 new _FilteredLocationMap( |
| 239 visitor.nodes, subProcess.nodeToSourceLocationsMap)); |
| 240 } |
| 241 return null; |
| 242 } |
| 243 }); |
| 244 } |
| 245 } |
| 246 |
| 247 /// Visitor that collects all nodes that are within a function. Used by the |
| 248 /// [RecordingSourceInformationStrategy] to filter what is recorded in a |
| 249 /// [RecordedSourceInformationProcess]. |
| 250 class FindVisitor extends js.BaseVisitor { |
| 251 final js.Node soughtNode; |
| 252 bool found = false; |
| 253 bool add = false; |
| 254 final Set<js.Node> nodes = new Set<js.Node>(); |
| 255 |
| 256 FindVisitor(this.soughtNode); |
| 257 |
| 258 visitNode(js.Node node) { |
| 259 if (node == soughtNode) { |
| 260 found = true; |
| 261 add = true; |
| 262 } |
| 263 if (add) { |
| 264 nodes.add(node); |
| 265 } |
| 266 node.visitChildren(this); |
| 267 if (node == soughtNode) { |
| 268 add = false; |
| 269 } |
| 270 } |
| 271 } |
| 272 |
| 273 const String USE_NEW_SOURCE_INFO = '--use-new-source-info'; |
| 274 const String DISABLE_INLINING = '--disable-inlining'; |
| 275 |
83 /// Processor that computes [SourceMapInfo] for the JavaScript compiled for a | 276 /// Processor that computes [SourceMapInfo] for the JavaScript compiled for a |
84 /// given Dart file. | 277 /// given Dart file. |
85 class SourceMapProcessor { | 278 class SourceMapProcessor { |
86 /// If `true` the output from the compilation is written to files. | 279 /// If `true` the output from the compilation is written to files. |
87 final bool outputToFile; | 280 final bool outputToFile; |
88 | 281 |
89 /// The [Uri] of the Dart entrypoint. | 282 /// The [Uri] of the Dart entrypoint. |
90 Uri inputUri; | 283 Uri inputUri; |
91 | 284 |
92 /// The name of the JavaScript output file. | 285 /// The name of the JavaScript output file. |
(...skipping 12 matching lines...) Expand all Loading... |
105 SourceMapProcessor(String filename, {this.outputToFile: false}) { | 298 SourceMapProcessor(String filename, {this.outputToFile: false}) { |
106 inputUri = Uri.base.resolve(nativeToUriPath(filename)); | 299 inputUri = Uri.base.resolve(nativeToUriPath(filename)); |
107 jsPath = 'out.js'; | 300 jsPath = 'out.js'; |
108 targetUri = Uri.base.resolve(jsPath); | 301 targetUri = Uri.base.resolve(jsPath); |
109 sourceMapFileUri = Uri.base.resolve('${jsPath}.map'); | 302 sourceMapFileUri = Uri.base.resolve('${jsPath}.map'); |
110 } | 303 } |
111 | 304 |
112 /// Computes the [SourceMapInfo] for the compiled elements. | 305 /// Computes the [SourceMapInfo] for the compiled elements. |
113 Future<List<SourceMapInfo>> process( | 306 Future<List<SourceMapInfo>> process( |
114 List<String> options, | 307 List<String> options, |
115 {bool verbose: true}) async { | 308 {bool verbose: true, |
| 309 bool perElement: true}) async { |
116 OutputProvider outputProvider = outputToFile | 310 OutputProvider outputProvider = outputToFile |
117 ? new OutputProvider() | 311 ? new CloningOutputProvider(targetUri, sourceMapFileUri) |
118 : new CloningOutputProvider(targetUri, sourceMapFileUri); | 312 : new OutputProvider(); |
119 if (options.contains('--use-new-source-info')) { | 313 if (options.contains(USE_NEW_SOURCE_INFO)) { |
120 if (verbose) print('Using the new source information system.'); | 314 if (verbose) print('Using the new source information system.'); |
121 useNewSourceInfo = true; | 315 useNewSourceInfo = true; |
122 } | 316 } |
123 api.CompilerImpl compiler = await compilerFor( | 317 api.CompilerImpl compiler = await compilerFor( |
124 outputProvider: outputProvider, | 318 outputProvider: outputProvider, |
125 // TODO(johnniwinther): Use [verbose] to avoid showing diagnostics. | 319 // TODO(johnniwinther): Use [verbose] to avoid showing diagnostics. |
126 options: ['--out=$targetUri', '--source-map=$sourceMapFileUri'] | 320 options: ['--out=$targetUri', '--source-map=$sourceMapFileUri'] |
127 ..addAll(options)); | 321 ..addAll(options)); |
128 if (options.contains('--disable-inlining')) { | 322 if (options.contains(DISABLE_INLINING)) { |
129 if (verbose) print('Inlining disabled'); | 323 if (verbose) print('Inlining disabled'); |
130 compiler.disableInlining = true; | 324 compiler.disableInlining = true; |
131 } | 325 } |
132 | 326 |
133 JavaScriptBackend backend = compiler.backend; | 327 JavaScriptBackend backend = compiler.backend; |
134 var handler = compiler.handler; | 328 var handler = compiler.handler; |
135 SourceFileProvider sourceFileProvider = handler.provider; | 329 SourceFileProvider sourceFileProvider = handler.provider; |
136 sourceFileManager = new ProviderSourceFileManager(sourceFileProvider); | 330 sourceFileManager = new ProviderSourceFileManager( |
| 331 sourceFileProvider, |
| 332 outputProvider); |
| 333 RecordingSourceInformationStrategy strategy = |
| 334 new RecordingSourceInformationStrategy(backend.sourceInformationStrategy
); |
| 335 backend.sourceInformationStrategy = strategy; |
137 await compiler.run(inputUri); | 336 await compiler.run(inputUri); |
138 | 337 |
139 List<SourceMapInfo> infoList = <SourceMapInfo>[]; | 338 List<SourceMapInfo> infoList = <SourceMapInfo>[]; |
140 backend.generatedCode.forEach((Element element, js.Expression node) { | 339 if (perElement) { |
141 js.JavaScriptPrintingOptions options = | 340 backend.generatedCode.forEach((Element element, js.Expression node) { |
142 new js.JavaScriptPrintingOptions(); | 341 RecordedSourceInformationProcess subProcess = |
143 JavaScriptSourceInformationStrategy sourceInformationStrategy = | 342 strategy.subProcessForNode(node); |
144 compiler.backend.sourceInformationStrategy; | 343 if (subProcess == null) { |
145 NodeToSourceLocationsMap nodeMap = new NodeToSourceLocationsMap(); | 344 // TODO(johnniwinther): Find out when this is happening and if it |
146 SourceInformationProcessor sourceInformationProcessor = | 345 // is benign. (Known to happen for `bool#fromString`) |
147 sourceInformationStrategy.createProcessor(nodeMap); | 346 print('No subProcess found for $element'); |
148 RecordingPrintingContext printingContext = | 347 return; |
149 new RecordingPrintingContext(sourceInformationProcessor); | 348 } |
150 new js.Printer(options, printingContext).visit(node); | 349 LocationMap nodeMap = subProcess.nodeToSourceLocationsMap; |
151 sourceInformationProcessor.process(node); | 350 String code = subProcess.code; |
152 | 351 CodePositionRecorder codePositions = subProcess.codePositions; |
153 String code = printingContext.getText(); | 352 CodePointComputer visitor = |
| 353 new CodePointComputer(sourceFileManager, code, nodeMap); |
| 354 visitor.apply(node); |
| 355 List<CodePoint> codePoints = visitor.codePoints; |
| 356 infoList.add(new SourceMapInfo( |
| 357 element, code, node, |
| 358 codePoints, |
| 359 codePositions/*strategy.codePositions*/, |
| 360 nodeMap)); |
| 361 }); |
| 362 } else { |
| 363 // TODO(johnniwinther): Supported multiple output units. |
| 364 RecordedSourceInformationProcess process = strategy.processMap.keys.first; |
| 365 js.Node node = strategy.processMap[process]; |
| 366 String code; |
| 367 LocationMap nodeMap; |
| 368 CodePositionRecorder codePositions; |
| 369 nodeMap = process.nodeToSourceLocationsMap; |
| 370 code = process.code; |
| 371 codePositions = process.codePositions; |
154 CodePointComputer visitor = | 372 CodePointComputer visitor = |
155 new CodePointComputer(sourceFileManager, code, nodeMap); | 373 new CodePointComputer(sourceFileManager, code, nodeMap); |
156 visitor.apply(node); | 374 visitor.apply(node); |
157 List<CodePoint> codePoints = visitor.codePoints; | 375 List<CodePoint> codePoints = visitor.codePoints; |
158 infoList.add(new SourceMapInfo(element, code, node, codePoints, nodeMap)); | 376 infoList.add(new SourceMapInfo( |
159 }); | 377 null, code, node, |
| 378 codePoints, |
| 379 codePositions, |
| 380 nodeMap)); |
| 381 } |
160 | 382 |
161 return infoList; | 383 return infoList; |
162 } | 384 } |
163 } | 385 } |
164 | 386 |
165 /// Source mapping information for the JavaScript code of an [Element]. | 387 /// Source mapping information for the JavaScript code of an [Element]. |
166 class SourceMapInfo { | 388 class SourceMapInfo { |
167 final String name; | 389 final String name; |
168 final Element element; | 390 final Element element; |
169 final String code; | 391 final String code; |
170 final js.Expression node; | 392 final js.Node node; |
171 final List<CodePoint> codePoints; | 393 final List<CodePoint> codePoints; |
172 final NodeToSourceLocationsMap nodeMap; | 394 final CodePositionMap jsCodePositions; |
| 395 final LocationMap nodeMap; |
173 | 396 |
174 SourceMapInfo( | 397 SourceMapInfo( |
175 Element element, this.code, this.node, this.codePoints, this.nodeMap) | 398 Element element, |
176 : this.name = computeElementNameForSourceMaps(element), | 399 this.code, |
| 400 this.node, |
| 401 this.codePoints, |
| 402 this.jsCodePositions, |
| 403 this.nodeMap) |
| 404 : this.name = |
| 405 element != null ? computeElementNameForSourceMaps(element) : '', |
177 this.element = element; | 406 this.element = element; |
| 407 |
| 408 String toString() { |
| 409 return '$name:$element'; |
| 410 } |
178 } | 411 } |
179 | 412 |
180 /// Collection of JavaScript nodes with their source mapped target offsets | 413 /// Collection of JavaScript nodes with their source mapped target offsets |
181 /// and source locations. | 414 /// and source locations. |
182 class NodeToSourceLocationsMap implements SourceMapper { | 415 abstract class LocationMap { |
| 416 Iterable<js.Node> get nodes; |
| 417 |
| 418 Map<int, List<SourceLocation>> operator[] (js.Node node); |
| 419 |
| 420 factory LocationMap.recorder() = _LocationRecorder; |
| 421 |
| 422 factory LocationMap.filter(Set<js.Node> nodes, LocationMap map) = |
| 423 _FilteredLocationMap; |
| 424 |
| 425 } |
| 426 |
| 427 class _LocationRecorder |
| 428 implements SourceMapper, LocationMap { |
183 final Map<js.Node, Map<int, List<SourceLocation>>> _nodeMap = {}; | 429 final Map<js.Node, Map<int, List<SourceLocation>>> _nodeMap = {}; |
184 | 430 |
185 @override | 431 @override |
186 void register(js.Node node, int codeOffset, SourceLocation sourceLocation) { | 432 void register(js.Node node, int codeOffset, SourceLocation sourceLocation) { |
187 _nodeMap.putIfAbsent(node, () => {}) | 433 _nodeMap.putIfAbsent(node, () => {}) |
188 .putIfAbsent(codeOffset, () => []) | 434 .putIfAbsent(codeOffset, () => []) |
189 .add(sourceLocation); | 435 .add(sourceLocation); |
190 } | 436 } |
191 | 437 |
192 Iterable<js.Node> get nodes => _nodeMap.keys; | 438 Iterable<js.Node> get nodes => _nodeMap.keys; |
193 | 439 |
194 Map<int, List<SourceLocation>> operator[] (js.Node node) { | 440 Map<int, List<SourceLocation>> operator[] (js.Node node) { |
195 return _nodeMap[node]; | 441 return _nodeMap[node]; |
196 } | 442 } |
197 } | 443 } |
198 | 444 |
| 445 class _FilteredLocationMap implements LocationMap { |
| 446 final Set<js.Node> _nodes; |
| 447 final LocationMap map; |
| 448 |
| 449 _FilteredLocationMap(this._nodes, this.map); |
| 450 |
| 451 Iterable<js.Node> get nodes => map.nodes.where((n) => _nodes.contains(n)); |
| 452 |
| 453 Map<int, List<SourceLocation>> operator[] (js.Node node) { |
| 454 return map[node]; |
| 455 } |
| 456 } |
| 457 |
| 458 |
199 /// Visitor that computes the [CodePoint]s for source mapping locations. | 459 /// Visitor that computes the [CodePoint]s for source mapping locations. |
200 class CodePointComputer extends js.BaseVisitor { | 460 class CodePointComputer extends js.BaseVisitor { |
201 final SourceFileManager sourceFileManager; | 461 final SourceFileManager sourceFileManager; |
202 final String code; | 462 final String code; |
203 final NodeToSourceLocationsMap nodeMap; | 463 final LocationMap nodeMap; |
204 List<CodePoint> codePoints = []; | 464 List<CodePoint> codePoints = []; |
205 | 465 |
206 CodePointComputer(this.sourceFileManager, this.code, this.nodeMap); | 466 CodePointComputer(this.sourceFileManager, this.code, this.nodeMap); |
207 | 467 |
208 String nodeToString(js.Node node) { | 468 String nodeToString(js.Node node) { |
209 js.JavaScriptPrintingOptions options = new js.JavaScriptPrintingOptions( | 469 js.JavaScriptPrintingOptions options = new js.JavaScriptPrintingOptions( |
210 shouldCompressOutput: true, | 470 shouldCompressOutput: true, |
211 preferSemicolonToNewlineInMinifiedOutput: true); | 471 preferSemicolonToNewlineInMinifiedOutput: true); |
212 LenientPrintingContext printingContext = new LenientPrintingContext(); | 472 LenientPrintingContext printingContext = new LenientPrintingContext(); |
213 new js.Printer(options, printingContext).visit(node); | 473 new js.Printer(options, printingContext).visit(node); |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
329 this.jsCode, | 589 this.jsCode, |
330 this.sourceLocation, | 590 this.sourceLocation, |
331 this.dartCode, | 591 this.dartCode, |
332 {this.isMissing: false}); | 592 {this.isMissing: false}); |
333 | 593 |
334 String toString() { | 594 String toString() { |
335 return 'CodePoint[kind=$kind,js=$jsCode,dart=$dartCode,' | 595 return 'CodePoint[kind=$kind,js=$jsCode,dart=$dartCode,' |
336 'location=$sourceLocation]'; | 596 'location=$sourceLocation]'; |
337 } | 597 } |
338 } | 598 } |
OLD | NEW |