| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 // Copyright (c) 2015, 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 import 'dart:collection'; | 
|  | 6 | 
|  | 7 import 'package:analyzer/src/generated/ast.dart'; | 
|  | 8 | 
|  | 9 // ASCII character codes. | 
|  | 10 | 
|  | 11 const _zero = 0x30; | 
|  | 12 const _nine = 0x39; | 
|  | 13 const _backslash = 0x5C; | 
|  | 14 const _openCurly = 0x7B; | 
|  | 15 const _closeCurly = 0x7D; | 
|  | 16 const _capitalA = 0x41; | 
|  | 17 const _capitalZ = 0x5A; | 
|  | 18 const _a = 0x61; | 
|  | 19 const _n = 0x6E; | 
|  | 20 const _r = 0x72; | 
|  | 21 const _f = 0x66; | 
|  | 22 const _b = 0x62; | 
|  | 23 const _t = 0x74; | 
|  | 24 const _u = 0x75; | 
|  | 25 const _v = 0x76; | 
|  | 26 const _x = 0x78; | 
|  | 27 const _z = 0x7A; | 
|  | 28 const _newline = 0xA; | 
|  | 29 const _carriageReturn = 0xD; | 
|  | 30 const _formFeed = 0xC; | 
|  | 31 const _backspace = 0x8; | 
|  | 32 const _tab = 0x9; | 
|  | 33 const _verticalTab = 0xB; | 
|  | 34 | 
|  | 35 /// An iterator over the runes in the value of a [StringLiteral]. | 
|  | 36 /// | 
|  | 37 /// In addition to exposing the values of the runes themselves, this also | 
|  | 38 /// exposes the offset of the current rune in the Dart source file. | 
|  | 39 class StringLiteralIterator extends Iterator<int> { | 
|  | 40   int get current => _current; | 
|  | 41   int _current; | 
|  | 42 | 
|  | 43   /// The offset of the beginning of [current] in the Dart source file that | 
|  | 44   /// contains the string literal. | 
|  | 45   /// | 
|  | 46   /// Before iteration begins, this points to the character before the first | 
|  | 47   /// rune. | 
|  | 48   int get offset => _offset; | 
|  | 49   int _offset; | 
|  | 50 | 
|  | 51   /// The offset of the next rune. | 
|  | 52   /// | 
|  | 53   /// This isn't necessarily just `offset + 1`, since a single rune may be | 
|  | 54   /// represented by multiple characters in the source file, or a string literal | 
|  | 55   /// may be composed of several adjacent string literals. | 
|  | 56   int _nextOffset; | 
|  | 57 | 
|  | 58   /// All [SimpleStringLiteral]s that compose the input literal. | 
|  | 59   /// | 
|  | 60   /// If the input literal is itself a [SimpleStringLiteral], this just contains | 
|  | 61   /// that literal; otherwise, the literal is an [AdjacentStrings], and this | 
|  | 62   /// contains its component literals. | 
|  | 63   final _strings = new Queue<SimpleStringLiteral>(); | 
|  | 64 | 
|  | 65   /// Whether this is a raw string that begins with `r`. | 
|  | 66   /// | 
|  | 67   /// This is necessary for knowing how to parse escape sequences. | 
|  | 68   bool _isRaw; | 
|  | 69 | 
|  | 70   /// The iterator over the runes in the Dart source file. | 
|  | 71   /// | 
|  | 72   /// When switching to a new string in [_strings], this is updated to point to | 
|  | 73   /// that string's component runes. | 
|  | 74   Iterator<int> _runes; | 
|  | 75 | 
|  | 76   /// Whether this has finished iterating. | 
|  | 77   bool _done = false; | 
|  | 78 | 
|  | 79   /// Creates a new [StringLiteralIterator] iterating over the contents of | 
|  | 80   /// [literal]. | 
|  | 81   /// | 
|  | 82   /// Throws an [ArgumentError] if [literal] contains interpolated strings. | 
|  | 83   StringLiteralIterator(StringLiteral literal) { | 
|  | 84     if (literal is StringInterpolation) { | 
|  | 85       throw new ArgumentError("Can't iterate over an interpolated string."); | 
|  | 86     } else if (literal is SimpleStringLiteral) { | 
|  | 87       _strings.add(literal); | 
|  | 88     } else { | 
|  | 89       assert(literal is AdjacentStrings); | 
|  | 90 | 
|  | 91       for (var string in literal.strings) { | 
|  | 92         if (string is StringInterpolation) { | 
|  | 93           throw new ArgumentError("Can't iterate over an interpolated string."); | 
|  | 94         } | 
|  | 95         assert(string is SimpleStringLiteral); | 
|  | 96         _strings.add(string); | 
|  | 97       } | 
|  | 98     } | 
|  | 99 | 
|  | 100     _offset = _strings.first.contentsOffset - 1; | 
|  | 101   } | 
|  | 102 | 
|  | 103   bool moveNext() { | 
|  | 104     if (_done) return false; | 
|  | 105 | 
|  | 106     // If we're at beginning of a [SimpleStringLiteral], move forward until | 
|  | 107     // there's actually text to consume. | 
|  | 108     while (_runes == null || _runes.current == null) { | 
|  | 109       if (_strings.isEmpty) { | 
|  | 110         // Move the offset past the end of the text. | 
|  | 111         _offset = _nextOffset; | 
|  | 112         _current = null; | 
|  | 113         return false; | 
|  | 114       } | 
|  | 115 | 
|  | 116       var string = _strings.removeFirst(); | 
|  | 117       var start = string.contentsOffset - string.offset; | 
|  | 118 | 
|  | 119       // Compensate for the opening and closing quotes. | 
|  | 120       var end = start + string.literal.lexeme.length - | 
|  | 121           2 * (string.isMultiline ? 3 : 1) - | 
|  | 122           (string.isRaw ? 1 : 0); | 
|  | 123       var text = string.literal.lexeme.substring(start, end); | 
|  | 124 | 
|  | 125       _nextOffset = string.contentsOffset; | 
|  | 126       _isRaw = string.isRaw; | 
|  | 127       _runes = text.runes.iterator; | 
|  | 128       _runes.moveNext(); | 
|  | 129     } | 
|  | 130 | 
|  | 131     _offset = _nextOffset; | 
|  | 132     _current = _nextRune(); | 
|  | 133     if (_current != null) return true; | 
|  | 134 | 
|  | 135     // If we encounter a parse failure, stop moving forward immediately. | 
|  | 136     _strings.clear(); | 
|  | 137     return false; | 
|  | 138   } | 
|  | 139 | 
|  | 140   /// Consume and return the next rune. | 
|  | 141   int _nextRune() { | 
|  | 142     if (_isRaw || _runes.current != _backslash) { | 
|  | 143       var rune = _runes.current; | 
|  | 144       _moveRunesNext(); | 
|  | 145       return rune; | 
|  | 146     } | 
|  | 147 | 
|  | 148     if (!_moveRunesNext()) return null; | 
|  | 149     return _parseEscapeSequence(); | 
|  | 150   } | 
|  | 151 | 
|  | 152   /// Parse an escape sequence in the underlying Dart text. | 
|  | 153   /// | 
|  | 154   /// This assumes that a backslash has already been consumed. It leaves the | 
|  | 155   /// [_runes] cursor on the first character after the escape sequence. | 
|  | 156   int _parseEscapeSequence() { | 
|  | 157     switch (_runes.current) { | 
|  | 158       case _n: | 
|  | 159         _moveRunesNext(); | 
|  | 160         return _newline; | 
|  | 161       case _r: | 
|  | 162         _moveRunesNext(); | 
|  | 163         return _carriageReturn; | 
|  | 164       case _f: | 
|  | 165         _moveRunesNext(); | 
|  | 166         return _formFeed; | 
|  | 167       case _b: | 
|  | 168         _moveRunesNext(); | 
|  | 169         return _backspace; | 
|  | 170       case _t: | 
|  | 171         _moveRunesNext(); | 
|  | 172         return _tab; | 
|  | 173       case _v: | 
|  | 174         _moveRunesNext(); | 
|  | 175         return _verticalTab; | 
|  | 176       case _x: | 
|  | 177         if (!_moveRunesNext()) return null; | 
|  | 178         return _parseHex(2); | 
|  | 179       case _u: | 
|  | 180         if (!_moveRunesNext()) return null; | 
|  | 181         if (_runes.current != _openCurly) return _parseHex(4); | 
|  | 182         if (!_moveRunesNext()) return null; | 
|  | 183 | 
|  | 184         var number = _parseHexSequence(); | 
|  | 185         if (_runes.current != _closeCurly) return null; | 
|  | 186         if (!_moveRunesNext()) return null; | 
|  | 187         return number; | 
|  | 188       default: | 
|  | 189         var rune = _runes.current; | 
|  | 190         _moveRunesNext(); | 
|  | 191         return rune; | 
|  | 192     } | 
|  | 193   } | 
|  | 194 | 
|  | 195   /// Parse a variable-length sequence of hexadecimal digits and returns their | 
|  | 196   /// value as an [int]. | 
|  | 197   /// | 
|  | 198   /// This parses digits as they appear in a unicode escape sequence: one to six | 
|  | 199   /// hex digits. | 
|  | 200   int _parseHexSequence() { | 
|  | 201     var number = _parseHexDigit(_runes.current); | 
|  | 202     if (number == null) return null; | 
|  | 203     if (!_moveRunesNext()) return null; | 
|  | 204 | 
|  | 205     for (var i = 0; i < 5; i++) { | 
|  | 206       var digit = _parseHexDigit(_runes.current); | 
|  | 207       if (digit == null) break; | 
|  | 208       number = number * 16 + digit; | 
|  | 209       if (!_moveRunesNext()) return null; | 
|  | 210     } | 
|  | 211 | 
|  | 212     return number; | 
|  | 213   } | 
|  | 214 | 
|  | 215   /// Parses [digits] hexadecimal digits and returns their value as an [int]. | 
|  | 216   int _parseHex(int digits) { | 
|  | 217     var number = 0; | 
|  | 218     for (var i = 0; i < digits; i++) { | 
|  | 219       if (_runes.current == null) return null; | 
|  | 220       var digit = _parseHexDigit(_runes.current); | 
|  | 221       if (digit == null) return null; | 
|  | 222       number = number * 16 + digit; | 
|  | 223       _moveRunesNext(); | 
|  | 224     } | 
|  | 225     return number; | 
|  | 226   } | 
|  | 227 | 
|  | 228   /// Parses a single hexadecimal digit. | 
|  | 229   int _parseHexDigit(int rune) { | 
|  | 230     if (rune < _zero) return null; | 
|  | 231     if (rune <= _nine) return rune - _zero; | 
|  | 232     if (rune < _capitalA) return null; | 
|  | 233     if (rune <= _capitalZ) return 10 + rune - _capitalA; | 
|  | 234     if (rune < _a) return null; | 
|  | 235     if (rune <= _z) return 10 + rune - _a; | 
|  | 236     return null; | 
|  | 237   } | 
|  | 238 | 
|  | 239   /// Move [_runes] to the next rune and update [_nextOffset]. | 
|  | 240   bool _moveRunesNext() { | 
|  | 241     var result = _runes.moveNext(); | 
|  | 242     _nextOffset++; | 
|  | 243     return result; | 
|  | 244   } | 
|  | 245 } | 
| OLD | NEW | 
|---|