49
49
* the full story. And if you don't yet have Jeffrey Friedl's "Mastering regular
50
50
* expressions", just <a href="http://regex.info">buy it</a> :p</p>
51
51
*
52
- * <p>As script engine is used either Nashorn or Rhino as its fallback.
53
- * Nashorn is only available on Java 8 up to 14.</p>
52
+ * <p>As script engine is used either GraalJS, Nashorn or Rhino as their
53
+ * fallback. Nashorn is only available on Java 8 up to 14.</p>
54
54
*
55
- * <p>Rhino is the fallback as it is tremendously slower.</p>
55
+ * <p>GraalJS is the first choice as it supports more RegExp features, e.g.
56
+ * lookbehind assertions, than both alternatives.</p>
57
+ *
58
+ * <p>Rhino is the fallback as it is tremendously slower than Nashorn.</p>
56
59
*/
57
60
@ ThreadSafe
58
61
public final class RegexECMA262Helper
@@ -89,10 +92,15 @@ private RegexECMA262Helper()
89
92
90
93
private static RegexScript determineRegexScript ()
91
94
{
95
+ try {
96
+ return new GraalJsScript ();
97
+ } catch (final ScriptException e ) {
98
+ // most probably GraalJS is simply not available
99
+ }
92
100
try {
93
101
return new NashornScript ();
94
102
} catch (final ScriptException e ) {
95
- // either Nashorn is not available or the JavaScript can't be parsed
103
+ // most probably Nashorn is simply not available
96
104
}
97
105
return new RhinoScript ();
98
106
}
@@ -134,26 +142,25 @@ private interface RegexScript
134
142
boolean regMatch (String regex , String input );
135
143
}
136
144
137
- private static class NashornScript implements RegexScript
145
+ private static abstract class ScriptEngineScript implements RegexScript
138
146
{
139
147
/**
140
148
* Script engine
141
149
*/
142
150
private final Invocable scriptEngine ;
143
151
144
- private NashornScript ( ) throws ScriptException
152
+ private ScriptEngineScript ( final String engineName ) throws ScriptException
145
153
{
146
154
final ScriptEngine engine = new ScriptEngineManager ()
147
- .getEngineByName ("nashorn" );
148
- if (engine == null ) {
149
- throw new ScriptException ("ScriptEngine 'nashorn ' not found." );
155
+ .getEngineByName (engineName );
156
+ if (engine == null ) {
157
+ throw new ScriptException ("ScriptEngine '" + engineName + " ' not found." );
150
158
}
151
159
engine .eval (jsAsString );
152
160
this .scriptEngine = (Invocable ) engine ;
153
161
}
154
162
155
- private boolean invokeScriptEngine (final String function ,
156
- final Object ... values )
163
+ boolean invoke (final String function , final Object ... values )
157
164
{
158
165
try {
159
166
return (Boolean ) scriptEngine .invokeFunction (function ,
@@ -178,6 +185,37 @@ public boolean regMatch(final String regex, final String input)
178
185
{
179
186
return invokeScriptEngine (REG_MATCH_FUNCTION_NAME , regex , input );
180
187
}
188
+
189
+ abstract boolean invokeScriptEngine (final String function , final Object ... values );
190
+ }
191
+
192
+ private static class GraalJsScript extends ScriptEngineScript
193
+ {
194
+ private GraalJsScript () throws ScriptException
195
+ {
196
+ super ("graal.js" );
197
+ }
198
+
199
+ // GraalJS works single-threaded. The synchronized ensures this.
200
+ @ Override
201
+ synchronized boolean invokeScriptEngine (final String function ,
202
+ final Object ... values ) {
203
+ return invoke (function , values );
204
+ }
205
+ }
206
+
207
+ private static class NashornScript extends ScriptEngineScript
208
+ {
209
+ private NashornScript () throws ScriptException
210
+ {
211
+ super ("nashorn" );
212
+ }
213
+
214
+ @ Override
215
+ boolean invokeScriptEngine (final String function ,
216
+ final Object ... values ) {
217
+ return invoke (function , values );
218
+ }
181
219
}
182
220
183
221
private static class RhinoScript implements RegexScript
0 commit comments