author | sundar |
Mon, 11 Feb 2013 21:26:06 +0530 | |
changeset 16226 | 0e4f37e6cc40 |
parent 16223 | dff592a332a4 |
child 16240 | e1468b33e201 |
permissions | -rw-r--r-- |
16147 | 1 |
/* |
16151 | 2 |
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. |
16147 | 3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
7 |
* published by the Free Software Foundation. Oracle designates this |
|
8 |
* particular file as subject to the "Classpath" exception as provided |
|
9 |
* by Oracle in the LICENSE file that accompanied this code. |
|
10 |
* |
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
24 |
*/ |
|
25 |
||
26 |
package jdk.nashorn.internal.objects; |
|
27 |
||
28 |
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; |
|
29 |
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; |
|
30 |
||
31 |
import java.util.ArrayList; |
|
32 |
import java.util.Arrays; |
|
33 |
import java.util.List; |
|
34 |
import java.util.regex.Matcher; |
|
35 |
import java.util.regex.Pattern; |
|
36 |
import jdk.nashorn.internal.objects.annotations.Attribute; |
|
37 |
import jdk.nashorn.internal.objects.annotations.Constructor; |
|
38 |
import jdk.nashorn.internal.objects.annotations.Function; |
|
39 |
import jdk.nashorn.internal.objects.annotations.Getter; |
|
40 |
import jdk.nashorn.internal.objects.annotations.Property; |
|
41 |
import jdk.nashorn.internal.objects.annotations.ScriptClass; |
|
42 |
import jdk.nashorn.internal.objects.annotations.SpecializedConstructor; |
|
16223
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
43 |
import jdk.nashorn.internal.objects.annotations.Where; |
16147 | 44 |
import jdk.nashorn.internal.runtime.BitVector; |
45 |
import jdk.nashorn.internal.runtime.JSType; |
|
46 |
import jdk.nashorn.internal.runtime.ParserException; |
|
16226
0e4f37e6cc40
8007915: Nashorn IR, codegen, parser packages and Context instance should be inaccessible to user code
sundar
parents:
16223
diff
changeset
|
47 |
import jdk.nashorn.internal.runtime.RegExp; |
16147 | 48 |
import jdk.nashorn.internal.runtime.RegExpMatch; |
49 |
import jdk.nashorn.internal.runtime.ScriptFunction; |
|
50 |
import jdk.nashorn.internal.runtime.ScriptObject; |
|
51 |
import jdk.nashorn.internal.runtime.ScriptRuntime; |
|
52 |
||
53 |
/** |
|
54 |
* ECMA 15.10 RegExp Objects. |
|
55 |
*/ |
|
56 |
@ScriptClass("RegExp") |
|
57 |
public final class NativeRegExp extends ScriptObject { |
|
58 |
/** ECMA 15.10.7.5 lastIndex property */ |
|
59 |
@Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE) |
|
60 |
public Object lastIndex; |
|
61 |
||
62 |
/** Pattern string. */ |
|
63 |
private String input; |
|
64 |
||
65 |
/** Global search flag for this regexp. */ |
|
66 |
private boolean global; |
|
67 |
||
68 |
/** Case insensitive flag for this regexp */ |
|
69 |
private boolean ignoreCase; |
|
70 |
||
71 |
/** Multi-line flag for this regexp */ |
|
72 |
private boolean multiline; |
|
73 |
||
74 |
/** Java regex pattern to use for match. We compile to one of these */ |
|
75 |
private Pattern pattern; |
|
76 |
||
77 |
private BitVector groupsInNegativeLookahead; |
|
78 |
||
16223
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
79 |
// Reference to global object needed to support static RegExp properties |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
80 |
private Global globalObject; |
16217
c5ac9be5c444
8007619: Add support for deprecated properties of RegExp constructor
sundar
parents:
16214
diff
changeset
|
81 |
|
16147 | 82 |
/* |
83 |
public NativeRegExp() { |
|
84 |
init(); |
|
85 |
}*/ |
|
86 |
||
87 |
NativeRegExp(final String input, final String flagString) { |
|
88 |
RegExp regExp = null; |
|
89 |
try { |
|
90 |
regExp = new RegExp(input, flagString); |
|
91 |
} catch (final ParserException e) { |
|
92 |
// translate it as SyntaxError object and throw it |
|
16188 | 93 |
e.throwAsEcmaException(); |
16147 | 94 |
throw new AssertionError(); //guard against null warnings below |
95 |
} |
|
96 |
||
97 |
this.setLastIndex(0); |
|
98 |
this.input = regExp.getInput(); |
|
99 |
this.global = regExp.isGlobal(); |
|
100 |
this.ignoreCase = regExp.isIgnoreCase(); |
|
101 |
this.multiline = regExp.isMultiline(); |
|
102 |
this.pattern = regExp.getPattern(); |
|
103 |
this.groupsInNegativeLookahead = regExp.getGroupsInNegativeLookahead(); |
|
104 |
||
105 |
init(); |
|
106 |
} |
|
107 |
||
108 |
NativeRegExp(final String string) { |
|
109 |
this(string, ""); |
|
110 |
} |
|
111 |
||
112 |
NativeRegExp(final NativeRegExp regExp) { |
|
113 |
this.input = regExp.getInput(); |
|
114 |
this.global = regExp.getGlobal(); |
|
115 |
this.multiline = regExp.getMultiline(); |
|
116 |
this.ignoreCase = regExp.getIgnoreCase(); |
|
117 |
this.lastIndex = regExp.getLastIndexObject(); |
|
118 |
this.pattern = regExp.getPattern(); |
|
119 |
this.groupsInNegativeLookahead = regExp.getGroupsInNegativeLookahead(); |
|
120 |
||
121 |
init(); |
|
122 |
} |
|
123 |
||
124 |
NativeRegExp(final Pattern pattern) { |
|
125 |
this.input = pattern.pattern(); |
|
126 |
this.multiline = (pattern.flags() & Pattern.MULTILINE) != 0; |
|
127 |
this.ignoreCase = (pattern.flags() & Pattern.CASE_INSENSITIVE) != 0; |
|
128 |
this.lastIndex = 0; |
|
129 |
this.pattern = pattern; |
|
130 |
||
131 |
init(); |
|
132 |
} |
|
133 |
||
134 |
@Override |
|
135 |
public String getClassName() { |
|
136 |
return "RegExp"; |
|
137 |
} |
|
138 |
||
139 |
/** |
|
140 |
* ECMA 15.10.4 |
|
141 |
* |
|
142 |
* Constructor |
|
143 |
* |
|
144 |
* @param isNew is the new operator used for instantiating this regexp |
|
145 |
* @param self self reference |
|
146 |
* @param args arguments (optional: pattern and flags) |
|
147 |
* @return new NativeRegExp |
|
148 |
*/ |
|
149 |
@Constructor(arity = 2) |
|
150 |
public static Object constructor(final boolean isNew, final Object self, final Object... args) { |
|
151 |
if (args.length > 1) { |
|
152 |
return newRegExp(args[0], args[1]); |
|
153 |
} else if (args.length > 0) { |
|
154 |
return newRegExp(args[0], UNDEFINED); |
|
155 |
} |
|
156 |
||
157 |
return newRegExp(UNDEFINED, UNDEFINED); |
|
158 |
} |
|
159 |
||
160 |
/** |
|
161 |
* ECMA 15.10.4 |
|
162 |
* |
|
163 |
* Constructor - specialized version, no args, empty regexp |
|
164 |
* |
|
165 |
* @param isNew is the new operator used for instantiating this regexp |
|
166 |
* @param self self reference |
|
167 |
* @return new NativeRegExp |
|
168 |
*/ |
|
169 |
@SpecializedConstructor |
|
170 |
public static Object constructor(final boolean isNew, final Object self) { |
|
171 |
return new NativeRegExp("", ""); |
|
172 |
} |
|
173 |
||
174 |
/** |
|
175 |
* ECMA 15.10.4 |
|
176 |
* |
|
177 |
* Constructor - specialized version, pattern, no flags |
|
178 |
* |
|
179 |
* @param isNew is the new operator used for instantiating this regexp |
|
180 |
* @param self self reference |
|
181 |
* @param pattern pattern |
|
182 |
* @return new NativeRegExp |
|
183 |
*/ |
|
184 |
@SpecializedConstructor |
|
185 |
public static Object constructor(final boolean isNew, final Object self, final Object pattern) { |
|
186 |
return newRegExp(pattern, UNDEFINED); |
|
187 |
} |
|
188 |
||
189 |
/** |
|
190 |
* ECMA 15.10.4 |
|
191 |
* |
|
192 |
* Constructor - specialized version, pattern and flags |
|
193 |
* |
|
194 |
* @param isNew is the new operator used for instantiating this regexp |
|
195 |
* @param self self reference |
|
196 |
* @param pattern pattern |
|
197 |
* @param flags flags |
|
198 |
* @return new NativeRegExp |
|
199 |
*/ |
|
200 |
@SpecializedConstructor |
|
201 |
public static Object constructor(final boolean isNew, final Object self, final Object pattern, final Object flags) { |
|
202 |
return newRegExp(pattern, flags); |
|
203 |
} |
|
204 |
||
205 |
/** |
|
206 |
* External constructor used in generated code created by {@link jdk.nashorn.internal.codegen.CodeGenerator}, which |
|
207 |
* explain the {@code public} access. |
|
208 |
* |
|
209 |
* @param regexp regexp |
|
210 |
* @param flags flags |
|
211 |
* @return new NativeRegExp |
|
212 |
*/ |
|
213 |
public static NativeRegExp newRegExp(final Object regexp, final Object flags) { |
|
214 |
String patternString = ""; |
|
215 |
String flagString = ""; |
|
216 |
boolean flagsDefined = false; |
|
217 |
||
218 |
if (flags != UNDEFINED) { |
|
219 |
flagsDefined = true; |
|
220 |
flagString = JSType.toString(flags); |
|
221 |
} |
|
222 |
||
223 |
if (regexp != UNDEFINED) { |
|
224 |
if (regexp instanceof NativeRegExp) { |
|
225 |
if (!flagsDefined) { |
|
226 |
return (NativeRegExp)regexp; // 15.10.3.1 - undefined flags and regexp as |
|
227 |
} |
|
16188 | 228 |
typeError("regex.cant.supply.flags"); |
16147 | 229 |
} |
230 |
patternString = JSType.toString(regexp); |
|
231 |
} |
|
232 |
||
233 |
return new NativeRegExp(patternString, flagString); |
|
234 |
} |
|
235 |
||
236 |
private String getFlagString() { |
|
237 |
final StringBuilder sb = new StringBuilder(); |
|
238 |
||
239 |
if (global) { |
|
240 |
sb.append('g'); |
|
241 |
} |
|
242 |
if (ignoreCase) { |
|
243 |
sb.append('i'); |
|
244 |
} |
|
245 |
if (multiline) { |
|
246 |
sb.append('m'); |
|
247 |
} |
|
248 |
||
249 |
return sb.toString(); |
|
250 |
} |
|
251 |
||
252 |
@Override |
|
253 |
public String safeToString() { |
|
254 |
return "[RegExp " + toString() + "]"; |
|
255 |
} |
|
256 |
||
257 |
@Override |
|
258 |
public String toString() { |
|
259 |
return "/" + input + "/" + getFlagString(); |
|
260 |
} |
|
261 |
||
262 |
/** |
|
263 |
* Nashorn extension: RegExp.prototype.compile - everybody implements this! |
|
264 |
* |
|
265 |
* @param self self reference |
|
266 |
* @param pattern pattern |
|
267 |
* @param flags flags |
|
268 |
* @return new NativeRegExp |
|
269 |
*/ |
|
270 |
@Function(attributes = Attribute.NOT_ENUMERABLE) |
|
271 |
public static Object compile(final Object self, final Object pattern, final Object flags) { |
|
272 |
final NativeRegExp regExp = checkRegExp(self); |
|
273 |
final NativeRegExp compiled = newRegExp(pattern, flags); |
|
274 |
// copy over fields to 'self' |
|
275 |
regExp.setInput(compiled.getInput()); |
|
276 |
regExp.setGlobal(compiled.getGlobal()); |
|
277 |
regExp.setIgnoreCase(compiled.getIgnoreCase()); |
|
278 |
regExp.setMultiline(compiled.getMultiline()); |
|
279 |
regExp.setPattern(compiled.getPattern()); |
|
280 |
regExp.setGroupsInNegativeLookahead(compiled.getGroupsInNegativeLookahead()); |
|
281 |
||
282 |
// Some implementations return undefined. Some return 'self'. Since return |
|
283 |
// value is most likely be ignored, we can play safe and return 'self'. |
|
284 |
return regExp; |
|
285 |
} |
|
286 |
||
287 |
/** |
|
288 |
* ECMA 15.10.6.2 RegExp.prototype.exec(string) |
|
289 |
* |
|
290 |
* @param self self reference |
|
291 |
* @param string string to match against regexp |
|
292 |
* @return array containing the matches or {@code null} if no match |
|
293 |
*/ |
|
294 |
@Function(attributes = Attribute.NOT_ENUMERABLE) |
|
295 |
public static Object exec(final Object self, final Object string) { |
|
296 |
return checkRegExp(self).exec(JSType.toString(string)); |
|
297 |
} |
|
298 |
||
299 |
/** |
|
300 |
* ECMA 15.10.6.3 RegExp.prototype.test(string) |
|
301 |
* |
|
302 |
* @param self self reference |
|
303 |
* @param string string to test for matches against regexp |
|
304 |
* @return true if matches found, false otherwise |
|
305 |
*/ |
|
306 |
@Function(attributes = Attribute.NOT_ENUMERABLE) |
|
307 |
public static Object test(final Object self, final Object string) { |
|
308 |
return checkRegExp(self).test(JSType.toString(string)); |
|
309 |
} |
|
310 |
||
311 |
/** |
|
312 |
* ECMA 15.10.6.4 RegExp.prototype.toString() |
|
313 |
* |
|
314 |
* @param self self reference |
|
315 |
* @return string version of regexp |
|
316 |
*/ |
|
317 |
@Function(attributes = Attribute.NOT_ENUMERABLE) |
|
318 |
public static Object toString(final Object self) { |
|
319 |
return checkRegExp(self).toString(); |
|
320 |
} |
|
321 |
||
322 |
/** |
|
323 |
* ECMA 15.10.7.1 source |
|
324 |
* |
|
325 |
* @param self self reference |
|
326 |
* @return the input string for the regexp |
|
327 |
*/ |
|
16223
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
328 |
@Getter(attributes = Attribute.NON_ENUMERABLE_CONSTANT) |
16147 | 329 |
public static Object source(final Object self) { |
330 |
return checkRegExp(self).input; |
|
331 |
} |
|
332 |
||
333 |
/** |
|
334 |
* ECMA 15.10.7.2 global |
|
335 |
* |
|
336 |
* @param self self reference |
|
337 |
* @return true if this regexp is flagged global, false otherwise |
|
338 |
*/ |
|
16223
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
339 |
@Getter(attributes = Attribute.NON_ENUMERABLE_CONSTANT) |
16147 | 340 |
public static Object global(final Object self) { |
341 |
return checkRegExp(self).global; |
|
342 |
} |
|
343 |
||
344 |
/** |
|
345 |
* ECMA 15.10.7.3 ignoreCase |
|
346 |
* |
|
347 |
* @param self self reference |
|
348 |
* @return true if this regexp if flagged to ignore case, false otherwise |
|
349 |
*/ |
|
16223
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
350 |
@Getter(attributes = Attribute.NON_ENUMERABLE_CONSTANT) |
16147 | 351 |
public static Object ignoreCase(final Object self) { |
352 |
return checkRegExp(self).ignoreCase; |
|
353 |
} |
|
354 |
||
355 |
/** |
|
356 |
* ECMA 15.10.7.4 multiline |
|
357 |
* |
|
358 |
* @param self self reference |
|
359 |
* @return true if this regexp is flagged to be multiline, false otherwise |
|
360 |
*/ |
|
16223
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
361 |
@Getter(attributes = Attribute.NON_ENUMERABLE_CONSTANT) |
16147 | 362 |
public static Object multiline(final Object self) { |
363 |
return checkRegExp(self).multiline; |
|
364 |
} |
|
365 |
||
16223
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
366 |
/** |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
367 |
* Getter for non-standard RegExp.input property. |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
368 |
* @param self self object |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
369 |
* @return last regexp input |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
370 |
*/ |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
371 |
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "input") |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
372 |
public static Object getLastInput(Object self) { |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
373 |
final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
374 |
return match == null ? "" : match.getInput(); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
375 |
} |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
376 |
|
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
377 |
/** |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
378 |
* Getter for non-standard RegExp.multiline property. |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
379 |
* @param self self object |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
380 |
* @return last regexp input |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
381 |
*/ |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
382 |
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "multiline") |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
383 |
public static Object getLastMultiline(Object self) { |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
384 |
return false; // doesn't ever seem to become true and isn't documented anyhwere |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
385 |
} |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
386 |
|
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
387 |
/** |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
388 |
* Getter for non-standard RegExp.lastMatch property. |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
389 |
* @param self self object |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
390 |
* @return last regexp input |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
391 |
*/ |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
392 |
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "lastMatch") |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
393 |
public static Object getLastMatch(Object self) { |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
394 |
final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
395 |
return match == null ? "" : match.getGroup(0); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
396 |
} |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
397 |
|
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
398 |
/** |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
399 |
* Getter for non-standard RegExp.lastParen property. |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
400 |
* @param self self object |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
401 |
* @return last regexp input |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
402 |
*/ |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
403 |
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "lastParen") |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
404 |
public static Object getLastParen(Object self) { |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
405 |
final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
406 |
return match == null ? "" : match.getLastParen(); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
407 |
} |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
408 |
|
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
409 |
/** |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
410 |
* Getter for non-standard RegExp.leftContext property. |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
411 |
* @param self self object |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
412 |
* @return last regexp input |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
413 |
*/ |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
414 |
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "leftContext") |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
415 |
public static Object getLeftContext(Object self) { |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
416 |
final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
417 |
return match == null ? "" : match.getInput().substring(0, match.getIndex()); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
418 |
} |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
419 |
|
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
420 |
/** |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
421 |
* Getter for non-standard RegExp.rightContext property. |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
422 |
* @param self self object |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
423 |
* @return last regexp input |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
424 |
*/ |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
425 |
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "rightContext") |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
426 |
public static Object getRightContext(Object self) { |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
427 |
final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
428 |
return match == null ? "" : match.getInput().substring(match.getIndex() + match.length()); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
429 |
} |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
430 |
|
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
431 |
/** |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
432 |
* Getter for non-standard RegExp.$1 property. |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
433 |
* @param self self object |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
434 |
* @return last regexp input |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
435 |
*/ |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
436 |
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$1") |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
437 |
public static Object getGroup1(Object self) { |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
438 |
final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
439 |
return match == null ? "" : match.getGroup(1); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
440 |
} |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
441 |
|
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
442 |
/** |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
443 |
* Getter for non-standard RegExp.$2 property. |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
444 |
* @param self self object |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
445 |
* @return last regexp input |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
446 |
*/ |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
447 |
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$2") |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
448 |
public static Object getGroup2(Object self) { |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
449 |
final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
450 |
return match == null ? "" : match.getGroup(2); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
451 |
} |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
452 |
|
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
453 |
/** |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
454 |
* Getter for non-standard RegExp.$3 property. |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
455 |
* @param self self object |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
456 |
* @return last regexp input |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
457 |
*/ |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
458 |
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$3") |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
459 |
public static Object getGroup3(Object self) { |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
460 |
final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
461 |
return match == null ? "" : match.getGroup(3); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
462 |
} |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
463 |
|
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
464 |
/** |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
465 |
* Getter for non-standard RegExp.$4 property. |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
466 |
* @param self self object |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
467 |
* @return last regexp input |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
468 |
*/ |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
469 |
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$4") |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
470 |
public static Object getGroup4(Object self) { |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
471 |
final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
472 |
return match == null ? "" : match.getGroup(4); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
473 |
} |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
474 |
|
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
475 |
/** |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
476 |
* Getter for non-standard RegExp.$5 property. |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
477 |
* @param self self object |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
478 |
* @return last regexp input |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
479 |
*/ |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
480 |
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$5") |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
481 |
public static Object getGroup5(Object self) { |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
482 |
final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
483 |
return match == null ? "" : match.getGroup(5); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
484 |
} |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
485 |
|
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
486 |
/** |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
487 |
* Getter for non-standard RegExp.$6 property. |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
488 |
* @param self self object |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
489 |
* @return last regexp input |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
490 |
*/ |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
491 |
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$6") |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
492 |
public static Object getGroup6(Object self) { |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
493 |
final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
494 |
return match == null ? "" : match.getGroup(6); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
495 |
} |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
496 |
|
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
497 |
/** |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
498 |
* Getter for non-standard RegExp.$7 property. |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
499 |
* @param self self object |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
500 |
* @return last regexp input |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
501 |
*/ |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
502 |
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$7") |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
503 |
public static Object getGroup7(Object self) { |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
504 |
final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
505 |
return match == null ? "" : match.getGroup(7); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
506 |
} |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
507 |
|
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
508 |
/** |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
509 |
* Getter for non-standard RegExp.$8 property. |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
510 |
* @param self self object |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
511 |
* @return last regexp input |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
512 |
*/ |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
513 |
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$8") |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
514 |
public static Object getGroup8(Object self) { |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
515 |
final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
516 |
return match == null ? "" : match.getGroup(8); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
517 |
} |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
518 |
|
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
519 |
/** |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
520 |
* Getter for non-standard RegExp.$9 property. |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
521 |
* @param self self object |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
522 |
* @return last regexp input |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
523 |
*/ |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
524 |
@Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$9") |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
525 |
public static Object getGroup9(Object self) { |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
526 |
final RegExpMatch match = Global.instance().getLastRegExpMatch(); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
527 |
return match == null ? "" : match.getGroup(9); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
528 |
} |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
529 |
|
16147 | 530 |
private RegExpMatch execInner(final String string) { |
531 |
if (this.pattern == null) { |
|
532 |
return null; // never matches or similar, e.g. a[] |
|
533 |
} |
|
534 |
||
535 |
final Matcher matcher = pattern.matcher(string); |
|
536 |
final int start = this.global ? getLastIndex() : 0; |
|
537 |
||
538 |
if (start < 0 || start > string.length()) { |
|
539 |
setLastIndex(0); |
|
540 |
return null; |
|
541 |
} |
|
542 |
||
543 |
if (!matcher.find(start)) { |
|
544 |
setLastIndex(0); |
|
545 |
return null; |
|
546 |
} |
|
547 |
||
548 |
if (global) { |
|
549 |
setLastIndex(matcher.end()); |
|
550 |
} |
|
551 |
||
16223
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
552 |
final RegExpMatch match = new RegExpMatch(string, matcher.start(), groups(matcher)); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
553 |
globalObject.setLastRegExpMatch(match); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
554 |
return match; |
16147 | 555 |
} |
556 |
||
557 |
/** |
|
558 |
* Convert java.util.regex.Matcher groups to JavaScript groups. |
|
559 |
* That is, replace null and groups that didn't match with undefined. |
|
560 |
*/ |
|
561 |
private Object[] groups(final Matcher matcher) { |
|
562 |
final int groupCount = matcher.groupCount(); |
|
563 |
final Object[] groups = new Object[groupCount + 1]; |
|
564 |
for (int i = 0, lastGroupStart = matcher.start(); i <= groupCount; i++) { |
|
565 |
final int groupStart = matcher.start(i); |
|
566 |
if (lastGroupStart > groupStart |
|
567 |
|| (groupsInNegativeLookahead != null && groupsInNegativeLookahead.isSet(i))) { |
|
568 |
// (1) ECMA 15.10.2.5 NOTE 3: need to clear Atom's captures each time Atom is repeated. |
|
569 |
// (2) ECMA 15.10.2.8 NOTE 3: Backreferences to captures in (?!Disjunction) from elsewhere |
|
570 |
// in the pattern always return undefined because the negative lookahead must fail. |
|
571 |
groups[i] = UNDEFINED; |
|
572 |
continue; |
|
573 |
} |
|
574 |
final String group = matcher.group(i); |
|
575 |
groups[i] = group == null ? UNDEFINED : group; |
|
576 |
lastGroupStart = groupStart; |
|
577 |
} |
|
578 |
return groups; |
|
579 |
} |
|
580 |
||
581 |
/** |
|
582 |
* Executes a search for a match within a string based on a regular |
|
583 |
* expression. It returns an array of information or null if no match is |
|
584 |
* found. |
|
585 |
* |
|
586 |
* @param string String to match. |
|
587 |
* @return NativeArray of matches, string or null. |
|
588 |
*/ |
|
589 |
public Object exec(final String string) { |
|
16223
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
590 |
final RegExpMatch match = execInner(string); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
591 |
|
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
592 |
if (match == null) { |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
593 |
return null; |
16147 | 594 |
} |
595 |
||
16223
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
596 |
return new NativeRegExpExecResult(match); |
16147 | 597 |
} |
598 |
||
599 |
/** |
|
600 |
* Executes a search for a match within a string based on a regular |
|
601 |
* expression. |
|
602 |
* |
|
603 |
* @param string String to match. |
|
604 |
* @return True if a match is found. |
|
605 |
*/ |
|
606 |
public Object test(final String string) { |
|
607 |
return exec(string) != null; |
|
608 |
} |
|
609 |
||
610 |
/** |
|
611 |
* Searches and replaces the regular expression portion (match) with the |
|
612 |
* replaced text instead. For the "replacement text" parameter, you can use |
|
613 |
* the keywords $1 to $2 to replace the original text with values from |
|
614 |
* sub-patterns defined within the main pattern. |
|
615 |
* |
|
616 |
* @param string String to match. |
|
617 |
* @param replacement Replacement string. |
|
618 |
* @return String with substitutions. |
|
619 |
*/ |
|
620 |
Object replace(final String string, final String replacement, final ScriptFunction function) { |
|
621 |
final Matcher matcher = pattern.matcher(string); |
|
622 |
/* |
|
623 |
* $$ -> $ |
|
624 |
* $& -> the matched substring |
|
625 |
* $` -> the portion of string that preceeds matched substring |
|
626 |
* $' -> the portion of string that follows the matched substring |
|
627 |
* $n -> the nth capture, where n is [1-9] and $n is NOT followed by a decimal digit |
|
628 |
* $nn -> the nnth capture, where nn is a two digit decimal number [01-99]. |
|
629 |
*/ |
|
630 |
String replace = replacement; |
|
631 |
||
632 |
if (!global) { |
|
633 |
if (!matcher.find()) { |
|
634 |
return string; |
|
635 |
} |
|
636 |
||
637 |
final StringBuilder sb = new StringBuilder(); |
|
638 |
if (function != null) { |
|
639 |
replace = callReplaceValue(function, matcher, string); |
|
640 |
} |
|
641 |
appendReplacement(matcher, string, replace, sb, 0); |
|
642 |
sb.append(string, matcher.end(), string.length()); |
|
643 |
return sb.toString(); |
|
644 |
} |
|
645 |
||
646 |
int end = 0; // a.k.a. lastAppendPosition |
|
647 |
setLastIndex(0); |
|
648 |
||
649 |
boolean found; |
|
650 |
try { |
|
651 |
found = matcher.find(end); |
|
652 |
} catch (final IndexOutOfBoundsException e) { |
|
653 |
found = false; |
|
654 |
} |
|
655 |
||
656 |
if (!found) { |
|
657 |
return string; |
|
658 |
} |
|
659 |
||
660 |
int previousLastIndex = 0; |
|
661 |
final StringBuilder sb = new StringBuilder(); |
|
662 |
do { |
|
663 |
if (function != null) { |
|
664 |
replace = callReplaceValue(function, matcher, string); |
|
665 |
} |
|
666 |
appendReplacement(matcher, string, replace, sb, end); |
|
667 |
end = matcher.end(); |
|
668 |
||
669 |
// ECMA 15.5.4.10 String.prototype.match(regexp) |
|
670 |
final int thisIndex = end; |
|
671 |
if (thisIndex == previousLastIndex) { |
|
672 |
setLastIndex(thisIndex + 1); |
|
673 |
previousLastIndex = thisIndex + 1; |
|
674 |
} else { |
|
675 |
previousLastIndex = thisIndex; |
|
676 |
} |
|
677 |
} while (matcher.find()); |
|
678 |
||
679 |
sb.append(string, end, string.length()); |
|
680 |
||
681 |
return sb.toString(); |
|
682 |
} |
|
683 |
||
684 |
private void appendReplacement(final Matcher matcher, final String text, final String replacement, final StringBuilder sb, final int lastAppendPosition) { |
|
685 |
// Process substitution string to replace group references with groups |
|
686 |
int cursor = 0; |
|
687 |
final StringBuilder result = new StringBuilder(); |
|
688 |
Object[] groups = null; |
|
689 |
||
690 |
while (cursor < replacement.length()) { |
|
691 |
char nextChar = replacement.charAt(cursor); |
|
692 |
if (nextChar == '$') { |
|
693 |
// Skip past $ |
|
694 |
cursor++; |
|
695 |
nextChar = replacement.charAt(cursor); |
|
696 |
final int firstDigit = nextChar - '0'; |
|
697 |
||
698 |
if (firstDigit >= 0 && firstDigit <= 9 && firstDigit <= matcher.groupCount()) { |
|
699 |
// $0 is not supported, but $01 is. implementation-defined: if n>m, ignore second digit. |
|
700 |
int refNum = firstDigit; |
|
701 |
cursor++; |
|
702 |
if (cursor < replacement.length() && firstDigit < matcher.groupCount()) { |
|
703 |
final int secondDigit = replacement.charAt(cursor) - '0'; |
|
704 |
if ((secondDigit >= 0) && (secondDigit <= 9)) { |
|
705 |
final int newRefNum = (firstDigit * 10) + secondDigit; |
|
706 |
if (newRefNum <= matcher.groupCount() && newRefNum > 0) { |
|
707 |
// $nn ($01-$99) |
|
708 |
refNum = newRefNum; |
|
709 |
cursor++; |
|
710 |
} |
|
711 |
} |
|
712 |
} |
|
713 |
if (refNum > 0) { |
|
714 |
if (groups == null) { |
|
715 |
groups = groups(matcher); |
|
716 |
} |
|
717 |
// Append group if matched. |
|
718 |
if (groups[refNum] != UNDEFINED) { |
|
719 |
result.append((String) groups[refNum]); |
|
720 |
} |
|
721 |
} else { // $0. ignore. |
|
722 |
assert refNum == 0; |
|
723 |
result.append("$0"); |
|
724 |
} |
|
725 |
} else if (nextChar == '$') { |
|
726 |
result.append('$'); |
|
727 |
cursor++; |
|
728 |
} else if (nextChar == '&') { |
|
729 |
result.append(matcher.group()); |
|
730 |
cursor++; |
|
731 |
} else if (nextChar == '`') { |
|
732 |
result.append(text.substring(0, matcher.start())); |
|
733 |
cursor++; |
|
734 |
} else if (nextChar == '\'') { |
|
735 |
result.append(text.substring(matcher.end())); |
|
736 |
cursor++; |
|
737 |
} else { |
|
738 |
// unknown substitution or $n with n>m. skip. |
|
739 |
result.append('$'); |
|
740 |
} |
|
741 |
} else { |
|
742 |
result.append(nextChar); |
|
743 |
cursor++; |
|
744 |
} |
|
745 |
} |
|
746 |
// Append the intervening text |
|
747 |
sb.append(text, lastAppendPosition, matcher.start()); |
|
748 |
// Append the match substitution |
|
749 |
sb.append(result); |
|
750 |
} |
|
751 |
||
752 |
private String callReplaceValue(final ScriptFunction function, final Matcher matcher, final String string) { |
|
753 |
final Object[] groups = groups(matcher); |
|
754 |
final Object[] args = Arrays.copyOf(groups, groups.length + 2); |
|
755 |
||
756 |
args[groups.length] = matcher.start(); |
|
757 |
args[groups.length + 1] = string; |
|
758 |
||
759 |
final Object self = function.isStrict() ? UNDEFINED : Global.instance(); |
|
760 |
||
761 |
return JSType.toString(ScriptRuntime.apply(function, self, args)); |
|
762 |
} |
|
763 |
||
764 |
/** |
|
765 |
* Breaks up a string into an array of substrings based on a regular |
|
766 |
* expression or fixed string. |
|
767 |
* |
|
768 |
* @param string String to match. |
|
769 |
* @param limit Split limit. |
|
770 |
* @return Array of substrings. |
|
771 |
*/ |
|
772 |
Object split(final String string, final long limit) { |
|
773 |
return split(this, string, limit); |
|
774 |
} |
|
775 |
||
776 |
private static Object split(final NativeRegExp regexp0, final String input, final long limit) { |
|
777 |
final List<Object> matches = new ArrayList<>(); |
|
778 |
||
779 |
final NativeRegExp regexp = new NativeRegExp(regexp0); |
|
780 |
regexp.setGlobal(true); |
|
781 |
||
782 |
if (limit == 0L) { |
|
783 |
return new NativeArray(); |
|
784 |
} |
|
785 |
||
786 |
RegExpMatch match; |
|
787 |
final int inputLength = input.length(); |
|
788 |
int lastLength = -1; |
|
789 |
int lastLastIndex = 0; |
|
790 |
||
791 |
while ((match = regexp.execInner(input)) != null) { |
|
792 |
final int lastIndex = match.getIndex() + match.length(); |
|
793 |
||
794 |
if (lastIndex > lastLastIndex) { |
|
795 |
matches.add(input.substring(lastLastIndex, match.getIndex())); |
|
796 |
if (match.getGroups().length > 1 && match.getIndex() < inputLength) { |
|
797 |
matches.addAll(Arrays.asList(match.getGroups()).subList(1, match.getGroups().length)); |
|
798 |
} |
|
799 |
||
800 |
lastLength = match.length(); |
|
801 |
lastLastIndex = lastIndex; |
|
802 |
||
803 |
if (matches.size() >= limit) { |
|
804 |
break; |
|
805 |
} |
|
806 |
} |
|
807 |
||
808 |
// bump the index to avoid infinite loop |
|
809 |
if (regexp.getLastIndex() == match.getIndex()) { |
|
810 |
regexp.setLastIndex(match.getIndex() + 1); |
|
811 |
} |
|
812 |
} |
|
813 |
||
814 |
if (matches.size() < limit) { |
|
815 |
// check special case if we need to append an empty string at the |
|
816 |
// end of the match |
|
817 |
// if the lastIndex was the entire string |
|
818 |
if (lastLastIndex == input.length()) { |
|
819 |
if (lastLength > 0 || regexp.test("") == Boolean.FALSE) { |
|
820 |
matches.add(""); |
|
821 |
} |
|
822 |
} else { |
|
823 |
matches.add(input.substring(lastLastIndex, inputLength)); |
|
824 |
} |
|
825 |
} |
|
826 |
||
827 |
return new NativeArray(matches.toArray()); |
|
828 |
} |
|
829 |
||
830 |
/** |
|
831 |
* Tests for a match in a string. It returns the index of the match, or -1 |
|
832 |
* if not found. |
|
833 |
* |
|
834 |
* @param string String to match. |
|
835 |
* @return Index of match. |
|
836 |
*/ |
|
837 |
Object search(final String string) { |
|
16223
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
838 |
final RegExpMatch match = execInner(string); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
839 |
|
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
840 |
if (match == null) { |
16217
c5ac9be5c444
8007619: Add support for deprecated properties of RegExp constructor
sundar
parents:
16214
diff
changeset
|
841 |
return -1; |
16147 | 842 |
} |
843 |
||
16223
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
844 |
return match.getIndex(); |
16147 | 845 |
} |
846 |
||
847 |
/** |
|
848 |
* Fast lastIndex getter |
|
849 |
* @return last index property as int |
|
850 |
*/ |
|
851 |
public int getLastIndex() { |
|
852 |
return JSType.toInt32(lastIndex); |
|
853 |
} |
|
854 |
||
855 |
/** |
|
856 |
* Fast lastIndex getter |
|
857 |
* @return last index property as boxed integer |
|
858 |
*/ |
|
859 |
public Object getLastIndexObject() { |
|
860 |
return lastIndex; |
|
861 |
} |
|
862 |
||
863 |
/** |
|
864 |
* Fast lastIndex setter |
|
865 |
* @param lastIndex lastIndex |
|
866 |
*/ |
|
867 |
public void setLastIndex(final int lastIndex) { |
|
868 |
this.lastIndex = JSType.toObject(lastIndex); |
|
869 |
} |
|
870 |
||
871 |
private void init() { |
|
16223
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
872 |
// Keep reference to global object to support "static" properties of RegExp |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
873 |
this.globalObject = Global.instance(); |
dff592a332a4
8007718: Make static RegExp properties fully compatible to other engines
hannesw
parents:
16217
diff
changeset
|
874 |
this.setProto(globalObject.getRegExpPrototype()); |
16147 | 875 |
} |
876 |
||
877 |
private static NativeRegExp checkRegExp(final Object self) { |
|
878 |
Global.checkObjectCoercible(self); |
|
879 |
if (self instanceof NativeRegExp) { |
|
880 |
return (NativeRegExp)self; |
|
881 |
} else if (self != null && self == Global.instance().getRegExpPrototype()) { |
|
882 |
return Global.instance().DEFAULT_REGEXP; |
|
883 |
} else { |
|
16188 | 884 |
typeError("not.a.regexp", ScriptRuntime.safeToString(self)); |
16147 | 885 |
return null; |
886 |
} |
|
887 |
} |
|
888 |
||
889 |
private String getInput() { |
|
890 |
return input; |
|
891 |
} |
|
892 |
||
893 |
private void setInput(final String input) { |
|
894 |
this.input = input; |
|
895 |
} |
|
896 |
||
897 |
boolean getGlobal() { |
|
898 |
return global; |
|
899 |
} |
|
900 |
||
901 |
private void setGlobal(final boolean global) { |
|
902 |
this.global = global; |
|
903 |
} |
|
904 |
||
905 |
private boolean getIgnoreCase() { |
|
906 |
return ignoreCase; |
|
907 |
} |
|
908 |
||
909 |
private void setIgnoreCase(final boolean ignoreCase) { |
|
910 |
this.ignoreCase = ignoreCase; |
|
911 |
} |
|
912 |
||
913 |
private boolean getMultiline() { |
|
914 |
return multiline; |
|
915 |
} |
|
916 |
||
917 |
private void setMultiline(final boolean multiline) { |
|
918 |
this.multiline = multiline; |
|
919 |
} |
|
920 |
||
921 |
private Pattern getPattern() { |
|
922 |
return pattern; |
|
923 |
} |
|
924 |
||
925 |
private void setPattern(final Pattern pattern) { |
|
926 |
this.pattern = pattern; |
|
927 |
} |
|
928 |
||
929 |
private BitVector getGroupsInNegativeLookahead() { |
|
930 |
return groupsInNegativeLookahead; |
|
931 |
} |
|
932 |
||
933 |
private void setGroupsInNegativeLookahead(final BitVector groupsInNegativeLookahead) { |
|
934 |
this.groupsInNegativeLookahead = groupsInNegativeLookahead; |
|
935 |
} |
|
936 |
||
937 |
} |