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 |