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 |