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 // Helper method used by internal libraries. | 7 // Helper method used by internal libraries. |
8 regExpGetNative(JSSyntaxRegExp regexp) => regexp._nativeRegExp; | 8 regExpGetNative(JSSyntaxRegExp regexp) => regexp._nativeRegExp; |
9 | 9 |
10 List<String> _stringList(List l) => l == null ? l : JS('', 'dart.list(#, #)', l,
String); | 10 List<String> _stringList(List l) => |
| 11 l == null ? l : JS('', 'dart.list(#, #)', l, String); |
11 | 12 |
12 /** | 13 /** |
13 * Returns a native version of the RegExp with the global flag set. | 14 * Returns a native version of the RegExp with the global flag set. |
14 * | 15 * |
15 * The RegExp's `lastIndex` property is zero when it is returned. | 16 * The RegExp's `lastIndex` property is zero when it is returned. |
16 * | 17 * |
17 * The returned regexp is shared, and its `lastIndex` property may be | 18 * The returned regexp is shared, and its `lastIndex` property may be |
18 * modified by other uses, so the returned regexp must be used immediately | 19 * modified by other uses, so the returned regexp must be used immediately |
19 * when it's returned, with no user-provided code run in between. | 20 * when it's returned, with no user-provided code run in between. |
20 */ | 21 */ |
(...skipping 23 matching lines...) Expand all Loading... |
44 | 45 |
45 class JSSyntaxRegExp implements RegExp { | 46 class JSSyntaxRegExp implements RegExp { |
46 final String pattern; | 47 final String pattern; |
47 final _nativeRegExp; | 48 final _nativeRegExp; |
48 var _nativeGlobalRegExp; | 49 var _nativeGlobalRegExp; |
49 var _nativeAnchoredRegExp; | 50 var _nativeAnchoredRegExp; |
50 | 51 |
51 String toString() => "RegExp/$pattern/"; | 52 String toString() => "RegExp/$pattern/"; |
52 | 53 |
53 JSSyntaxRegExp(String source, | 54 JSSyntaxRegExp(String source, |
54 { bool multiLine: false, | 55 {bool multiLine: false, bool caseSensitive: true}) |
55 bool caseSensitive: true }) | |
56 : this.pattern = source, | 56 : this.pattern = source, |
57 this._nativeRegExp = | 57 this._nativeRegExp = |
58 makeNative(source, multiLine, caseSensitive, false); | 58 makeNative(source, multiLine, caseSensitive, false); |
59 | 59 |
60 get _nativeGlobalVersion { | 60 get _nativeGlobalVersion { |
61 if (_nativeGlobalRegExp != null) return _nativeGlobalRegExp; | 61 if (_nativeGlobalRegExp != null) return _nativeGlobalRegExp; |
62 return _nativeGlobalRegExp = makeNative(pattern, | 62 return _nativeGlobalRegExp = |
63 _isMultiLine, | 63 makeNative(pattern, _isMultiLine, _isCaseSensitive, true); |
64 _isCaseSensitive, | |
65 true); | |
66 } | 64 } |
67 | 65 |
68 get _nativeAnchoredVersion { | 66 get _nativeAnchoredVersion { |
69 if (_nativeAnchoredRegExp != null) return _nativeAnchoredRegExp; | 67 if (_nativeAnchoredRegExp != null) return _nativeAnchoredRegExp; |
70 // An "anchored version" of a regexp is created by adding "|()" to the | 68 // An "anchored version" of a regexp is created by adding "|()" to the |
71 // source. This means that the regexp always matches at the first position | 69 // source. This means that the regexp always matches at the first position |
72 // that it tries, and you can see if the original regexp matched, or it | 70 // that it tries, and you can see if the original regexp matched, or it |
73 // was the added zero-width match that matched, by looking at the last | 71 // was the added zero-width match that matched, by looking at the last |
74 // capture. If it is a String, the match participated, otherwise it didn't. | 72 // capture. If it is a String, the match participated, otherwise it didn't. |
75 return _nativeAnchoredRegExp = makeNative("$pattern|()", | 73 return _nativeAnchoredRegExp = |
76 _isMultiLine, | 74 makeNative("$pattern|()", _isMultiLine, _isCaseSensitive, true); |
77 _isCaseSensitive, | |
78 true); | |
79 } | 75 } |
80 | 76 |
81 bool get _isMultiLine => JS("bool", "#.multiline", _nativeRegExp); | 77 bool get _isMultiLine => JS("bool", "#.multiline", _nativeRegExp); |
82 bool get _isCaseSensitive => JS("bool", "!#.ignoreCase", _nativeRegExp); | 78 bool get _isCaseSensitive => JS("bool", "!#.ignoreCase", _nativeRegExp); |
83 | 79 |
84 static makeNative( | 80 static makeNative( |
85 String source, bool multiLine, bool caseSensitive, bool global) { | 81 String source, bool multiLine, bool caseSensitive, bool global) { |
86 checkString(source); | 82 checkString(source); |
87 String m = multiLine ? 'm' : ''; | 83 String m = multiLine ? 'm' : ''; |
88 String i = caseSensitive ? '' : 'i'; | 84 String i = caseSensitive ? '' : 'i'; |
89 String g = global ? 'g' : ''; | 85 String g = global ? 'g' : ''; |
90 // We're using the JavaScript's try catch instead of the Dart one | 86 // We're using the JavaScript's try catch instead of the Dart one |
91 // to avoid dragging in Dart runtime support just because of using | 87 // to avoid dragging in Dart runtime support just because of using |
92 // RegExp. | 88 // RegExp. |
93 var regexp = JS('', | 89 var regexp = JS( |
| 90 '', |
94 '(function() {' | 91 '(function() {' |
95 'try {' | 92 'try {' |
96 'return new RegExp(#, # + # + #);' | 93 'return new RegExp(#, # + # + #);' |
97 '} catch (e) {' | 94 '} catch (e) {' |
98 'return e;' | 95 'return e;' |
99 '}' | 96 '}' |
100 '})()', source, m, i, g); | 97 '})()', |
| 98 source, |
| 99 m, |
| 100 i, |
| 101 g); |
101 if (JS('bool', '# instanceof RegExp', regexp)) return regexp; | 102 if (JS('bool', '# instanceof RegExp', regexp)) return regexp; |
102 // The returned value is the JavaScript exception. Turn it into a | 103 // The returned value is the JavaScript exception. Turn it into a |
103 // Dart exception. | 104 // Dart exception. |
104 String errorMessage = JS('String', r'String(#)', regexp); | 105 String errorMessage = JS('String', r'String(#)', regexp); |
105 throw new FormatException( | 106 throw new FormatException("Illegal RegExp pattern: $source, $errorMessage"); |
106 "Illegal RegExp pattern: $source, $errorMessage"); | |
107 } | 107 } |
108 | 108 |
109 Match firstMatch(String string) { | 109 Match firstMatch(String string) { |
110 List m = JS('JSExtendableArray|Null', | 110 List m = JS('JSExtendableArray|Null', r'#.exec(#)', _nativeRegExp, |
111 r'#.exec(#)', | 111 checkString(string)); |
112 _nativeRegExp, | |
113 checkString(string)); | |
114 if (m == null) return null; | 112 if (m == null) return null; |
115 return new _MatchImplementation(this, _stringList(m)); | 113 return new _MatchImplementation(this, _stringList(m)); |
116 } | 114 } |
117 | 115 |
118 bool hasMatch(String string) { | 116 bool hasMatch(String string) { |
119 return JS('bool', r'#.test(#)', _nativeRegExp, checkString(string)); | 117 return JS('bool', r'#.test(#)', _nativeRegExp, checkString(string)); |
120 } | 118 } |
121 | 119 |
122 String stringMatch(String string) { | 120 String stringMatch(String string) { |
123 var match = firstMatch(string); | 121 var match = firstMatch(string); |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
221 _current = match; | 219 _current = match; |
222 int nextIndex = match.end; | 220 int nextIndex = match.end; |
223 if (match.start == nextIndex) { | 221 if (match.start == nextIndex) { |
224 nextIndex++; | 222 nextIndex++; |
225 } | 223 } |
226 _nextIndex = nextIndex; | 224 _nextIndex = nextIndex; |
227 return true; | 225 return true; |
228 } | 226 } |
229 } | 227 } |
230 _current = null; | 228 _current = null; |
231 _string = null; // Marks iteration as ended. | 229 _string = null; // Marks iteration as ended. |
232 return false; | 230 return false; |
233 } | 231 } |
234 } | 232 } |
235 | 233 |
236 /** Find the first match of [regExp] in [string] at or after [start]. */ | 234 /** Find the first match of [regExp] in [string] at or after [start]. */ |
237 Match firstMatchAfter(JSSyntaxRegExp regExp, String string, int start) { | 235 Match firstMatchAfter(JSSyntaxRegExp regExp, String string, int start) { |
238 return regExp._execGlobal(string, start); | 236 return regExp._execGlobal(string, start); |
239 } | 237 } |
OLD | NEW |