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