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

Side by Side Diff: sdk/lib/_internal/compiler/js_lib/regexp_helper.dart

Issue 1212513002: sdk files reorganization to make dart2js a proper package (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: renamed Created 5 years, 5 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 _js_helper;
6
7 // Helper method used by internal libraries.
8 regExpGetNative(JSSyntaxRegExp regexp) => regexp._nativeRegExp;
9
10 /**
11 * Returns a native version of the RegExp with the global flag set.
12 *
13 * The RegExp's `lastIndex` property is zero when it is returned.
14 *
15 * The returned regexp is shared, and its `lastIndex` property may be
16 * modified by other uses, so the returned regexp must be used immediately
17 * when it's returned, with no user-provided code run in between.
18 */
19 regExpGetGlobalNative(JSSyntaxRegExp regexp) {
20 var nativeRegexp = regexp._nativeGlobalVersion;
21 JS("void", "#.lastIndex = 0", nativeRegexp);
22 return nativeRegexp;
23 }
24
25 /**
26 * Computes the number of captures in a regexp.
27 *
28 * This currently involves creating a new RegExp object with a different
29 * source and running it against the empty string (the last part is usually
30 * fast).
31 *
32 * The JSSyntaxRegExp could cache the result, and set the cache any time
33 * it finds a match.
34 */
35 int regExpCaptureCount(JSSyntaxRegExp regexp) {
36 var nativeAnchoredRegExp = regexp._nativeAnchoredVersion;
37 var match = JS('JSExtendableArray', "#.exec('')", nativeAnchoredRegExp);
38 // The native-anchored regexp always have one capture more than the original,
39 // and always matches the empty string.
40 return match.length - 2;
41 }
42
43 class JSSyntaxRegExp implements RegExp {
44 final String pattern;
45 final _nativeRegExp;
46 var _nativeGlobalRegExp;
47 var _nativeAnchoredRegExp;
48
49 String toString() => "RegExp/$pattern/";
50
51 JSSyntaxRegExp(String source,
52 { bool multiLine: false,
53 bool caseSensitive: true })
54 : this.pattern = source,
55 this._nativeRegExp =
56 makeNative(source, multiLine, caseSensitive, false);
57
58 get _nativeGlobalVersion {
59 if (_nativeGlobalRegExp != null) return _nativeGlobalRegExp;
60 return _nativeGlobalRegExp = makeNative(pattern,
61 _isMultiLine,
62 _isCaseSensitive,
63 true);
64 }
65
66 get _nativeAnchoredVersion {
67 if (_nativeAnchoredRegExp != null) return _nativeAnchoredRegExp;
68 // An "anchored version" of a regexp is created by adding "|()" to the
69 // source. This means that the regexp always matches at the first position
70 // that it tries, and you can see if the original regexp matched, or it
71 // was the added zero-width match that matched, by looking at the last
72 // capture. If it is a String, the match participated, otherwise it didn't.
73 return _nativeAnchoredRegExp = makeNative("$pattern|()",
74 _isMultiLine,
75 _isCaseSensitive,
76 true);
77 }
78
79 bool get _isMultiLine => JS("bool", "#.multiline", _nativeRegExp);
80 bool get _isCaseSensitive => JS("bool", "!#.ignoreCase", _nativeRegExp);
81
82 static makeNative(
83 String source, bool multiLine, bool caseSensitive, bool global) {
84 checkString(source);
85 String m = multiLine ? 'm' : '';
86 String i = caseSensitive ? '' : 'i';
87 String g = global ? 'g' : '';
88 // We're using the JavaScript's try catch instead of the Dart one
89 // to avoid dragging in Dart runtime support just because of using
90 // RegExp.
91 var regexp = JS('',
92 '(function() {'
93 'try {'
94 'return new RegExp(#, # + # + #);'
95 '} catch (e) {'
96 'return e;'
97 '}'
98 '})()', source, m, i, g);
99 if (JS('bool', '# instanceof RegExp', regexp)) return regexp;
100 // The returned value is the JavaScript exception. Turn it into a
101 // Dart exception.
102 String errorMessage = JS('String', r'String(#)', regexp);
103 throw new FormatException(
104 "Illegal RegExp pattern ($errorMessage)", source);
105 }
106
107 Match firstMatch(String string) {
108 List<String> m = JS('JSExtendableArray|Null',
109 r'#.exec(#)',
110 _nativeRegExp,
111 checkString(string));
112 if (m == null) return null;
113 return new _MatchImplementation(this, m);
114 }
115
116 bool hasMatch(String string) {
117 return JS('bool', r'#.test(#)', _nativeRegExp, checkString(string));
118 }
119
120 String stringMatch(String string) {
121 var match = firstMatch(string);
122 if (match != null) return match.group(0);
123 return null;
124 }
125
126 Iterable<Match> allMatches(String string, [int start = 0]) {
127 checkString(string);
128 checkInt(start);
129 if (start < 0 || start > string.length) {
130 throw new RangeError.range(start, 0, string.length);
131 }
132 return new _AllMatchesIterable(this, string, start);
133 }
134
135 Match _execGlobal(String string, int start) {
136 Object regexp = _nativeGlobalVersion;
137 JS("void", "#.lastIndex = #", regexp, start);
138 List match = JS("JSExtendableArray|Null", "#.exec(#)", regexp, string);
139 if (match == null) return null;
140 return new _MatchImplementation(this, match);
141 }
142
143 Match _execAnchored(String string, int start) {
144 Object regexp = _nativeAnchoredVersion;
145 JS("void", "#.lastIndex = #", regexp, start);
146 List match = JS("JSExtendableArray|Null", "#.exec(#)", regexp, string);
147 if (match == null) return null;
148 // If the last capture group participated, the original regexp did not
149 // match at the start position.
150 if (match[match.length - 1] != null) return null;
151 match.length -= 1;
152 return new _MatchImplementation(this, match);
153 }
154
155 Match matchAsPrefix(String string, [int start = 0]) {
156 if (start < 0 || start > string.length) {
157 throw new RangeError.range(start, 0, string.length);
158 }
159 return _execAnchored(string, start);
160 }
161
162 bool get isMultiLine => _isMultiLine;
163 bool get isCaseSensitive => _isCaseSensitive;
164 }
165
166 class _MatchImplementation implements Match {
167 final Pattern pattern;
168 // Contains a JS RegExp match object.
169 // It is an Array of String values with extra "index" and "input" properties.
170 final List<String> _match;
171
172 _MatchImplementation(this.pattern, this._match) {
173 assert(JS("var", "#.input", _match) is String);
174 assert(JS("var", "#.index", _match) is int);
175 }
176
177 String get input => JS("String", "#.input", _match);
178 int get start => JS("int", "#.index", _match);
179 int get end => start + _match[0].length;
180
181 String group(int index) => _match[index];
182 String operator [](int index) => group(index);
183 int get groupCount => _match.length - 1;
184
185 List<String> groups(List<int> groups) {
186 List<String> out = [];
187 for (int i in groups) {
188 out.add(group(i));
189 }
190 return out;
191 }
192 }
193
194 class _AllMatchesIterable extends IterableBase<Match> {
195 final JSSyntaxRegExp _re;
196 final String _string;
197 final int _start;
198
199 _AllMatchesIterable(this._re, this._string, this._start);
200
201 Iterator<Match> get iterator => new _AllMatchesIterator(_re, _string, _start);
202 }
203
204 class _AllMatchesIterator implements Iterator<Match> {
205 final JSSyntaxRegExp _regExp;
206 String _string;
207 int _nextIndex;
208 Match _current;
209
210 _AllMatchesIterator(this._regExp, this._string, this._nextIndex);
211
212 Match get current => _current;
213
214 bool moveNext() {
215 if (_string == null) return false;
216 if (_nextIndex <= _string.length) {
217 var match = _regExp._execGlobal(_string, _nextIndex);
218 if (match != null) {
219 _current = match;
220 int nextIndex = match.end;
221 if (match.start == nextIndex) {
222 nextIndex++;
223 }
224 _nextIndex = nextIndex;
225 return true;
226 }
227 }
228 _current = null;
229 _string = null; // Marks iteration as ended.
230 return false;
231 }
232 }
233
234 /** Find the first match of [regExp] in [string] at or after [start]. */
235 Match firstMatchAfter(JSSyntaxRegExp regExp, String string, int start) {
236 return regExp._execGlobal(string, start);
237 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698