Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(355)

Side by Side Diff: test/generated_sdk/lib/_internal/compiler/js_lib/js_string.dart

Issue 1162723007: remove generated_sdk from checked in code (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 _interceptors;
6
7 /**
8 * The interceptor class for [String]. The compiler recognizes this
9 * class as an interceptor, and changes references to [:this:] to
10 * actually use the receiver of the method, which is generated as an extra
11 * argument added to each member.
12 */
13 class JSString extends Interceptor implements String, JSIndexable {
14 const JSString();
15
16 int codeUnitAt(int index) {
17 if (index is !int) throw new ArgumentError(index);
18 if (index < 0) throw new RangeError.value(index);
19 if (index >= length) throw new RangeError.value(index);
20 return JS('JSUInt31', r'#.charCodeAt(#)', this, index);
21 }
22
23 Iterable<Match> allMatches(String string, [int start = 0]) {
24 checkString(string);
25 checkInt(start);
26 if (0 > start || start > string.length) {
27 throw new RangeError.range(start, 0, string.length);
28 }
29 return allMatchesInStringUnchecked(this, string, start);
30 }
31
32 Match matchAsPrefix(String string, [int start = 0]) {
33 if (start < 0 || start > string.length) {
34 throw new RangeError.range(start, 0, string.length);
35 }
36 if (start + this.length > string.length) return null;
37 // TODO(lrn): See if this can be optimized.
38 for (int i = 0; i < this.length; i++) {
39 if (string.codeUnitAt(start + i) != this.codeUnitAt(i)) {
40 return null;
41 }
42 }
43 return new StringMatch(start, string, this);
44 }
45
46 String operator +(String other) {
47 if (other is !String) throw new ArgumentError(other);
48 return JS('String', r'# + #', this, other);
49 }
50
51 bool endsWith(String other) {
52 checkString(other);
53 int otherLength = other.length;
54 if (otherLength > length) return false;
55 return other == substring(length - otherLength);
56 }
57
58 String replaceAll(Pattern from, String to) {
59 checkString(to);
60 return stringReplaceAllUnchecked(this, from, to);
61 }
62
63 String replaceAllMapped(Pattern from, String convert(Match match)) {
64 return this.splitMapJoin(from, onMatch: convert);
65 }
66
67 String splitMapJoin(Pattern from,
68 {String onMatch(Match match),
69 String onNonMatch(String nonMatch)}) {
70 return stringReplaceAllFuncUnchecked(this, from, onMatch, onNonMatch);
71 }
72
73 String replaceFirst(Pattern from, String to, [int startIndex = 0]) {
74 checkString(to);
75 checkInt(startIndex);
76 if (startIndex < 0 || startIndex > this.length) {
77 throw new RangeError.range(startIndex, 0, this.length);
78 }
79 return stringReplaceFirstUnchecked(this, from, to, startIndex);
80 }
81
82 List<String> split(Pattern pattern) {
83 checkNull(pattern);
84 if (pattern is String) {
85 return JS('JSExtendableArray', r'#.split(#)', this, pattern);
86 } else if (pattern is JSSyntaxRegExp && regExpCaptureCount(pattern) == 0) {
87 var re = regExpGetNative(pattern);
88 return JS('JSExtendableArray', r'#.split(#)', this, re);
89 } else {
90 return _defaultSplit(pattern);
91 }
92 }
93
94 List<String> _defaultSplit(Pattern pattern) {
95 List<String> result = <String>[];
96 // End of most recent match. That is, start of next part to add to result.
97 int start = 0;
98 // Length of most recent match.
99 // Set >0, so no match on the empty string causes the result to be [""].
100 int length = 1;
101 for (var match in pattern.allMatches(this)) {
102 int matchStart = match.start;
103 int matchEnd = match.end;
104 length = matchEnd - matchStart;
105 if (length == 0 && start == matchStart) {
106 // An empty match right after another match is ignored.
107 // This includes an empty match at the start of the string.
108 continue;
109 }
110 int end = matchStart;
111 result.add(this.substring(start, end));
112 start = matchEnd;
113 }
114 if (start < this.length || length > 0) {
115 // An empty match at the end of the string does not cause a "" at the end.
116 // A non-empty match ending at the end of the string does add a "".
117 result.add(this.substring(start));
118 }
119 return result;
120 }
121
122 bool startsWith(Pattern pattern, [int index = 0]) {
123 checkInt(index);
124 if (index < 0 || index > this.length) {
125 throw new RangeError.range(index, 0, this.length);
126 }
127 if (pattern is String) {
128 String other = pattern;
129 int otherLength = other.length;
130 int endIndex = index + otherLength;
131 if (endIndex > length) return false;
132 return other == JS('String', r'#.substring(#, #)', this, index, endIndex);
133 }
134 return pattern.matchAsPrefix(this, index) != null;
135 }
136
137 String substring(int startIndex, [int endIndex]) {
138 checkInt(startIndex);
139 if (endIndex == null) endIndex = length;
140 checkInt(endIndex);
141 if (startIndex < 0 ) throw new RangeError.value(startIndex);
142 if (startIndex > endIndex) throw new RangeError.value(startIndex);
143 if (endIndex > length) throw new RangeError.value(endIndex);
144 return JS('String', r'#.substring(#, #)', this, startIndex, endIndex);
145 }
146
147 String toLowerCase() {
148 return JS('String', r'#.toLowerCase()', this);
149 }
150
151 String toUpperCase() {
152 return JS('String', r'#.toUpperCase()', this);
153 }
154
155 // Characters with Whitespace property (Unicode 6.2).
156 // 0009..000D ; White_Space # Cc <control-0009>..<control-000D>
157 // 0020 ; White_Space # Zs SPACE
158 // 0085 ; White_Space # Cc <control-0085>
159 // 00A0 ; White_Space # Zs NO-BREAK SPACE
160 // 1680 ; White_Space # Zs OGHAM SPACE MARK
161 // 180E ; White_Space # Zs MONGOLIAN VOWEL SEPARATOR
162 // 2000..200A ; White_Space # Zs EN QUAD..HAIR SPACE
163 // 2028 ; White_Space # Zl LINE SEPARATOR
164 // 2029 ; White_Space # Zp PARAGRAPH SEPARATOR
165 // 202F ; White_Space # Zs NARROW NO-BREAK SPACE
166 // 205F ; White_Space # Zs MEDIUM MATHEMATICAL SPACE
167 // 3000 ; White_Space # Zs IDEOGRAPHIC SPACE
168 //
169 // BOM: 0xFEFF
170 static bool _isWhitespace(int codeUnit) {
171 // Most codeUnits should be less than 256. Special case with a smaller
172 // switch.
173 if (codeUnit < 256) {
174 switch (codeUnit) {
175 case 0x09:
176 case 0x0A:
177 case 0x0B:
178 case 0x0C:
179 case 0x0D:
180 case 0x20:
181 case 0x85:
182 case 0xA0:
183 return true;
184 default:
185 return false;
186 }
187 }
188 switch (codeUnit) {
189 case 0x1680:
190 case 0x180E:
191 case 0x2000:
192 case 0x2001:
193 case 0x2002:
194 case 0x2003:
195 case 0x2004:
196 case 0x2005:
197 case 0x2006:
198 case 0x2007:
199 case 0x2008:
200 case 0x2009:
201 case 0x200A:
202 case 0x2028:
203 case 0x2029:
204 case 0x202F:
205 case 0x205F:
206 case 0x3000:
207 case 0xFEFF:
208 return true;
209 default:
210 return false;
211 }
212 }
213
214 /// Finds the index of the first non-whitespace character, or the
215 /// end of the string. Start looking at position [index].
216 static int _skipLeadingWhitespace(String string, int index) {
217 const int SPACE = 0x20;
218 const int CARRIAGE_RETURN = 0x0D;
219 while (index < string.length) {
220 int codeUnit = string.codeUnitAt(index);
221 if (codeUnit != SPACE &&
222 codeUnit != CARRIAGE_RETURN &&
223 !_isWhitespace(codeUnit)) {
224 break;
225 }
226 index++;
227 }
228 return index;
229 }
230
231 /// Finds the index after the the last non-whitespace character, or 0.
232 /// Start looking at position [index - 1].
233 static int _skipTrailingWhitespace(String string, int index) {
234 const int SPACE = 0x20;
235 const int CARRIAGE_RETURN = 0x0D;
236 while (index > 0) {
237 int codeUnit = string.codeUnitAt(index - 1);
238 if (codeUnit != SPACE &&
239 codeUnit != CARRIAGE_RETURN &&
240 !_isWhitespace(codeUnit)) {
241 break;
242 }
243 index--;
244 }
245 return index;
246 }
247
248 // Dart2js can't use JavaScript trim directly,
249 // because JavaScript does not trim
250 // the NEXT LINE (NEL) character (0x85).
251 String trim() {
252 const int NEL = 0x85;
253
254 // Start by doing JS trim. Then check if it leaves a NEL at
255 // either end of the string.
256 String result = JS('String', '#.trim()', this);
257 if (result.length == 0) return result;
258 int firstCode = result.codeUnitAt(0);
259 int startIndex = 0;
260 if (firstCode == NEL) {
261 startIndex = _skipLeadingWhitespace(result, 1);
262 if (startIndex == result.length) return "";
263 }
264
265 int endIndex = result.length;
266 // We know that there is at least one character that is non-whitespace.
267 // Therefore we don't need to verify that endIndex > startIndex.
268 int lastCode = result.codeUnitAt(endIndex - 1);
269 if (lastCode == NEL) {
270 endIndex = _skipTrailingWhitespace(result, endIndex - 1);
271 }
272 if (startIndex == 0 && endIndex == result.length) return result;
273 return JS('String', r'#.substring(#, #)', result, startIndex, endIndex);
274 }
275
276 // Dart2js can't use JavaScript trimLeft directly,
277 // because it is not in ES5, so not every browser implements it,
278 // and because those that do will not trim the NEXT LINE character (0x85).
279 String trimLeft() {
280 const int NEL = 0x85;
281
282 // Start by doing JS trim. Then check if it leaves a NEL at
283 // the beginning of the string.
284 String result;
285 int startIndex = 0;
286 if (JS('bool', 'typeof #.trimLeft != "undefined"', this)) {
287 result = JS('String', '#.trimLeft()', this);
288 if (result.length == 0) return result;
289 int firstCode = result.codeUnitAt(0);
290 if (firstCode == NEL) {
291 startIndex = _skipLeadingWhitespace(result, 1);
292 }
293 } else {
294 result = this;
295 startIndex = _skipLeadingWhitespace(this, 0);
296 }
297 if (startIndex == 0) return result;
298 if (startIndex == result.length) return "";
299 return JS('String', r'#.substring(#)', result, startIndex);
300 }
301
302 // Dart2js can't use JavaScript trimRight directly,
303 // because it is not in ES5 and because JavaScript does not trim
304 // the NEXT LINE character (0x85).
305 String trimRight() {
306 const int NEL = 0x85;
307
308 // Start by doing JS trim. Then check if it leaves a NEL or BOM at
309 // the end of the string.
310 String result;
311 int endIndex;
312 // trimRight is implemented by Firefox and Chrome/Blink,
313 // so use it if it is there.
314 if (JS('bool', 'typeof #.trimRight != "undefined"', this)) {
315 result = JS('String', '#.trimRight()', this);
316 endIndex = result.length;
317 if (endIndex == 0) return result;
318 int lastCode = result.codeUnitAt(endIndex - 1);
319 if (lastCode == NEL) {
320 endIndex = _skipTrailingWhitespace(result, endIndex - 1);
321 }
322 } else {
323 result = this;
324 endIndex = _skipTrailingWhitespace(this, this.length);
325 }
326
327 if (endIndex == result.length) return result;
328 if (endIndex == 0) return "";
329 return JS('String', r'#.substring(#, #)', result, 0, endIndex);
330 }
331
332 String operator*(int times) {
333 if (0 >= times) return ''; // Unnecessary but hoists argument type check.
334 if (times == 1 || this.length == 0) return this;
335 if (times != JS('JSUInt32', '# >>> 0', times)) {
336 // times >= 2^32. We can't create a string that big.
337 throw const OutOfMemoryError();
338 }
339 var result = '';
340 var s = this;
341 while (true) {
342 if (times & 1 == 1) result = s + result;
343 times = JS('JSUInt31', '# >>> 1', times);
344 if (times == 0) break;
345 s += s;
346 }
347 return result;
348 }
349
350 String padLeft(int width, [String padding = ' ']) {
351 int delta = width - this.length;
352 if (delta <= 0) return this;
353 return padding * delta + this;
354 }
355
356 String padRight(int width, [String padding = ' ']) {
357 int delta = width - this.length;
358 if (delta <= 0) return this;
359 return this + padding * delta;
360 }
361
362 List<int> get codeUnits => new _CodeUnits(this);
363
364 Runes get runes => new Runes(this);
365
366 int indexOf(Pattern pattern, [int start = 0]) {
367 checkNull(pattern);
368 if (start is! int) throw new ArgumentError(start);
369 if (start < 0 || start > this.length) {
370 throw new RangeError.range(start, 0, this.length);
371 }
372 if (pattern is String) {
373 return JS('int', r'#.indexOf(#, #)', this, pattern, start);
374 }
375 if (pattern is JSSyntaxRegExp) {
376 JSSyntaxRegExp re = pattern;
377 Match match = firstMatchAfter(re, this, start);
378 return (match == null) ? -1 : match.start;
379 }
380 for (int i = start; i <= this.length; i++) {
381 if (pattern.matchAsPrefix(this, i) != null) return i;
382 }
383 return -1;
384 }
385
386 int lastIndexOf(Pattern pattern, [int start]) {
387 checkNull(pattern);
388 if (start == null) {
389 start = length;
390 } else if (start is! int) {
391 throw new ArgumentError(start);
392 } else if (start < 0 || start > this.length) {
393 throw new RangeError.range(start, 0, this.length);
394 }
395 if (pattern is String) {
396 String other = pattern;
397 if (start + other.length > this.length) {
398 start = this.length - other.length;
399 }
400 return stringLastIndexOfUnchecked(this, other, start);
401 }
402 for (int i = start; i >= 0; i--) {
403 if (pattern.matchAsPrefix(this, i) != null) return i;
404 }
405 return -1;
406 }
407
408 bool contains(Pattern other, [int startIndex = 0]) {
409 checkNull(other);
410 if (startIndex < 0 || startIndex > this.length) {
411 throw new RangeError.range(startIndex, 0, this.length);
412 }
413 return stringContainsUnchecked(this, other, startIndex);
414 }
415
416 bool get isEmpty => length == 0;
417
418 bool get isNotEmpty => !isEmpty;
419
420 int compareTo(String other) {
421 if (other is !String) throw new ArgumentError(other);
422 return this == other ? 0
423 : JS('bool', r'# < #', this, other) ? -1 : 1;
424 }
425
426 // Note: if you change this, also change the function [S].
427 String toString() => this;
428
429 /**
430 * This is the [Jenkins hash function][1] but using masking to keep
431 * values in SMI range.
432 *
433 * [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
434 */
435 int get hashCode {
436 // TODO(ahe): This method shouldn't have to use JS. Update when our
437 // optimizations are smarter.
438 int hash = 0;
439 for (int i = 0; i < length; i++) {
440 hash = 0x1fffffff & (hash + JS('int', r'#.charCodeAt(#)', this, i));
441 hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
442 hash = JS('int', '# ^ (# >> 6)', hash, hash);
443 }
444 hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
445 hash = JS('int', '# ^ (# >> 11)', hash, hash);
446 return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
447 }
448
449 Type get runtimeType => String;
450
451 int get length => JS('int', r'#.length', this);
452
453 String operator [](int index) {
454 if (index is !int) throw new ArgumentError(index);
455 if (index >= length || index < 0) throw new RangeError.value(index);
456 return JS('String', '#[#]', this, index);
457 }
458 }
459
460 /**
461 * An [Iterable] of the UTF-16 code units of a [String] in index order.
462 */
463 class _CodeUnits extends UnmodifiableListBase<int> {
464 /** The string that this is the code units of. */
465 String _string;
466
467 _CodeUnits(this._string);
468
469 int get length => _string.length;
470 int operator[](int i) => _string.codeUnitAt(i);
471 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698