| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 dart2js.code_output; | 5 library dart2js.code_output; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'source_information.dart'; | 9 import 'source_information.dart'; |
| 10 | 10 |
| 11 class CodeOutputMarker { | |
| 12 final int offsetDelta; | |
| 13 final SourceLocation sourcePosition; | |
| 14 | |
| 15 CodeOutputMarker(this.offsetDelta, this.sourcePosition); | |
| 16 } | |
| 17 | |
| 18 abstract class CodeOutputListener { | 11 abstract class CodeOutputListener { |
| 19 void onText(String text); | 12 void onText(String text); |
| 20 void onDone(int length); | 13 void onDone(int length); |
| 21 } | 14 } |
| 22 | 15 |
| 23 abstract class CodeOutput { | 16 abstract class CodeOutput { |
| 24 /// Write [text] to this output. | 17 /// Write [text] to this output. |
| 25 /// | 18 /// |
| 26 /// If the output is closed, a [StateError] is thrown. | 19 /// If the output is closed, a [StateError] is thrown. |
| 27 void add(String text); | 20 void add(String text); |
| 28 | 21 |
| 29 /// Adds the content of [buffer] to the output and adds its markers to | 22 /// Adds the content of [buffer] to the output and adds its markers to |
| 30 /// [markers]. | 23 /// [markers]. |
| 31 /// | 24 /// |
| 32 /// If the output is closed, a [StateError] is thrown. | 25 /// If the output is closed, a [StateError] is thrown. |
| 33 void addBuffer(CodeBuffer buffer); | 26 void addBuffer(CodeBuffer buffer); |
| 34 | 27 |
| 35 /// Returns the number of characters currently write to this output. | 28 /// Returns the number of characters currently write to this output. |
| 36 int get length; | 29 int get length; |
| 37 | 30 |
| 38 /// Returns `true` if this output has been closed. | 31 /// Returns `true` if this output has been closed. |
| 39 bool get isClosed; | 32 bool get isClosed; |
| 40 | 33 |
| 41 /// Closes the output. Further writes will cause a [StateError]. | 34 /// Closes the output. Further writes will cause a [StateError]. |
| 42 void close(); | 35 void close(); |
| 43 | 36 |
| 44 /// Sets the [sourcePosition] for the code next added to this output. | 37 /// Adds a [sourceLocation] at the specified [targetOffset] in the buffer. |
| 45 void setSourceLocation(SourceLocation sourcePosition); | 38 void addSourceLocation(int targetOffset, SourceLocation sourcePosition); |
| 46 | 39 |
| 47 /// Applies [f] to every marker in this output. | 40 /// Applies [f] to every marker in this output. |
| 48 void forEachSourceLocation(void f(int targetOffset, | 41 void forEachSourceLocation(void f(int targetOffset, |
| 49 SourceLocation sourceLocation)); | 42 SourceLocation sourceLocation)); |
| 50 } | 43 } |
| 51 | 44 |
| 52 abstract class AbstractCodeOutput extends CodeOutput { | 45 abstract class AbstractCodeOutput extends CodeOutput { |
| 53 List<CodeOutputMarker> markers = new List<CodeOutputMarker>(); | 46 Map<int, List<SourceLocation>> markers = <int, List<SourceLocation>>{}; |
| 54 int lastBufferOffset = 0; | |
| 55 int mappedRangeCounter = 0; | |
| 56 bool isClosed = false; | 47 bool isClosed = false; |
| 57 | 48 |
| 58 void _addInternal(String text); | 49 void _addInternal(String text); |
| 59 | 50 |
| 60 @override | 51 @override |
| 61 void add(String text) { | 52 void add(String text) { |
| 62 if (isClosed) { | 53 if (isClosed) { |
| 63 throw new StateError("Code output is closed. Trying to write '$text'."); | 54 throw new StateError("Code output is closed. Trying to write '$text'."); |
| 64 } | 55 } |
| 65 if (mappedRangeCounter == 0) setSourceLocation(null); | |
| 66 _addInternal(text); | 56 _addInternal(text); |
| 67 } | 57 } |
| 68 | 58 |
| 69 @override | 59 @override |
| 70 void addBuffer(CodeBuffer other) { | 60 void addBuffer(CodeBuffer other) { |
| 71 if (other.markers.length > 0) { | 61 if (other.markers.length > 0) { |
| 72 CodeOutputMarker firstMarker = other.markers[0]; | 62 other.markers.forEach( |
| 73 int offsetDelta = | 63 (int targetOffset, List<SourceLocation> sourceLocations) { |
| 74 length + firstMarker.offsetDelta - lastBufferOffset; | 64 markers.putIfAbsent(length + targetOffset, () => <SourceLocation>[]) |
| 75 markers.add(new CodeOutputMarker(offsetDelta, | 65 .addAll(sourceLocations); |
| 76 firstMarker.sourcePosition)); | 66 }); |
| 77 for (int i = 1; i < other.markers.length; ++i) { | |
| 78 markers.add(other.markers[i]); | |
| 79 } | |
| 80 lastBufferOffset = length + other.lastBufferOffset; | |
| 81 } | 67 } |
| 82 if (!other.isClosed) { | 68 if (!other.isClosed) { |
| 83 other.close(); | 69 other.close(); |
| 84 } | 70 } |
| 85 _addInternal(other.getText()); | 71 _addInternal(other.getText()); |
| 86 } | 72 } |
| 87 | 73 |
| 88 void beginMappedRange() { | 74 void addSourceLocation(int targetOffset, |
| 89 ++mappedRangeCounter; | 75 SourceLocation sourceLocation) { |
| 76 assert(targetOffset <= length); |
| 77 List<SourceLocation> sourceLocations = |
| 78 markers.putIfAbsent(targetOffset, () => <SourceLocation>[]); |
| 79 sourceLocations.add(sourceLocation); |
| 90 } | 80 } |
| 91 | 81 |
| 92 void endMappedRange() { | 82 void forEachSourceLocation(void f(int targetOffset, var sourceLocation)) { |
| 93 assert(mappedRangeCounter > 0); | 83 markers.forEach((int targetOffset, List<SourceLocation> sourceLocations) { |
| 94 --mappedRangeCounter; | 84 for (SourceLocation sourceLocation in sourceLocations) { |
| 95 } | 85 f(targetOffset, sourceLocation); |
| 96 | 86 } |
| 97 void setSourceLocation(SourceLocation sourcePosition) { | |
| 98 if (sourcePosition == null) { | |
| 99 if (markers.length > 0 && markers.last.sourcePosition == null) return; | |
| 100 } | |
| 101 int offsetDelta = length - lastBufferOffset; | |
| 102 markers.add(new CodeOutputMarker(offsetDelta, sourcePosition)); | |
| 103 lastBufferOffset = length; | |
| 104 } | |
| 105 | |
| 106 void forEachSourceLocation(void f(int targetOffset, var sourcePosition)) { | |
| 107 int targetOffset = 0; | |
| 108 markers.forEach((marker) { | |
| 109 targetOffset += marker.offsetDelta; | |
| 110 f(targetOffset, marker.sourcePosition); | |
| 111 }); | 87 }); |
| 112 } | 88 } |
| 113 | 89 |
| 114 void close() { | 90 void close() { |
| 115 if (isClosed) { | 91 if (isClosed) { |
| 116 throw new StateError("Code output is already closed."); | 92 throw new StateError("Code output is already closed."); |
| 117 } | 93 } |
| 118 isClosed = true; | 94 isClosed = true; |
| 119 } | 95 } |
| 120 } | 96 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 158 } | 134 } |
| 159 | 135 |
| 160 void close() { | 136 void close() { |
| 161 output.close(); | 137 output.close(); |
| 162 super.close(); | 138 super.close(); |
| 163 if (_listeners != null) { | 139 if (_listeners != null) { |
| 164 _listeners.forEach((listener) => listener.onDone(length)); | 140 _listeners.forEach((listener) => listener.onDone(length)); |
| 165 } | 141 } |
| 166 } | 142 } |
| 167 } | 143 } |
| OLD | NEW |