Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for GraalJS script engine on RegExp checks #97

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,13 @@
* the full story. And if you don't yet have Jeffrey Friedl's "Mastering regular
* expressions", just <a href="http://regex.info">buy it</a> :p</p>
*
* <p>As script engine is used either Nashorn or Rhino as its fallback.
* Nashorn is only available on Java 8 up to 14.</p>
* <p>As script engine is used either GraalJS, Nashorn or Rhino as their
* fallback. Nashorn is only available on Java 8 up to 14.</p>
*
* <p>Rhino is the fallback as it is tremendously slower.</p>
* <p>GraalJS is the first choice as it supports more RegExp features, e.g.
* lookbehind assertions, than both alternatives.</p>
*
* <p>Rhino is the fallback as it is tremendously slower than Nashorn.</p>
*/
@ThreadSafe
public final class RegexECMA262Helper
Expand Down Expand Up @@ -89,10 +92,15 @@ private RegexECMA262Helper()

private static RegexScript determineRegexScript()
{
try {
return new GraalJsScript();
} catch(final ScriptException e) {
// most probably GraalJS is simply not available
}
try {
return new NashornScript();
} catch(final ScriptException e) {
// either Nashorn is not available or the JavaScript can't be parsed
// most probably Nashorn is simply not available
}
return new RhinoScript();
}
Expand Down Expand Up @@ -134,26 +142,25 @@ private interface RegexScript
boolean regMatch(String regex, String input);
}

private static class NashornScript implements RegexScript
private static abstract class ScriptEngineScript implements RegexScript
{
/**
* Script engine
*/
private final Invocable scriptEngine;

private NashornScript() throws ScriptException
private ScriptEngineScript(final String engineName) throws ScriptException
{
final ScriptEngine engine = new ScriptEngineManager()
.getEngineByName("nashorn");
if (engine == null) {
throw new ScriptException("ScriptEngine 'nashorn' not found.");
.getEngineByName(engineName);
if(engine == null) {
throw new ScriptException("ScriptEngine '" + engineName + "' not found.");
}
engine.eval(jsAsString);
this.scriptEngine = (Invocable) engine;
}

private boolean invokeScriptEngine(final String function,
final Object... values)
boolean invoke(final String function, final Object... values)
{
try {
return (Boolean) scriptEngine.invokeFunction(function,
Expand All @@ -178,6 +185,37 @@ public boolean regMatch(final String regex, final String input)
{
return invokeScriptEngine(REG_MATCH_FUNCTION_NAME, regex, input);
}

abstract boolean invokeScriptEngine(final String function, final Object... values);
}

private static class GraalJsScript extends ScriptEngineScript
{
private GraalJsScript() throws ScriptException
{
super("graal.js");
}

// GraalJS works single-threaded. The synchronized ensures this.
@Override
synchronized boolean invokeScriptEngine(final String function,
final Object... values) {
return invoke(function, values);
}
}

private static class NashornScript extends ScriptEngineScript
{
private NashornScript() throws ScriptException
{
super("nashorn");
}

@Override
boolean invokeScriptEngine(final String function,
final Object... values) {
return invoke(function, values);
}
}

private static class RhinoScript implements RegexScript
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public Iterator<Object[]> ecma262regexes()
{
return ImmutableList.of(
new Object[] { "[^]", true },
new Object[] { "(?<=foo)bar", false },
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to change this.

With GraalJS this "Positive Lookbehind" is supported and wouldn't have failed as expected.

new Object[] { "(?<=foobar", false },
new Object[] { "", true },
new Object[] { "[a-z]+(?!foo)(?=bar)", true }
).iterator();
Expand Down