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

Unified 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 side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tool/input_sdk/private/string_helper.dart
diff --git a/tool/input_sdk/private/string_helper.dart b/tool/input_sdk/private/string_helper.dart
index 85383c6b9512cea2d2bf2773a70c08916507b392..e97448a23af431a9d4f498823e0d5e951a3159f3 100644
--- a/tool/input_sdk/private/string_helper.dart
+++ b/tool/input_sdk/private/string_helper.dart
@@ -4,6 +4,22 @@
part of dart._js_helper;
+int stringIndexOfStringUnchecked(receiver, other, startIndex) {
+ return JS('int', '#.indexOf(#, #)', receiver, other, startIndex);
+}
+
+String substring1Unchecked(receiver, startIndex) {
+ return JS('String', '#.substring(#)', receiver, startIndex);
+}
+
+String substring2Unchecked(receiver, startIndex, endIndex) {
+ return JS('String', '#.substring(#, #)', receiver, startIndex, endIndex);
+}
+
+bool stringContainsStringUnchecked(receiver, other, startIndex) {
+ return stringIndexOfStringUnchecked(receiver, other, startIndex) >= 0;
+}
+
class StringMatch implements Match {
const StringMatch(int this.start,
String this.input,
@@ -33,34 +49,63 @@ class StringMatch implements Match {
final String pattern;
}
-List<Match> allMatchesInStringUnchecked(String needle, String haystack,
- int startIndex) {
- // Copied from StringBase.allMatches in
- // /runtime/lib/string_base.dart
- List<Match> result = new List<Match>();
- int length = haystack.length;
- int patternLength = needle.length;
- while (true) {
- int position = haystack.indexOf(needle, startIndex);
- if (position == -1) {
- break;
+Iterable<Match> allMatchesInStringUnchecked(String pattern, String string,
+ int startIndex) {
+ return new _StringAllMatchesIterable(string, pattern, startIndex);
+}
+
+class _StringAllMatchesIterable extends IterableBase<Match> {
+ final String _input;
+ final String _pattern;
+ final int _index;
+
+ _StringAllMatchesIterable(this._input, this._pattern, this._index);
+
+ Iterator<Match> get iterator =>
+ new _StringAllMatchesIterator(_input, _pattern, _index);
+
+ Match get first {
+ int index = stringIndexOfStringUnchecked(_input, _pattern, _index);
+ if (index >= 0) {
+ return new StringMatch(index, _input, _pattern);
}
- result.add(new StringMatch(position, haystack, needle));
- int endIndex = position + patternLength;
- if (endIndex == length) {
- break;
- } else if (position == endIndex) {
- ++startIndex; // empty match, advance and restart
- } else {
- startIndex = endIndex;
+ throw IterableElementError.noElement();
+ }
+}
+
+class _StringAllMatchesIterator implements Iterator<Match> {
+ final String _input;
+ final String _pattern;
+ int _index;
+ Match _current;
+
+ _StringAllMatchesIterator(this._input, this._pattern, this._index);
+
+ bool moveNext() {
+ if (_index + _pattern.length > _input.length) {
+ _current = null;
+ return false;
+ }
+ var index = stringIndexOfStringUnchecked(_input, _pattern, _index);
+ if (index < 0) {
+ _index = _input.length + 1;
+ _current = null;
+ return false;
}
+ int end = index + _pattern.length;
+ _current = new StringMatch(index, _input, _pattern);
+ // Empty match, don't start at same location again.
+ if (end == _index) end++;
+ _index = end;
+ return true;
}
- return result;
+
+ Match get current => _current;
}
-stringContainsUnchecked(receiver, other, startIndex) {
+bool stringContainsUnchecked(String receiver, other, int startIndex) {
if (other is String) {
- return receiver.indexOf(other, startIndex) != -1;
+ return stringContainsStringUnchecked(receiver, other, startIndex);
} else if (other is JSSyntaxRegExp) {
return other.hasMatch(receiver.substring(startIndex));
} else {
@@ -69,51 +114,57 @@ stringContainsUnchecked(receiver, other, startIndex) {
}
}
-stringReplaceJS(receiver, replacer, to) {
+String stringReplaceJS(receiver, replacer, replacement) {
// The JavaScript String.replace method recognizes replacement
// patterns in the replacement string. Dart does not have that
// behavior.
- to = JS('String', r'#.replace(/\$/g, "$$$$")', to);
- return JS('String', r'#.replace(#, #)', receiver, replacer, to);
+ replacement = JS('String', r'#.replace(/\$/g, "$$$$")', replacement);
+ return JS('String', r'#.replace(#, #)', receiver, replacer, replacement);
}
-stringReplaceFirstRE(receiver, regexp, to, startIndex) {
+String stringReplaceFirstRE(String receiver,
+ JSSyntaxRegExp regexp, String replacement, int startIndex) {
var match = regexp._execGlobal(receiver, startIndex);
if (match == null) return receiver;
var start = match.start;
var end = match.end;
- return "${receiver.substring(0,start)}$to${receiver.substring(end)}";
+ return stringReplaceRangeUnchecked(receiver, start, end, replacement);
}
-const String ESCAPE_REGEXP = r'[[\]{}()*+?.\\^$|]';
-stringReplaceAllUnchecked(receiver, from, to) {
- checkString(to);
- if (from is String) {
- if (from == "") {
+/// Returns a string for a RegExp pattern that matches [string]. This is done by
+/// escaping all RegExp metacharacters.
+String quoteStringForRegExp(string) {
+ return JS('String', r'#.replace(/[[\]{}()*+?.\\^$|]/g, "\\$&")', string);
+}
+
+String stringReplaceAllUnchecked(
+ String receiver, Pattern pattern, String replacement) {
+ checkString(replacement);
+ if (pattern is String) {
+ if (pattern == "") {
if (receiver == "") {
- return to;
+ return replacement;
} else {
StringBuffer result = new StringBuffer();
int length = receiver.length;
- result.write(to);
+ result.write(replacement);
for (int i = 0; i < length; i++) {
result.write(receiver[i]);
- result.write(to);
+ result.write(replacement);
}
return result.toString();
}
} else {
- var quoter = JS('', "new RegExp(#, 'g')", ESCAPE_REGEXP);
- var quoted = JS('String', r'#.replace(#, "\\$&")', from, quoter);
+ var quoted = quoteStringForRegExp(pattern);
var replacer = JS('', "new RegExp(#, 'g')", quoted);
- return stringReplaceJS(receiver, replacer, to);
+ return stringReplaceJS(receiver, replacer, replacement);
}
- } else if (from is JSSyntaxRegExp) {
- var re = regExpGetGlobalNative(from);
- return stringReplaceJS(receiver, re, to);
+ } else if (pattern is JSSyntaxRegExp) {
+ var re = regExpGetGlobalNative(pattern);
+ return stringReplaceJS(receiver, re, replacement);
} else {
- checkNull(from);
+ checkNull(pattern);
// TODO(floitsch): implement generic String.replace (with patterns).
throw "String.replaceAll(Pattern) UNIMPLEMENTED";
}
@@ -122,16 +173,23 @@ stringReplaceAllUnchecked(receiver, from, to) {
String _matchString(Match match) => match[0];
String _stringIdentity(String string) => string;
-stringReplaceAllFuncUnchecked(receiver, pattern, onMatch, onNonMatch) {
- if (pattern is! Pattern) {
- throw new ArgumentError("${pattern} is not a Pattern");
- }
+String stringReplaceAllFuncUnchecked(
+ String receiver,
+ Pattern pattern,
+ String onMatch(Match match),
+ String onNonMatch(String nonMatch)) {
if (onMatch == null) onMatch = _matchString;
if (onNonMatch == null) onNonMatch = _stringIdentity;
if (pattern is String) {
return stringReplaceAllStringFuncUnchecked(receiver, pattern,
onMatch, onNonMatch);
}
+ // Placing the Pattern test here is indistingishable from placing it at the
+ // top of the method but it saves an extra check on the `pattern is String`
+ // path.
+ if (pattern is! Pattern) {
+ throw new ArgumentError.value(pattern, 'pattern', 'is not a Pattern');
+ }
StringBuffer buffer = new StringBuffer();
int startIndex = 0;
for (Match match in pattern.allMatches(receiver)) {
@@ -143,7 +201,9 @@ stringReplaceAllFuncUnchecked(receiver, pattern, onMatch, onNonMatch) {
return buffer.toString();
}
-stringReplaceAllEmptyFuncUnchecked(receiver, onMatch, onNonMatch) {
+String stringReplaceAllEmptyFuncUnchecked(String receiver,
+ String onMatch(Match match),
+ String onNonMatch(String nonMatch)) {
// Pattern is the empty string.
StringBuffer buffer = new StringBuffer();
int length = receiver.length;
@@ -171,7 +231,11 @@ stringReplaceAllEmptyFuncUnchecked(receiver, onMatch, onNonMatch) {
return buffer.toString();
}
-stringReplaceAllStringFuncUnchecked(receiver, pattern, onMatch, onNonMatch) {
+String stringReplaceAllStringFuncUnchecked(
+ String receiver,
+ String pattern,
+ String onMatch(Match match),
+ String onNonMatch(String nonMatch)) {
int patternLength = pattern.length;
if (patternLength == 0) {
return stringReplaceAllEmptyFuncUnchecked(receiver, onMatch, onNonMatch);
@@ -180,7 +244,7 @@ stringReplaceAllStringFuncUnchecked(receiver, pattern, onMatch, onNonMatch) {
StringBuffer buffer = new StringBuffer();
int startIndex = 0;
while (startIndex < length) {
- int position = receiver.indexOf(pattern, startIndex);
+ int position = stringIndexOfStringUnchecked(receiver, pattern, startIndex);
if (position == -1) {
break;
}
@@ -193,23 +257,45 @@ stringReplaceAllStringFuncUnchecked(receiver, pattern, onMatch, onNonMatch) {
}
-stringReplaceFirstUnchecked(receiver, from, to, [int startIndex = 0]) {
- if (from is String) {
- var index = receiver.indexOf(from, startIndex);
+String stringReplaceFirstUnchecked(
+ String receiver, Pattern pattern, String replacement, int startIndex) {
+ if (pattern is String) {
+ int index = stringIndexOfStringUnchecked(receiver, pattern, startIndex);
if (index < 0) return receiver;
- return '${receiver.substring(0, index)}$to'
- '${receiver.substring(index + from.length)}';
- } else if (from is JSSyntaxRegExp) {
- return startIndex == 0 ?
- stringReplaceJS(receiver, regExpGetNative(from), to) :
- stringReplaceFirstRE(receiver, from, to, startIndex);
- } else {
- checkNull(from);
- // TODO(floitsch): implement generic String.replace (with patterns).
- throw "String.replace(Pattern) UNIMPLEMENTED";
+ int end = index + pattern.length;
+ return stringReplaceRangeUnchecked(receiver, index, end, replacement);
+ }
+ if (pattern is JSSyntaxRegExp) {
+ return startIndex == 0
+ ? stringReplaceJS(receiver, regExpGetNative(pattern), replacement)
+ : stringReplaceFirstRE(receiver, pattern, replacement, startIndex);
}
+ checkNull(pattern);
+ Iterator<Match> matches = pattern.allMatches(receiver, startIndex).iterator;
+ if (!matches.moveNext()) return receiver;
+ Match match = matches.current;
+ return receiver.replaceRange(match.start, match.end, replacement);
}
-stringJoinUnchecked(array, separator) {
+String stringReplaceFirstMappedUnchecked(
+ String receiver,
+ Pattern pattern,
+ String replace(Match current),
+ int startIndex) {
+ Iterator<Match> matches = pattern.allMatches(receiver, startIndex).iterator;
+ if (!matches.moveNext()) return receiver;
+ Match match = matches.current;
+ String replacement = "${replace(match)}";
+ return receiver.replaceRange(match.start, match.end, replacement);
+}
+
+String stringJoinUnchecked(array, separator) {
return JS('String', r'#.join(#)', array, separator);
}
+
+String stringReplaceRangeUnchecked(String receiver,
+ int start, int end, String replacement) {
+ var prefix = JS('String', '#.substring(0, #)', receiver, start);
+ var suffix = JS('String', '#.substring(#)', receiver, end);
+ return "$prefix$replacement$suffix";
+}
« 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