OLD | NEW |
---|---|
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 /// Contains a code printer that generates code by recording the source maps. | 5 /// Contains a code printer that generates code by recording the source maps. |
6 library source_maps.printer; | 6 library source_maps.printer; |
7 | 7 |
8 import 'dart:utf' show stringToCodepoints; | 8 import 'dart:utf' show stringToCodepoints; |
9 import 'builder.dart'; | 9 import 'builder.dart'; |
10 import 'span.dart'; | 10 import 'span.dart'; |
11 | 11 |
12 const int _LF = 10; | 12 const int _LF = 10; |
13 const int _CR = 13; | 13 const int _CR = 13; |
14 | 14 |
15 /// A printer that keeps track of offset locations and records source maps | 15 /// A simple printer that keeps track of offset locations and records source |
16 /// locations. | 16 /// maps locations. |
17 class Printer { | 17 class Printer { |
18 final String filename; | 18 final String filename; |
19 final StringBuffer _buff = new StringBuffer(); | 19 final StringBuffer _buff = new StringBuffer(); |
20 final SourceMapBuilder _maps = new SourceMapBuilder(); | 20 final SourceMapBuilder _maps = new SourceMapBuilder(); |
21 String get text => _buff.toString(); | 21 String get text => _buff.toString(); |
22 String get map => _maps.toJson(filename); | 22 String get map => _maps.toJson(filename); |
23 | 23 |
24 /// Current source location mapping. | 24 /// Current source location mapping. |
25 Location _loc; | 25 Location _loc; |
26 | 26 |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
80 loc = mark; | 80 loc = mark; |
81 } else if (mark is Span) { | 81 } else if (mark is Span) { |
82 loc = mark.start; | 82 loc = mark.start; |
83 if (mark.isIdentifier) identifier = mark.text; | 83 if (mark.isIdentifier) identifier = mark.text; |
84 } | 84 } |
85 _maps.addLocation(loc, | 85 _maps.addLocation(loc, |
86 new FixedLocation(_buff.length, null, _line, _column), identifier); | 86 new FixedLocation(_buff.length, null, _line, _column), identifier); |
87 _loc = loc; | 87 _loc = loc; |
88 } | 88 } |
89 } | 89 } |
90 | |
91 /// A more advanced printer that keeps track of offset locations to record | |
Siggi Cherem (dart-lang)
2013/08/09 22:09:09
this code is very similar to the original main dif
| |
92 /// source maps, but additionally allows nesting of different kind of items, | |
93 /// including [NestedPrinter]s, and it let's you automatically indent text. | |
94 /// | |
95 /// This class is especially useful when doing code generation, where different | |
96 /// peices of the code are generated independently on separate printers, and are | |
97 /// finally put together in the end. | |
98 class NestedPrinter implements NestedItem { | |
99 | |
100 /// Items recoded by this printer, which can be [String] literals, | |
101 /// [NestedItem]s, and source map information like [Location] and [Span]. | |
102 List _items = []; | |
103 | |
104 /// Internal buffer to merge consecutive strings added to this printer. | |
105 StringBuffer _buff; | |
106 | |
107 /// Current indentation, which can be updated from outside this class. | |
108 int indent; | |
109 | |
110 /// Item used to indicate that the following item is copied from the original | |
111 /// source code, and hence we should preserve source-maps on every new line. | |
112 static final _ORIGINAL = new Object(); | |
113 | |
114 NestedPrinter([this.indent = 0]); | |
115 | |
116 /// Adds [object] to this printer. [object] can be a [String], | |
117 /// [NestedPrinter], or anything implementing [NestedItem]. If [object] is a | |
118 /// [String], the value is appended directly, without doing any formatting | |
119 /// changes. If you wish to add a line of code with automatic indentation, use | |
120 /// [addLine] instead. [NestedPrinter]s and [NestedItem]s are not processed | |
121 /// until [build] gets called later on. We ensure that [build] emits every | |
122 /// object in the order that they were added to this printer. | |
123 /// | |
124 /// The [location] and [span] parameters indicate the corresponding source map | |
125 /// location of [object] in the original input. Only one, [location] or | |
126 /// [span], should be provided at a time. | |
127 /// | |
128 /// Indicate [isOriginal] when [object] is copied directly from the user code. | |
129 /// Setting [isOriginal] will make this printer propagate source map locations | |
130 /// on every line-break. | |
131 void add(object, {Location location, Span span, bool isOriginal: false}) { | |
132 if (object is! String || location != null || span != null || isOriginal) { | |
133 _flush(); | |
134 assert(location == null || span == null); | |
135 if (location != null) _items.add(location); | |
136 if (span != null) _items.add(span); | |
137 if (isOriginal) _items.add(_ORIGINAL); | |
138 } | |
139 | |
140 if (object is String) { | |
141 _appendString(object); | |
142 } else { | |
143 _items.add(object); | |
144 } | |
145 } | |
146 | |
147 /// Append `2 * indent` spaces to this printer. | |
148 void insertIndent() => _indent(indent); | |
149 | |
150 /// Add a [line], autoindenting to the current value of [indent]. Note, | |
151 /// indentation is not inferred from the contents added to this printer. If a | |
152 /// line starts or ends an indentation block, you need to also update [indent] | |
153 /// accordingly. Also, indentation is not adapted for nested printers. If | |
154 /// you add a [NestedPrinter] to this printer, its indentation is set | |
155 /// separately and will not include any the indentation set here. | |
156 /// | |
157 /// The [location] and [span] parameters indicate the corresponding source map | |
158 /// location of [object] in the original input. Only one, [location] or | |
159 /// [span], should be provided at a time. | |
160 void addLine(String line, {Location location, Span span}) { | |
161 if (location != null || span != null) { | |
162 _flush(); | |
163 assert(location == null || span == null); | |
164 if (location != null) _items.add(location); | |
165 if (span != null) _items.add(span); | |
166 } | |
167 if (line == null) return; | |
168 if (line != '') { | |
169 // We don't indent empty lines. | |
170 _indent(indent); | |
171 _appendString(line); | |
172 } | |
173 _appendString('\n'); | |
174 } | |
175 | |
176 /// Appends a string merging it with any previous strings, if possible. | |
177 void _appendString(String s) { | |
178 if (_buff == null) _buff = new StringBuffer(); | |
179 _buff.write(s); | |
180 } | |
181 | |
182 /// Adds all of the current [_buff] contents as a string item. | |
183 void _flush() { | |
184 if (_buff != null) { | |
185 _items.add(_buff.toString()); | |
186 _buff = null; | |
187 } | |
188 } | |
189 | |
190 void _indent(int indent) { | |
191 for (int i = 0; i < indent; i++) _appendString(' '); | |
192 } | |
193 | |
194 /// Returns a string representation of all the contents appended to this | |
195 /// printer, including source map location tokens. | |
196 String toString() { | |
197 _flush(); | |
198 return (new StringBuffer()..writeAll(_items)).toString(); | |
199 } | |
200 | |
201 /// [Printer] used during the last call to [build], if any. | |
202 Printer printer; | |
203 | |
204 /// Returns the text produced after calling [build]. | |
205 String get text => printer.text; | |
206 | |
207 /// Returns the source-map information produced after calling [build]. | |
208 String get map => printer.map; | |
209 | |
210 /// Builds the output of this printer and source map information. After | |
211 /// calling this function, you can use [text] and [map] to retrieve the | |
212 /// geenrated code and source map information, respectively. | |
213 void build(String filename) { | |
214 writeTo(printer = new Printer(filename)); | |
215 } | |
216 | |
217 /// Implements the [NestedItem] interface. | |
218 void writeTo(Printer printer) { | |
219 _flush(); | |
220 bool propagate = false; | |
221 for (var item in _items) { | |
222 if (item is NestedItem) { | |
223 item.writeTo(printer); | |
224 } else if (item is String) { | |
225 printer.add(item, projectMarks: propagate); | |
226 propagate = false; | |
227 } else if (item is Location || item is Span) { | |
228 printer.mark(item); | |
229 } else if (item == _ORIGINAL) { | |
230 // we insert booleans when we are about to quote text that was copied | |
231 // from the original source. In such case, we will propagate marks on | |
232 // every new-line. | |
233 propagate = true; | |
234 } else { | |
235 throw new UnsupportedError('Unknown item type: $item'); | |
236 } | |
237 } | |
238 } | |
239 } | |
240 | |
241 /// An item added to a [NestedPrinter]. | |
242 abstract class NestedItem { | |
243 /// Write the contents of this item into [printer]. | |
244 void writeTo(Printer printer); | |
245 } | |
OLD | NEW |