| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 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 | 
|  | 3 // BSD-style license that can be found in the LICENSE file. | 
|  | 4 | 
|  | 5 /// Contains a code printer that generates code by recording the source maps. | 
|  | 6 library source_maps.printer; | 
|  | 7 | 
|  | 8 import 'package:source_span/source_span.dart'; | 
|  | 9 | 
|  | 10 import 'builder.dart'; | 
|  | 11 import 'src/source_map_span.dart'; | 
|  | 12 | 
|  | 13 const int _LF = 10; | 
|  | 14 const int _CR = 13; | 
|  | 15 | 
|  | 16 /// A simple printer that keeps track of offset locations and records source | 
|  | 17 /// maps locations. | 
|  | 18 class Printer { | 
|  | 19   final String filename; | 
|  | 20   final StringBuffer _buff = new StringBuffer(); | 
|  | 21   final SourceMapBuilder _maps = new SourceMapBuilder(); | 
|  | 22   String get text => _buff.toString(); | 
|  | 23   String get map => _maps.toJson(filename); | 
|  | 24 | 
|  | 25   /// Current source location mapping. | 
|  | 26   SourceLocation _loc; | 
|  | 27 | 
|  | 28   /// Current line in the buffer; | 
|  | 29   int _line = 0; | 
|  | 30 | 
|  | 31   /// Current column in the buffer. | 
|  | 32   int _column = 0; | 
|  | 33 | 
|  | 34   Printer(this.filename); | 
|  | 35 | 
|  | 36   /// Add [str] contents to the output, tracking new lines to track correct | 
|  | 37   /// positions for span locations. When [projectMarks] is true, this method | 
|  | 38   /// adds a source map location on each new line, projecting that every new | 
|  | 39   /// line in the target file (printed here) corresponds to a new line in the | 
|  | 40   /// source file. | 
|  | 41   void add(String str, {projectMarks: false}) { | 
|  | 42     var chars = str.runes.toList(); | 
|  | 43     var length = chars.length; | 
|  | 44     for (int i = 0; i < length; i++) { | 
|  | 45       var c = chars[i]; | 
|  | 46       if (c == _LF || (c == _CR && (i + 1 == length || chars[i + 1] != _LF))) { | 
|  | 47         // Return not followed by line-feed is treated as a new line. | 
|  | 48         _line++; | 
|  | 49         _column = 0; | 
|  | 50         if (projectMarks && _loc != null) { | 
|  | 51           if (_loc is FileLocation) { | 
|  | 52             var file = (_loc as FileLocation).file; | 
|  | 53             mark(file.location(file.getOffset(_loc.line + 1))); | 
|  | 54           } else { | 
|  | 55             mark(new SourceLocation(0, | 
|  | 56                 sourceUrl: _loc.sourceUrl, line: _loc.line + 1, column: 0)); | 
|  | 57           } | 
|  | 58         } | 
|  | 59       } else { | 
|  | 60         _column++; | 
|  | 61       } | 
|  | 62     } | 
|  | 63     _buff.write(str); | 
|  | 64   } | 
|  | 65 | 
|  | 66 | 
|  | 67   /// Append a [total] number of spaces in the target file. Typically used for | 
|  | 68   /// formatting indentation. | 
|  | 69   void addSpaces(int total) { | 
|  | 70     for (int i = 0; i < total; i++) _buff.write(' '); | 
|  | 71     _column += total; | 
|  | 72   } | 
|  | 73 | 
|  | 74   /// Marks that the current point in the target file corresponds to the [mark] | 
|  | 75   /// in the source file, which can be either a [SourceLocation] or a | 
|  | 76   /// [SourceSpan]. When the mark is a [SourceMapSpan] with `isIdentifier` set, | 
|  | 77   /// this also records the name of the identifier in the source map | 
|  | 78   /// information. | 
|  | 79   void mark(mark) { | 
|  | 80     var loc; | 
|  | 81     var identifier = null; | 
|  | 82     if (mark is SourceLocation) { | 
|  | 83       loc = mark; | 
|  | 84     } else if (mark is SourceSpan) { | 
|  | 85       loc = mark.start; | 
|  | 86       if (mark is SourceMapSpan && mark.isIdentifier) identifier = mark.text; | 
|  | 87     } | 
|  | 88     _maps.addLocation( | 
|  | 89         loc, | 
|  | 90         new SourceLocation(_buff.length, line: _line, column: _column), | 
|  | 91         identifier); | 
|  | 92     _loc = loc; | 
|  | 93   } | 
|  | 94 } | 
|  | 95 | 
|  | 96 /// A more advanced printer that keeps track of offset locations to record | 
|  | 97 /// source maps, but additionally allows nesting of different kind of items, | 
|  | 98 /// including [NestedPrinter]s, and it let's you automatically indent text. | 
|  | 99 /// | 
|  | 100 /// This class is especially useful when doing code generation, where different | 
|  | 101 /// peices of the code are generated independently on separate printers, and are | 
|  | 102 /// finally put together in the end. | 
|  | 103 class NestedPrinter implements NestedItem { | 
|  | 104 | 
|  | 105   /// Items recoded by this printer, which can be [String] literals, | 
|  | 106   /// [NestedItem]s, and source map information like [SourceLocation] and | 
|  | 107   /// [SourceSpan]. | 
|  | 108   List _items = []; | 
|  | 109 | 
|  | 110   /// Internal buffer to merge consecutive strings added to this printer. | 
|  | 111   StringBuffer _buff; | 
|  | 112 | 
|  | 113   /// Current indentation, which can be updated from outside this class. | 
|  | 114   int indent; | 
|  | 115 | 
|  | 116   /// Item used to indicate that the following item is copied from the original | 
|  | 117   /// source code, and hence we should preserve source-maps on every new line. | 
|  | 118   static final _ORIGINAL = new Object(); | 
|  | 119 | 
|  | 120   NestedPrinter([this.indent = 0]); | 
|  | 121 | 
|  | 122   /// Adds [object] to this printer. [object] can be a [String], | 
|  | 123   /// [NestedPrinter], or anything implementing [NestedItem]. If [object] is a | 
|  | 124   /// [String], the value is appended directly, without doing any formatting | 
|  | 125   /// changes. If you wish to add a line of code with automatic indentation, use | 
|  | 126   /// [addLine] instead.  [NestedPrinter]s and [NestedItem]s are not processed | 
|  | 127   /// until [build] gets called later on. We ensure that [build] emits every | 
|  | 128   /// object in the order that they were added to this printer. | 
|  | 129   /// | 
|  | 130   /// The [location] and [span] parameters indicate the corresponding source map | 
|  | 131   /// location of [object] in the original input. Only one, [location] or | 
|  | 132   /// [span], should be provided at a time. | 
|  | 133   /// | 
|  | 134   /// Indicate [isOriginal] when [object] is copied directly from the user code. | 
|  | 135   /// Setting [isOriginal] will make this printer propagate source map locations | 
|  | 136   /// on every line-break. | 
|  | 137   void add(object, {SourceLocation location, SourceSpan span, | 
|  | 138       bool isOriginal: false}) { | 
|  | 139     if (object is! String || location != null || span != null || isOriginal) { | 
|  | 140       _flush(); | 
|  | 141       assert(location == null || span == null); | 
|  | 142       if (location != null) _items.add(location); | 
|  | 143       if (span != null) _items.add(span); | 
|  | 144       if (isOriginal) _items.add(_ORIGINAL); | 
|  | 145     } | 
|  | 146 | 
|  | 147     if (object is String) { | 
|  | 148       _appendString(object); | 
|  | 149     } else { | 
|  | 150       _items.add(object); | 
|  | 151     } | 
|  | 152   } | 
|  | 153 | 
|  | 154   /// Append `2 * indent` spaces to this printer. | 
|  | 155   void insertIndent() => _indent(indent); | 
|  | 156 | 
|  | 157   /// Add a [line], autoindenting to the current value of [indent]. Note, | 
|  | 158   /// indentation is not inferred from the contents added to this printer. If a | 
|  | 159   /// line starts or ends an indentation block, you need to also update [indent] | 
|  | 160   /// accordingly. Also, indentation is not adapted for nested printers. If | 
|  | 161   /// you add a [NestedPrinter] to this printer, its indentation is set | 
|  | 162   /// separately and will not include any the indentation set here. | 
|  | 163   /// | 
|  | 164   /// The [location] and [span] parameters indicate the corresponding source map | 
|  | 165   /// location of [object] in the original input. Only one, [location] or | 
|  | 166   /// [span], should be provided at a time. | 
|  | 167   void addLine(String line, {SourceLocation location, SourceSpan span}) { | 
|  | 168     if (location != null || span != null) { | 
|  | 169       _flush(); | 
|  | 170       assert(location == null || span == null); | 
|  | 171       if (location != null) _items.add(location); | 
|  | 172       if (span != null) _items.add(span); | 
|  | 173     } | 
|  | 174     if (line == null) return; | 
|  | 175     if (line != '') { | 
|  | 176       // We don't indent empty lines. | 
|  | 177       _indent(indent); | 
|  | 178       _appendString(line); | 
|  | 179     } | 
|  | 180     _appendString('\n'); | 
|  | 181   } | 
|  | 182 | 
|  | 183   /// Appends a string merging it with any previous strings, if possible. | 
|  | 184   void _appendString(String s) { | 
|  | 185     if (_buff == null) _buff = new StringBuffer(); | 
|  | 186     _buff.write(s); | 
|  | 187   } | 
|  | 188 | 
|  | 189   /// Adds all of the current [_buff] contents as a string item. | 
|  | 190   void _flush() { | 
|  | 191     if (_buff != null) { | 
|  | 192       _items.add(_buff.toString()); | 
|  | 193       _buff = null; | 
|  | 194     } | 
|  | 195   } | 
|  | 196 | 
|  | 197   void _indent(int indent) { | 
|  | 198     for (int i = 0; i < indent; i++) _appendString('  '); | 
|  | 199   } | 
|  | 200 | 
|  | 201   /// Returns a string representation of all the contents appended to this | 
|  | 202   /// printer, including source map location tokens. | 
|  | 203   String toString() { | 
|  | 204     _flush(); | 
|  | 205     return (new StringBuffer()..writeAll(_items)).toString(); | 
|  | 206   } | 
|  | 207 | 
|  | 208   /// [Printer] used during the last call to [build], if any. | 
|  | 209   Printer printer; | 
|  | 210 | 
|  | 211   /// Returns the text produced after calling [build]. | 
|  | 212   String get text => printer.text; | 
|  | 213 | 
|  | 214   /// Returns the source-map information produced after calling [build]. | 
|  | 215   String get map => printer.map; | 
|  | 216 | 
|  | 217   /// Builds the output of this printer and source map information. After | 
|  | 218   /// calling this function, you can use [text] and [map] to retrieve the | 
|  | 219   /// geenrated code and source map information, respectively. | 
|  | 220   void build(String filename) { | 
|  | 221     writeTo(printer = new Printer(filename)); | 
|  | 222   } | 
|  | 223 | 
|  | 224   /// Implements the [NestedItem] interface. | 
|  | 225   void writeTo(Printer printer) { | 
|  | 226     _flush(); | 
|  | 227     bool propagate = false; | 
|  | 228     for (var item in _items) { | 
|  | 229       if (item is NestedItem) { | 
|  | 230         item.writeTo(printer); | 
|  | 231       } else if (item is String) { | 
|  | 232         printer.add(item, projectMarks: propagate); | 
|  | 233         propagate = false; | 
|  | 234       } else if (item is SourceLocation || item is SourceSpan) { | 
|  | 235         printer.mark(item); | 
|  | 236       } else if (item == _ORIGINAL) { | 
|  | 237         // we insert booleans when we are about to quote text that was copied | 
|  | 238         // from the original source. In such case, we will propagate marks on | 
|  | 239         // every new-line. | 
|  | 240         propagate = true; | 
|  | 241       } else { | 
|  | 242         throw new UnsupportedError('Unknown item type: $item'); | 
|  | 243       } | 
|  | 244     } | 
|  | 245   } | 
|  | 246 } | 
|  | 247 | 
|  | 248 /// An item added to a [NestedPrinter]. | 
|  | 249 abstract class NestedItem { | 
|  | 250   /// Write the contents of this item into [printer]. | 
|  | 251   void writeTo(Printer printer); | 
|  | 252 } | 
| OLD | NEW | 
|---|