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 |