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

Side by Side Diff: tool/input_sdk/private/string_helper.dart

Issue 1950133003: Update String methods. (Closed) Base URL: https://github.com/dart-lang/dev_compiler@master
Patch Set: Created 4 years, 7 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
« no previous file with comments | « tool/input_sdk/private/js_string.dart ('k') | tool/sdk_expected_errors.txt » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 dart._js_helper; 5 part of dart._js_helper;
6 6
7 int stringIndexOfStringUnchecked(receiver, other, startIndex) {
8 return JS('int', '#.indexOf(#, #)', receiver, other, startIndex);
9 }
10
11 String substring1Unchecked(receiver, startIndex) {
12 return JS('String', '#.substring(#)', receiver, startIndex);
13 }
14
15 String substring2Unchecked(receiver, startIndex, endIndex) {
16 return JS('String', '#.substring(#, #)', receiver, startIndex, endIndex);
17 }
18
19 bool stringContainsStringUnchecked(receiver, other, startIndex) {
20 return stringIndexOfStringUnchecked(receiver, other, startIndex) >= 0;
21 }
22
7 class StringMatch implements Match { 23 class StringMatch implements Match {
8 const StringMatch(int this.start, 24 const StringMatch(int this.start,
9 String this.input, 25 String this.input,
10 String this.pattern); 26 String this.pattern);
11 27
12 int get end => start + pattern.length; 28 int get end => start + pattern.length;
13 String operator[](int g) => group(g); 29 String operator[](int g) => group(g);
14 int get groupCount => 0; 30 int get groupCount => 0;
15 31
16 String group(int group_) { 32 String group(int group_) {
17 if (group_ != 0) { 33 if (group_ != 0) {
18 throw new RangeError.value(group_); 34 throw new RangeError.value(group_);
19 } 35 }
20 return pattern; 36 return pattern;
21 } 37 }
22 38
23 List<String> groups(List<int> groups_) { 39 List<String> groups(List<int> groups_) {
24 List<String> result = new List<String>(); 40 List<String> result = new List<String>();
25 for (int g in groups_) { 41 for (int g in groups_) {
26 result.add(group(g)); 42 result.add(group(g));
27 } 43 }
28 return result; 44 return result;
29 } 45 }
30 46
31 final int start; 47 final int start;
32 final String input; 48 final String input;
33 final String pattern; 49 final String pattern;
34 } 50 }
35 51
36 List<Match> allMatchesInStringUnchecked(String needle, String haystack, 52 Iterable<Match> allMatchesInStringUnchecked(String pattern, String string,
37 int startIndex) { 53 int startIndex) {
38 // Copied from StringBase.allMatches in 54 return new _StringAllMatchesIterable(string, pattern, startIndex);
39 // /runtime/lib/string_base.dart
40 List<Match> result = new List<Match>();
41 int length = haystack.length;
42 int patternLength = needle.length;
43 while (true) {
44 int position = haystack.indexOf(needle, startIndex);
45 if (position == -1) {
46 break;
47 }
48 result.add(new StringMatch(position, haystack, needle));
49 int endIndex = position + patternLength;
50 if (endIndex == length) {
51 break;
52 } else if (position == endIndex) {
53 ++startIndex; // empty match, advance and restart
54 } else {
55 startIndex = endIndex;
56 }
57 }
58 return result;
59 } 55 }
60 56
61 stringContainsUnchecked(receiver, other, startIndex) { 57 class _StringAllMatchesIterable extends IterableBase<Match> {
58 final String _input;
59 final String _pattern;
60 final int _index;
61
62 _StringAllMatchesIterable(this._input, this._pattern, this._index);
63
64 Iterator<Match> get iterator =>
65 new _StringAllMatchesIterator(_input, _pattern, _index);
66
67 Match get first {
68 int index = stringIndexOfStringUnchecked(_input, _pattern, _index);
69 if (index >= 0) {
70 return new StringMatch(index, _input, _pattern);
71 }
72 throw IterableElementError.noElement();
73 }
74 }
75
76 class _StringAllMatchesIterator implements Iterator<Match> {
77 final String _input;
78 final String _pattern;
79 int _index;
80 Match _current;
81
82 _StringAllMatchesIterator(this._input, this._pattern, this._index);
83
84 bool moveNext() {
85 if (_index + _pattern.length > _input.length) {
86 _current = null;
87 return false;
88 }
89 var index = stringIndexOfStringUnchecked(_input, _pattern, _index);
90 if (index < 0) {
91 _index = _input.length + 1;
92 _current = null;
93 return false;
94 }
95 int end = index + _pattern.length;
96 _current = new StringMatch(index, _input, _pattern);
97 // Empty match, don't start at same location again.
98 if (end == _index) end++;
99 _index = end;
100 return true;
101 }
102
103 Match get current => _current;
104 }
105
106 bool stringContainsUnchecked(String receiver, other, int startIndex) {
62 if (other is String) { 107 if (other is String) {
63 return receiver.indexOf(other, startIndex) != -1; 108 return stringContainsStringUnchecked(receiver, other, startIndex);
64 } else if (other is JSSyntaxRegExp) { 109 } else if (other is JSSyntaxRegExp) {
65 return other.hasMatch(receiver.substring(startIndex)); 110 return other.hasMatch(receiver.substring(startIndex));
66 } else { 111 } else {
67 var substr = receiver.substring(startIndex); 112 var substr = receiver.substring(startIndex);
68 return other.allMatches(substr).isNotEmpty; 113 return other.allMatches(substr).isNotEmpty;
69 } 114 }
70 } 115 }
71 116
72 stringReplaceJS(receiver, replacer, to) { 117 String stringReplaceJS(receiver, replacer, replacement) {
73 // The JavaScript String.replace method recognizes replacement 118 // The JavaScript String.replace method recognizes replacement
74 // patterns in the replacement string. Dart does not have that 119 // patterns in the replacement string. Dart does not have that
75 // behavior. 120 // behavior.
76 to = JS('String', r'#.replace(/\$/g, "$$$$")', to); 121 replacement = JS('String', r'#.replace(/\$/g, "$$$$")', replacement);
77 return JS('String', r'#.replace(#, #)', receiver, replacer, to); 122 return JS('String', r'#.replace(#, #)', receiver, replacer, replacement);
78 } 123 }
79 124
80 stringReplaceFirstRE(receiver, regexp, to, startIndex) { 125 String stringReplaceFirstRE(String receiver,
126 JSSyntaxRegExp regexp, String replacement, int startIndex) {
81 var match = regexp._execGlobal(receiver, startIndex); 127 var match = regexp._execGlobal(receiver, startIndex);
82 if (match == null) return receiver; 128 if (match == null) return receiver;
83 var start = match.start; 129 var start = match.start;
84 var end = match.end; 130 var end = match.end;
85 return "${receiver.substring(0,start)}$to${receiver.substring(end)}"; 131 return stringReplaceRangeUnchecked(receiver, start, end, replacement);
86 } 132 }
87 133
88 const String ESCAPE_REGEXP = r'[[\]{}()*+?.\\^$|]';
89 134
90 stringReplaceAllUnchecked(receiver, from, to) { 135 /// Returns a string for a RegExp pattern that matches [string]. This is done by
91 checkString(to); 136 /// escaping all RegExp metacharacters.
92 if (from is String) { 137 String quoteStringForRegExp(string) {
93 if (from == "") { 138 return JS('String', r'#.replace(/[[\]{}()*+?.\\^$|]/g, "\\$&")', string);
139 }
140
141 String stringReplaceAllUnchecked(
142 String receiver, Pattern pattern, String replacement) {
143 checkString(replacement);
144 if (pattern is String) {
145 if (pattern == "") {
94 if (receiver == "") { 146 if (receiver == "") {
95 return to; 147 return replacement;
96 } else { 148 } else {
97 StringBuffer result = new StringBuffer(); 149 StringBuffer result = new StringBuffer();
98 int length = receiver.length; 150 int length = receiver.length;
99 result.write(to); 151 result.write(replacement);
100 for (int i = 0; i < length; i++) { 152 for (int i = 0; i < length; i++) {
101 result.write(receiver[i]); 153 result.write(receiver[i]);
102 result.write(to); 154 result.write(replacement);
103 } 155 }
104 return result.toString(); 156 return result.toString();
105 } 157 }
106 } else { 158 } else {
107 var quoter = JS('', "new RegExp(#, 'g')", ESCAPE_REGEXP); 159 var quoted = quoteStringForRegExp(pattern);
108 var quoted = JS('String', r'#.replace(#, "\\$&")', from, quoter);
109 var replacer = JS('', "new RegExp(#, 'g')", quoted); 160 var replacer = JS('', "new RegExp(#, 'g')", quoted);
110 return stringReplaceJS(receiver, replacer, to); 161 return stringReplaceJS(receiver, replacer, replacement);
111 } 162 }
112 } else if (from is JSSyntaxRegExp) { 163 } else if (pattern is JSSyntaxRegExp) {
113 var re = regExpGetGlobalNative(from); 164 var re = regExpGetGlobalNative(pattern);
114 return stringReplaceJS(receiver, re, to); 165 return stringReplaceJS(receiver, re, replacement);
115 } else { 166 } else {
116 checkNull(from); 167 checkNull(pattern);
117 // TODO(floitsch): implement generic String.replace (with patterns). 168 // TODO(floitsch): implement generic String.replace (with patterns).
118 throw "String.replaceAll(Pattern) UNIMPLEMENTED"; 169 throw "String.replaceAll(Pattern) UNIMPLEMENTED";
119 } 170 }
120 } 171 }
121 172
122 String _matchString(Match match) => match[0]; 173 String _matchString(Match match) => match[0];
123 String _stringIdentity(String string) => string; 174 String _stringIdentity(String string) => string;
124 175
125 stringReplaceAllFuncUnchecked(receiver, pattern, onMatch, onNonMatch) { 176 String stringReplaceAllFuncUnchecked(
126 if (pattern is! Pattern) { 177 String receiver,
127 throw new ArgumentError("${pattern} is not a Pattern"); 178 Pattern pattern,
128 } 179 String onMatch(Match match),
180 String onNonMatch(String nonMatch)) {
129 if (onMatch == null) onMatch = _matchString; 181 if (onMatch == null) onMatch = _matchString;
130 if (onNonMatch == null) onNonMatch = _stringIdentity; 182 if (onNonMatch == null) onNonMatch = _stringIdentity;
131 if (pattern is String) { 183 if (pattern is String) {
132 return stringReplaceAllStringFuncUnchecked(receiver, pattern, 184 return stringReplaceAllStringFuncUnchecked(receiver, pattern,
133 onMatch, onNonMatch); 185 onMatch, onNonMatch);
134 } 186 }
187 // Placing the Pattern test here is indistingishable from placing it at the
188 // top of the method but it saves an extra check on the `pattern is String`
189 // path.
190 if (pattern is! Pattern) {
191 throw new ArgumentError.value(pattern, 'pattern', 'is not a Pattern');
192 }
135 StringBuffer buffer = new StringBuffer(); 193 StringBuffer buffer = new StringBuffer();
136 int startIndex = 0; 194 int startIndex = 0;
137 for (Match match in pattern.allMatches(receiver)) { 195 for (Match match in pattern.allMatches(receiver)) {
138 buffer.write(onNonMatch(receiver.substring(startIndex, match.start))); 196 buffer.write(onNonMatch(receiver.substring(startIndex, match.start)));
139 buffer.write(onMatch(match)); 197 buffer.write(onMatch(match));
140 startIndex = match.end; 198 startIndex = match.end;
141 } 199 }
142 buffer.write(onNonMatch(receiver.substring(startIndex))); 200 buffer.write(onNonMatch(receiver.substring(startIndex)));
143 return buffer.toString(); 201 return buffer.toString();
144 } 202 }
145 203
146 stringReplaceAllEmptyFuncUnchecked(receiver, onMatch, onNonMatch) { 204 String stringReplaceAllEmptyFuncUnchecked(String receiver,
205 String onMatch(Match match),
206 String onNonMatch(String nonMatch)) {
147 // Pattern is the empty string. 207 // Pattern is the empty string.
148 StringBuffer buffer = new StringBuffer(); 208 StringBuffer buffer = new StringBuffer();
149 int length = receiver.length; 209 int length = receiver.length;
150 int i = 0; 210 int i = 0;
151 buffer.write(onNonMatch("")); 211 buffer.write(onNonMatch(""));
152 while (i < length) { 212 while (i < length) {
153 buffer.write(onMatch(new StringMatch(i, receiver, ""))); 213 buffer.write(onMatch(new StringMatch(i, receiver, "")));
154 // Special case to avoid splitting a surrogate pair. 214 // Special case to avoid splitting a surrogate pair.
155 int code = receiver.codeUnitAt(i); 215 int code = receiver.codeUnitAt(i);
156 if ((code & ~0x3FF) == 0xD800 && length > i + 1) { 216 if ((code & ~0x3FF) == 0xD800 && length > i + 1) {
157 // Leading surrogate; 217 // Leading surrogate;
158 code = receiver.codeUnitAt(i + 1); 218 code = receiver.codeUnitAt(i + 1);
159 if ((code & ~0x3FF) == 0xDC00) { 219 if ((code & ~0x3FF) == 0xDC00) {
160 // Matching trailing surrogate. 220 // Matching trailing surrogate.
161 buffer.write(onNonMatch(receiver.substring(i, i + 2))); 221 buffer.write(onNonMatch(receiver.substring(i, i + 2)));
162 i += 2; 222 i += 2;
163 continue; 223 continue;
164 } 224 }
165 } 225 }
166 buffer.write(onNonMatch(receiver[i])); 226 buffer.write(onNonMatch(receiver[i]));
167 i++; 227 i++;
168 } 228 }
169 buffer.write(onMatch(new StringMatch(i, receiver, ""))); 229 buffer.write(onMatch(new StringMatch(i, receiver, "")));
170 buffer.write(onNonMatch("")); 230 buffer.write(onNonMatch(""));
171 return buffer.toString(); 231 return buffer.toString();
172 } 232 }
173 233
174 stringReplaceAllStringFuncUnchecked(receiver, pattern, onMatch, onNonMatch) { 234 String stringReplaceAllStringFuncUnchecked(
235 String receiver,
236 String pattern,
237 String onMatch(Match match),
238 String onNonMatch(String nonMatch)) {
175 int patternLength = pattern.length; 239 int patternLength = pattern.length;
176 if (patternLength == 0) { 240 if (patternLength == 0) {
177 return stringReplaceAllEmptyFuncUnchecked(receiver, onMatch, onNonMatch); 241 return stringReplaceAllEmptyFuncUnchecked(receiver, onMatch, onNonMatch);
178 } 242 }
179 int length = receiver.length; 243 int length = receiver.length;
180 StringBuffer buffer = new StringBuffer(); 244 StringBuffer buffer = new StringBuffer();
181 int startIndex = 0; 245 int startIndex = 0;
182 while (startIndex < length) { 246 while (startIndex < length) {
183 int position = receiver.indexOf(pattern, startIndex); 247 int position = stringIndexOfStringUnchecked(receiver, pattern, startIndex);
184 if (position == -1) { 248 if (position == -1) {
185 break; 249 break;
186 } 250 }
187 buffer.write(onNonMatch(receiver.substring(startIndex, position))); 251 buffer.write(onNonMatch(receiver.substring(startIndex, position)));
188 buffer.write(onMatch(new StringMatch(position, receiver, pattern))); 252 buffer.write(onMatch(new StringMatch(position, receiver, pattern)));
189 startIndex = position + patternLength; 253 startIndex = position + patternLength;
190 } 254 }
191 buffer.write(onNonMatch(receiver.substring(startIndex))); 255 buffer.write(onNonMatch(receiver.substring(startIndex)));
192 return buffer.toString(); 256 return buffer.toString();
193 } 257 }
194 258
195 259
196 stringReplaceFirstUnchecked(receiver, from, to, [int startIndex = 0]) { 260 String stringReplaceFirstUnchecked(
197 if (from is String) { 261 String receiver, Pattern pattern, String replacement, int startIndex) {
198 var index = receiver.indexOf(from, startIndex); 262 if (pattern is String) {
263 int index = stringIndexOfStringUnchecked(receiver, pattern, startIndex);
199 if (index < 0) return receiver; 264 if (index < 0) return receiver;
200 return '${receiver.substring(0, index)}$to' 265 int end = index + pattern.length;
201 '${receiver.substring(index + from.length)}'; 266 return stringReplaceRangeUnchecked(receiver, index, end, replacement);
202 } else if (from is JSSyntaxRegExp) {
203 return startIndex == 0 ?
204 stringReplaceJS(receiver, regExpGetNative(from), to) :
205 stringReplaceFirstRE(receiver, from, to, startIndex);
206 } else {
207 checkNull(from);
208 // TODO(floitsch): implement generic String.replace (with patterns).
209 throw "String.replace(Pattern) UNIMPLEMENTED";
210 } 267 }
268 if (pattern is JSSyntaxRegExp) {
269 return startIndex == 0
270 ? stringReplaceJS(receiver, regExpGetNative(pattern), replacement)
271 : stringReplaceFirstRE(receiver, pattern, replacement, startIndex);
272 }
273 checkNull(pattern);
274 Iterator<Match> matches = pattern.allMatches(receiver, startIndex).iterator;
275 if (!matches.moveNext()) return receiver;
276 Match match = matches.current;
277 return receiver.replaceRange(match.start, match.end, replacement);
211 } 278 }
212 279
213 stringJoinUnchecked(array, separator) { 280 String stringReplaceFirstMappedUnchecked(
281 String receiver,
282 Pattern pattern,
283 String replace(Match current),
284 int startIndex) {
285 Iterator<Match> matches = pattern.allMatches(receiver, startIndex).iterator;
286 if (!matches.moveNext()) return receiver;
287 Match match = matches.current;
288 String replacement = "${replace(match)}";
289 return receiver.replaceRange(match.start, match.end, replacement);
290 }
291
292 String stringJoinUnchecked(array, separator) {
214 return JS('String', r'#.join(#)', array, separator); 293 return JS('String', r'#.join(#)', array, separator);
215 } 294 }
295
296 String stringReplaceRangeUnchecked(String receiver,
297 int start, int end, String replacement) {
298 var prefix = JS('String', '#.substring(0, #)', receiver, start);
299 var suffix = JS('String', '#.substring(#)', receiver, end);
300 return "$prefix$replacement$suffix";
301 }
OLDNEW
« no previous file with comments | « tool/input_sdk/private/js_string.dart ('k') | tool/sdk_expected_errors.txt » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698