| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 part of tree; | |
| 6 | |
| 7 /** | |
| 8 * The [DartString] type represents a Dart string value as a sequence of Unicode | |
| 9 * Scalar Values. | |
| 10 * After parsing, any valid [LiteralString] will contain a [DartString] | |
| 11 * representing its content after removing quotes and resolving escapes in | |
| 12 * its source. | |
| 13 */ | |
| 14 abstract class DartString extends IterableBase<int> { | |
| 15 factory DartString.empty() => const LiteralDartString(""); | |
| 16 // This is a convenience constructor. If you need a const literal DartString, | |
| 17 // use [const LiteralDartString(string)] directly. | |
| 18 factory DartString.literal(String string) => new LiteralDartString(string); | |
| 19 factory DartString.rawString(String source, int length) => | |
| 20 new RawSourceDartString(source, length); | |
| 21 factory DartString.escapedString(String source, int length) => | |
| 22 new EscapedSourceDartString(source, length); | |
| 23 factory DartString.concat(DartString first, DartString second) { | |
| 24 if (first.isEmpty) return second; | |
| 25 if (second.isEmpty) return first; | |
| 26 return new ConsDartString(first, second); | |
| 27 } | |
| 28 const DartString(); | |
| 29 | |
| 30 /** | |
| 31 * The length of this [DartString], which is the string length after | |
| 32 * escapes have been resolved. | |
| 33 */ | |
| 34 int get length; | |
| 35 bool get isEmpty => length == 0; | |
| 36 | |
| 37 Iterator<int> get iterator; | |
| 38 | |
| 39 /** | |
| 40 * The string represented by this [DartString]. | |
| 41 */ | |
| 42 String slowToString(); | |
| 43 | |
| 44 bool operator ==(var other) { | |
| 45 if (other is !DartString) return false; | |
| 46 DartString otherString = other; | |
| 47 if (length != otherString.length) return false; | |
| 48 Iterator it1 = iterator; | |
| 49 Iterator it2 = otherString.iterator; | |
| 50 while (it1.moveNext()) { | |
| 51 if (!it2.moveNext()) return false; | |
| 52 if (it1.current != it2.current) return false; | |
| 53 } | |
| 54 return true; | |
| 55 } | |
| 56 | |
| 57 int get hashCode => throw new UnsupportedError('DartString.hashCode'); | |
| 58 | |
| 59 /** | |
| 60 * A textual representation of this [DartString] with some debugging | |
| 61 * information. | |
| 62 */ | |
| 63 String toString() => "DartString#${length}:${slowToString()}"; | |
| 64 } | |
| 65 | |
| 66 | |
| 67 /** | |
| 68 * A [DartString] where the content is represented by an actual [String]. | |
| 69 */ | |
| 70 class LiteralDartString extends DartString { | |
| 71 final String string; | |
| 72 const LiteralDartString(this.string); | |
| 73 int get length => string.length; | |
| 74 Iterator<int> get iterator => string.codeUnits.iterator; | |
| 75 String slowToString() => string; | |
| 76 } | |
| 77 | |
| 78 /** | |
| 79 * A [DartString] whereSource the content comes from a slice of the program | |
| 80 * source. | |
| 81 */ | |
| 82 abstract class SourceBasedDartString extends DartString { | |
| 83 /** | |
| 84 * The source string containing explicit escapes from which this [DartString] | |
| 85 * is built. | |
| 86 */ | |
| 87 final String source; | |
| 88 final int length; | |
| 89 SourceBasedDartString(this.source, this.length); | |
| 90 Iterator<int> get iterator; | |
| 91 } | |
| 92 | |
| 93 /** | |
| 94 * Special case of a [SourceBasedDartString] where we know the source doesn't | |
| 95 * contain any escapes. | |
| 96 */ | |
| 97 class RawSourceDartString extends SourceBasedDartString { | |
| 98 RawSourceDartString(source, length) : super(source, length); | |
| 99 Iterator<int> get iterator => source.codeUnits.iterator; | |
| 100 String slowToString() => source; | |
| 101 } | |
| 102 | |
| 103 /** | |
| 104 * General case of a [SourceBasedDartString] where the source might contain | |
| 105 * escapes. | |
| 106 */ | |
| 107 class EscapedSourceDartString extends SourceBasedDartString { | |
| 108 String toStringCache; | |
| 109 EscapedSourceDartString(source, length) : super(source, length); | |
| 110 Iterator<int> get iterator { | |
| 111 if (toStringCache != null) return toStringCache.codeUnits.iterator; | |
| 112 return new StringEscapeIterator(source); | |
| 113 } | |
| 114 String slowToString() { | |
| 115 if (toStringCache != null) return toStringCache; | |
| 116 StringBuffer buffer = new StringBuffer(); | |
| 117 StringEscapeIterator it = new StringEscapeIterator(source); | |
| 118 while (it.moveNext()) { | |
| 119 buffer.writeCharCode(it.current); | |
| 120 } | |
| 121 toStringCache = buffer.toString(); | |
| 122 return toStringCache; | |
| 123 } | |
| 124 } | |
| 125 | |
| 126 /** | |
| 127 * The concatenation of two [DartString]s. | |
| 128 */ | |
| 129 class ConsDartString extends DartString { | |
| 130 final DartString left; | |
| 131 final DartString right; | |
| 132 final int length; | |
| 133 String toStringCache; | |
| 134 ConsDartString(DartString left, DartString right) | |
| 135 : this.left = left, | |
| 136 this.right = right, | |
| 137 length = left.length + right.length; | |
| 138 | |
| 139 Iterator<int> get iterator => new ConsDartStringIterator(this); | |
| 140 | |
| 141 String slowToString() { | |
| 142 if (toStringCache != null) return toStringCache; | |
| 143 toStringCache = left.slowToString() + right.slowToString(); | |
| 144 return toStringCache; | |
| 145 } | |
| 146 String get source => slowToString(); | |
| 147 } | |
| 148 | |
| 149 class ConsDartStringIterator implements Iterator<int> { | |
| 150 HasNextIterator<int> currentIterator; | |
| 151 DartString right; | |
| 152 bool hasNextLookAhead; | |
| 153 int _current = null; | |
| 154 | |
| 155 ConsDartStringIterator(ConsDartString cons) | |
| 156 : currentIterator = new HasNextIterator<int>(cons.left.iterator), | |
| 157 right = cons.right { | |
| 158 hasNextLookAhead = currentIterator.hasNext; | |
| 159 if (!hasNextLookAhead) { | |
| 160 nextPart(); | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 int get current => _current; | |
| 165 | |
| 166 bool moveNext() { | |
| 167 if (!hasNextLookAhead) { | |
| 168 _current = null; | |
| 169 return false; | |
| 170 } | |
| 171 _current = currentIterator.next(); | |
| 172 hasNextLookAhead = currentIterator.hasNext; | |
| 173 if (!hasNextLookAhead) { | |
| 174 nextPart(); | |
| 175 } | |
| 176 return true; | |
| 177 } | |
| 178 void nextPart() { | |
| 179 if (right != null) { | |
| 180 currentIterator = new HasNextIterator<int>(right.iterator); | |
| 181 right = null; | |
| 182 hasNextLookAhead = currentIterator.hasNext; | |
| 183 } | |
| 184 } | |
| 185 } | |
| 186 | |
| 187 /** | |
| 188 *Iterator that returns the actual string contents of a string with escapes. | |
| 189 */ | |
| 190 class StringEscapeIterator implements Iterator<int>{ | |
| 191 final Iterator<int> source; | |
| 192 int _current = null; | |
| 193 | |
| 194 StringEscapeIterator(String source) : this.source = source.codeUnits.iterator; | |
| 195 | |
| 196 int get current => _current; | |
| 197 | |
| 198 bool moveNext() { | |
| 199 if (!source.moveNext()) { | |
| 200 _current = null; | |
| 201 return false; | |
| 202 } | |
| 203 int code = source.current; | |
| 204 if (code != $BACKSLASH) { | |
| 205 _current = code; | |
| 206 return true; | |
| 207 } | |
| 208 source.moveNext(); | |
| 209 code = source.current; | |
| 210 switch (code) { | |
| 211 case $n: _current = $LF; break; | |
| 212 case $r: _current = $CR; break; | |
| 213 case $t: _current = $TAB; break; | |
| 214 case $b: _current = $BS; break; | |
| 215 case $f: _current = $FF; break; | |
| 216 case $v: _current = $VTAB; break; | |
| 217 case $x: | |
| 218 source.moveNext(); | |
| 219 int value = hexDigitValue(source.current); | |
| 220 source.moveNext(); | |
| 221 value = value * 16 + hexDigitValue(source.current); | |
| 222 _current = value; | |
| 223 break; | |
| 224 case $u: | |
| 225 int value = 0; | |
| 226 source.moveNext(); | |
| 227 code = source.current; | |
| 228 if (code == $OPEN_CURLY_BRACKET) { | |
| 229 source.moveNext(); | |
| 230 while (source.current != $CLOSE_CURLY_BRACKET) { | |
| 231 value = value * 16 + hexDigitValue(source.current); | |
| 232 source.moveNext(); | |
| 233 } | |
| 234 _current = value; | |
| 235 break; | |
| 236 } | |
| 237 // Four digit hex value. | |
| 238 value = hexDigitValue(code); | |
| 239 for (int i = 0; i < 3; i++) { | |
| 240 source.moveNext(); | |
| 241 value = value * 16 + hexDigitValue(source.current); | |
| 242 } | |
| 243 _current = value; | |
| 244 break; | |
| 245 default: | |
| 246 _current = code; | |
| 247 } | |
| 248 return true; | |
| 249 } | |
| 250 } | |
| 251 | |
| OLD | NEW |