| 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 dart._js_helper; | 5 part of dart._js_helper; |
| 6 | 6 |
| 7 int stringIndexOfStringUnchecked(receiver, other, startIndex) { | 7 int stringIndexOfStringUnchecked(receiver, other, startIndex) { |
| 8 return JS('int', '#.indexOf(#, #)', receiver, other, startIndex); | 8 return JS('int', '#.indexOf(#, #)', receiver, other, startIndex); |
| 9 } | 9 } |
| 10 | 10 |
| 11 String substring1Unchecked(receiver, startIndex) { | 11 String substring1Unchecked(receiver, startIndex) { |
| 12 return JS('String', '#.substring(#)', receiver, startIndex); | 12 return JS('String', '#.substring(#)', receiver, startIndex); |
| 13 } | 13 } |
| 14 | 14 |
| 15 String substring2Unchecked(receiver, startIndex, endIndex) { | 15 String substring2Unchecked(receiver, startIndex, endIndex) { |
| 16 return JS('String', '#.substring(#, #)', receiver, startIndex, endIndex); | 16 return JS('String', '#.substring(#, #)', receiver, startIndex, endIndex); |
| 17 } | 17 } |
| 18 | 18 |
| 19 bool stringContainsStringUnchecked(receiver, other, startIndex) { | 19 bool stringContainsStringUnchecked(receiver, other, startIndex) { |
| 20 return stringIndexOfStringUnchecked(receiver, other, startIndex) >= 0; | 20 return stringIndexOfStringUnchecked(receiver, other, startIndex) >= 0; |
| 21 } | 21 } |
| 22 | 22 |
| 23 class StringMatch implements Match { | 23 class StringMatch implements Match { |
| 24 const StringMatch(int this.start, | 24 const StringMatch(int this.start, String this.input, String this.pattern); |
| 25 String this.input, | |
| 26 String this.pattern); | |
| 27 | 25 |
| 28 int get end => start + pattern.length; | 26 int get end => start + pattern.length; |
| 29 String operator[](int g) => group(g); | 27 String operator [](int g) => group(g); |
| 30 int get groupCount => 0; | 28 int get groupCount => 0; |
| 31 | 29 |
| 32 String group(int group_) { | 30 String group(int group_) { |
| 33 if (group_ != 0) { | 31 if (group_ != 0) { |
| 34 throw new RangeError.value(group_); | 32 throw new RangeError.value(group_); |
| 35 } | 33 } |
| 36 return pattern; | 34 return pattern; |
| 37 } | 35 } |
| 38 | 36 |
| 39 List<String> groups(List<int> groups_) { | 37 List<String> groups(List<int> groups_) { |
| 40 List<String> result = new List<String>(); | 38 List<String> result = new List<String>(); |
| 41 for (int g in groups_) { | 39 for (int g in groups_) { |
| 42 result.add(group(g)); | 40 result.add(group(g)); |
| 43 } | 41 } |
| 44 return result; | 42 return result; |
| 45 } | 43 } |
| 46 | 44 |
| 47 final int start; | 45 final int start; |
| 48 final String input; | 46 final String input; |
| 49 final String pattern; | 47 final String pattern; |
| 50 } | 48 } |
| 51 | 49 |
| 52 Iterable<Match> allMatchesInStringUnchecked(String pattern, String string, | 50 Iterable<Match> allMatchesInStringUnchecked( |
| 53 int startIndex) { | 51 String pattern, String string, int startIndex) { |
| 54 return new _StringAllMatchesIterable(string, pattern, startIndex); | 52 return new _StringAllMatchesIterable(string, pattern, startIndex); |
| 55 } | 53 } |
| 56 | 54 |
| 57 class _StringAllMatchesIterable extends Iterable<Match> { | 55 class _StringAllMatchesIterable extends Iterable<Match> { |
| 58 final String _input; | 56 final String _input; |
| 59 final String _pattern; | 57 final String _pattern; |
| 60 final int _index; | 58 final int _index; |
| 61 | 59 |
| 62 _StringAllMatchesIterable(this._input, this._pattern, this._index); | 60 _StringAllMatchesIterable(this._input, this._pattern, this._index); |
| 63 | 61 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 115 } | 113 } |
| 116 | 114 |
| 117 String stringReplaceJS(receiver, replacer, replacement) { | 115 String stringReplaceJS(receiver, replacer, replacement) { |
| 118 // The JavaScript String.replace method recognizes replacement | 116 // The JavaScript String.replace method recognizes replacement |
| 119 // patterns in the replacement string. Dart does not have that | 117 // patterns in the replacement string. Dart does not have that |
| 120 // behavior. | 118 // behavior. |
| 121 replacement = JS('String', r'#.replace(/\$/g, "$$$$")', replacement); | 119 replacement = JS('String', r'#.replace(/\$/g, "$$$$")', replacement); |
| 122 return JS('String', r'#.replace(#, #)', receiver, replacer, replacement); | 120 return JS('String', r'#.replace(#, #)', receiver, replacer, replacement); |
| 123 } | 121 } |
| 124 | 122 |
| 125 String stringReplaceFirstRE(String receiver, | 123 String stringReplaceFirstRE(String receiver, JSSyntaxRegExp regexp, |
| 126 JSSyntaxRegExp regexp, String replacement, int startIndex) { | 124 String replacement, int startIndex) { |
| 127 var match = regexp._execGlobal(receiver, startIndex); | 125 var match = regexp._execGlobal(receiver, startIndex); |
| 128 if (match == null) return receiver; | 126 if (match == null) return receiver; |
| 129 var start = match.start; | 127 var start = match.start; |
| 130 var end = match.end; | 128 var end = match.end; |
| 131 return stringReplaceRangeUnchecked(receiver, start, end, replacement); | 129 return stringReplaceRangeUnchecked(receiver, start, end, replacement); |
| 132 } | 130 } |
| 133 | 131 |
| 134 | |
| 135 /// Returns a string for a RegExp pattern that matches [string]. This is done by | 132 /// Returns a string for a RegExp pattern that matches [string]. This is done by |
| 136 /// escaping all RegExp metacharacters. | 133 /// escaping all RegExp metacharacters. |
| 137 String quoteStringForRegExp(string) { | 134 String quoteStringForRegExp(string) { |
| 138 return JS('String', r'#.replace(/[[\]{}()*+?.\\^$|]/g, "\\$&")', string); | 135 return JS('String', r'#.replace(/[[\]{}()*+?.\\^$|]/g, "\\$&")', string); |
| 139 } | 136 } |
| 140 | 137 |
| 141 String stringReplaceAllUnchecked( | 138 String stringReplaceAllUnchecked( |
| 142 String receiver, Pattern pattern, String replacement) { | 139 String receiver, Pattern pattern, String replacement) { |
| 143 checkString(replacement); | 140 checkString(replacement); |
| 144 if (pattern is String) { | 141 if (pattern is String) { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 166 } else { | 163 } else { |
| 167 checkNull(pattern); | 164 checkNull(pattern); |
| 168 // TODO(floitsch): implement generic String.replace (with patterns). | 165 // TODO(floitsch): implement generic String.replace (with patterns). |
| 169 throw "String.replaceAll(Pattern) UNIMPLEMENTED"; | 166 throw "String.replaceAll(Pattern) UNIMPLEMENTED"; |
| 170 } | 167 } |
| 171 } | 168 } |
| 172 | 169 |
| 173 String _matchString(Match match) => match[0]; | 170 String _matchString(Match match) => match[0]; |
| 174 String _stringIdentity(String string) => string; | 171 String _stringIdentity(String string) => string; |
| 175 | 172 |
| 176 String stringReplaceAllFuncUnchecked( | 173 String stringReplaceAllFuncUnchecked(String receiver, Pattern pattern, |
| 177 String receiver, | 174 String onMatch(Match match), String onNonMatch(String nonMatch)) { |
| 178 Pattern pattern, | |
| 179 String onMatch(Match match), | |
| 180 String onNonMatch(String nonMatch)) { | |
| 181 if (onMatch == null) onMatch = _matchString; | 175 if (onMatch == null) onMatch = _matchString; |
| 182 if (onNonMatch == null) onNonMatch = _stringIdentity; | 176 if (onNonMatch == null) onNonMatch = _stringIdentity; |
| 183 if (pattern is String) { | 177 if (pattern is String) { |
| 184 return stringReplaceAllStringFuncUnchecked(receiver, pattern, | 178 return stringReplaceAllStringFuncUnchecked( |
| 185 onMatch, onNonMatch); | 179 receiver, pattern, onMatch, onNonMatch); |
| 186 } | 180 } |
| 187 // Placing the Pattern test here is indistingishable from placing it at the | 181 // 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` | 182 // top of the method but it saves an extra check on the `pattern is String` |
| 189 // path. | 183 // path. |
| 190 if (pattern is! Pattern) { | 184 if (pattern is! Pattern) { |
| 191 throw new ArgumentError.value(pattern, 'pattern', 'is not a Pattern'); | 185 throw new ArgumentError.value(pattern, 'pattern', 'is not a Pattern'); |
| 192 } | 186 } |
| 193 StringBuffer buffer = new StringBuffer(); | 187 StringBuffer buffer = new StringBuffer(); |
| 194 int startIndex = 0; | 188 int startIndex = 0; |
| 195 for (Match match in pattern.allMatches(receiver)) { | 189 for (Match match in pattern.allMatches(receiver)) { |
| 196 buffer.write(onNonMatch(receiver.substring(startIndex, match.start))); | 190 buffer.write(onNonMatch(receiver.substring(startIndex, match.start))); |
| 197 buffer.write(onMatch(match)); | 191 buffer.write(onMatch(match)); |
| 198 startIndex = match.end; | 192 startIndex = match.end; |
| 199 } | 193 } |
| 200 buffer.write(onNonMatch(receiver.substring(startIndex))); | 194 buffer.write(onNonMatch(receiver.substring(startIndex))); |
| 201 return buffer.toString(); | 195 return buffer.toString(); |
| 202 } | 196 } |
| 203 | 197 |
| 204 String stringReplaceAllEmptyFuncUnchecked(String receiver, | 198 String stringReplaceAllEmptyFuncUnchecked(String receiver, |
| 205 String onMatch(Match match), | 199 String onMatch(Match match), String onNonMatch(String nonMatch)) { |
| 206 String onNonMatch(String nonMatch)) { | |
| 207 // Pattern is the empty string. | 200 // Pattern is the empty string. |
| 208 StringBuffer buffer = new StringBuffer(); | 201 StringBuffer buffer = new StringBuffer(); |
| 209 int length = receiver.length; | 202 int length = receiver.length; |
| 210 int i = 0; | 203 int i = 0; |
| 211 buffer.write(onNonMatch("")); | 204 buffer.write(onNonMatch("")); |
| 212 while (i < length) { | 205 while (i < length) { |
| 213 buffer.write(onMatch(new StringMatch(i, receiver, ""))); | 206 buffer.write(onMatch(new StringMatch(i, receiver, ""))); |
| 214 // Special case to avoid splitting a surrogate pair. | 207 // Special case to avoid splitting a surrogate pair. |
| 215 int code = receiver.codeUnitAt(i); | 208 int code = receiver.codeUnitAt(i); |
| 216 if ((code & ~0x3FF) == 0xD800 && length > i + 1) { | 209 if ((code & ~0x3FF) == 0xD800 && length > i + 1) { |
| 217 // Leading surrogate; | 210 // Leading surrogate; |
| 218 code = receiver.codeUnitAt(i + 1); | 211 code = receiver.codeUnitAt(i + 1); |
| 219 if ((code & ~0x3FF) == 0xDC00) { | 212 if ((code & ~0x3FF) == 0xDC00) { |
| 220 // Matching trailing surrogate. | 213 // Matching trailing surrogate. |
| 221 buffer.write(onNonMatch(receiver.substring(i, i + 2))); | 214 buffer.write(onNonMatch(receiver.substring(i, i + 2))); |
| 222 i += 2; | 215 i += 2; |
| 223 continue; | 216 continue; |
| 224 } | 217 } |
| 225 } | 218 } |
| 226 buffer.write(onNonMatch(receiver[i])); | 219 buffer.write(onNonMatch(receiver[i])); |
| 227 i++; | 220 i++; |
| 228 } | 221 } |
| 229 buffer.write(onMatch(new StringMatch(i, receiver, ""))); | 222 buffer.write(onMatch(new StringMatch(i, receiver, ""))); |
| 230 buffer.write(onNonMatch("")); | 223 buffer.write(onNonMatch("")); |
| 231 return buffer.toString(); | 224 return buffer.toString(); |
| 232 } | 225 } |
| 233 | 226 |
| 234 String stringReplaceAllStringFuncUnchecked( | 227 String stringReplaceAllStringFuncUnchecked(String receiver, String pattern, |
| 235 String receiver, | 228 String onMatch(Match match), String onNonMatch(String nonMatch)) { |
| 236 String pattern, | |
| 237 String onMatch(Match match), | |
| 238 String onNonMatch(String nonMatch)) { | |
| 239 int patternLength = pattern.length; | 229 int patternLength = pattern.length; |
| 240 if (patternLength == 0) { | 230 if (patternLength == 0) { |
| 241 return stringReplaceAllEmptyFuncUnchecked(receiver, onMatch, onNonMatch); | 231 return stringReplaceAllEmptyFuncUnchecked(receiver, onMatch, onNonMatch); |
| 242 } | 232 } |
| 243 int length = receiver.length; | 233 int length = receiver.length; |
| 244 StringBuffer buffer = new StringBuffer(); | 234 StringBuffer buffer = new StringBuffer(); |
| 245 int startIndex = 0; | 235 int startIndex = 0; |
| 246 while (startIndex < length) { | 236 while (startIndex < length) { |
| 247 int position = stringIndexOfStringUnchecked(receiver, pattern, startIndex); | 237 int position = stringIndexOfStringUnchecked(receiver, pattern, startIndex); |
| 248 if (position == -1) { | 238 if (position == -1) { |
| 249 break; | 239 break; |
| 250 } | 240 } |
| 251 buffer.write(onNonMatch(receiver.substring(startIndex, position))); | 241 buffer.write(onNonMatch(receiver.substring(startIndex, position))); |
| 252 buffer.write(onMatch(new StringMatch(position, receiver, pattern))); | 242 buffer.write(onMatch(new StringMatch(position, receiver, pattern))); |
| 253 startIndex = position + patternLength; | 243 startIndex = position + patternLength; |
| 254 } | 244 } |
| 255 buffer.write(onNonMatch(receiver.substring(startIndex))); | 245 buffer.write(onNonMatch(receiver.substring(startIndex))); |
| 256 return buffer.toString(); | 246 return buffer.toString(); |
| 257 } | 247 } |
| 258 | 248 |
| 259 | |
| 260 String stringReplaceFirstUnchecked( | 249 String stringReplaceFirstUnchecked( |
| 261 String receiver, Pattern pattern, String replacement, int startIndex) { | 250 String receiver, Pattern pattern, String replacement, int startIndex) { |
| 262 if (pattern is String) { | 251 if (pattern is String) { |
| 263 int index = stringIndexOfStringUnchecked(receiver, pattern, startIndex); | 252 int index = stringIndexOfStringUnchecked(receiver, pattern, startIndex); |
| 264 if (index < 0) return receiver; | 253 if (index < 0) return receiver; |
| 265 int end = index + pattern.length; | 254 int end = index + pattern.length; |
| 266 return stringReplaceRangeUnchecked(receiver, index, end, replacement); | 255 return stringReplaceRangeUnchecked(receiver, index, end, replacement); |
| 267 } | 256 } |
| 268 if (pattern is JSSyntaxRegExp) { | 257 if (pattern is JSSyntaxRegExp) { |
| 269 return startIndex == 0 | 258 return startIndex == 0 |
| 270 ? stringReplaceJS(receiver, regExpGetNative(pattern), replacement) | 259 ? stringReplaceJS(receiver, regExpGetNative(pattern), replacement) |
| 271 : stringReplaceFirstRE(receiver, pattern, replacement, startIndex); | 260 : stringReplaceFirstRE(receiver, pattern, replacement, startIndex); |
| 272 } | 261 } |
| 273 checkNull(pattern); | 262 checkNull(pattern); |
| 274 Iterator<Match> matches = pattern.allMatches(receiver, startIndex).iterator; | 263 Iterator<Match> matches = pattern.allMatches(receiver, startIndex).iterator; |
| 275 if (!matches.moveNext()) return receiver; | 264 if (!matches.moveNext()) return receiver; |
| 276 Match match = matches.current; | 265 Match match = matches.current; |
| 277 return receiver.replaceRange(match.start, match.end, replacement); | 266 return receiver.replaceRange(match.start, match.end, replacement); |
| 278 } | 267 } |
| 279 | 268 |
| 280 String stringReplaceFirstMappedUnchecked( | 269 String stringReplaceFirstMappedUnchecked(String receiver, Pattern pattern, |
| 281 String receiver, | 270 String replace(Match current), int startIndex) { |
| 282 Pattern pattern, | |
| 283 String replace(Match current), | |
| 284 int startIndex) { | |
| 285 Iterator<Match> matches = pattern.allMatches(receiver, startIndex).iterator; | 271 Iterator<Match> matches = pattern.allMatches(receiver, startIndex).iterator; |
| 286 if (!matches.moveNext()) return receiver; | 272 if (!matches.moveNext()) return receiver; |
| 287 Match match = matches.current; | 273 Match match = matches.current; |
| 288 String replacement = "${replace(match)}"; | 274 String replacement = "${replace(match)}"; |
| 289 return receiver.replaceRange(match.start, match.end, replacement); | 275 return receiver.replaceRange(match.start, match.end, replacement); |
| 290 } | 276 } |
| 291 | 277 |
| 292 String stringJoinUnchecked(array, separator) { | 278 String stringJoinUnchecked(array, separator) { |
| 293 return JS('String', r'#.join(#)', array, separator); | 279 return JS('String', r'#.join(#)', array, separator); |
| 294 } | 280 } |
| 295 | 281 |
| 296 String stringReplaceRangeUnchecked(String receiver, | 282 String stringReplaceRangeUnchecked( |
| 297 int start, int end, String replacement) { | 283 String receiver, int start, int end, String replacement) { |
| 298 var prefix = JS('String', '#.substring(0, #)', receiver, start); | 284 var prefix = JS('String', '#.substring(0, #)', receiver, start); |
| 299 var suffix = JS('String', '#.substring(#)', receiver, end); | 285 var suffix = JS('String', '#.substring(#)', receiver, end); |
| 300 return "$prefix$replacement$suffix"; | 286 return "$prefix$replacement$suffix"; |
| 301 } | 287 } |
| OLD | NEW |