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