You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2021/12/23 10:51:15 UTC
[tinkerpop] branch vars updated: wip - need to restructure grammar after this to take vars more generally
This is an automated email from the ASF dual-hosted git repository.
spmallette pushed a commit to branch vars
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
The following commit(s) were added to refs/heads/vars by this push:
new f5f3dc6 wip - need to restructure grammar after this to take vars more generally
f5f3dc6 is described below
commit f5f3dc69c735421ae9c45fe3882af03832904ce0
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Thu Dec 23 05:49:52 2021 -0500
wip - need to restructure grammar after this to take vars more generally
needs to cover things like enums and Traversal - the current model isnt working too well for that.
---
.../gremlin/jsr223/GremlinLangScriptEngine.java | 2 +-
.../language/grammar/GenericLiteralVisitor.java | 51 +++++++++++++++++++---
.../language/grammar/GremlinAntlrToJava.java | 8 ++++
.../jsr223/GremlinLangScriptEngineTest.java | 46 ++++++++++++++++++-
4 files changed, 98 insertions(+), 9 deletions(-)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinLangScriptEngine.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinLangScriptEngine.java
index 6c771bd..f13004c 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinLangScriptEngine.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinLangScriptEngine.java
@@ -104,7 +104,7 @@ public class GremlinLangScriptEngine extends AbstractScriptEngine implements Gre
if (!(o instanceof GraphTraversalSource))
throw new IllegalArgumentException("g is of type " + o.getClass().getSimpleName() + " and is not an instance of TraversalSource");
- final GremlinAntlrToJava antlr = new GremlinAntlrToJava((GraphTraversalSource) o);
+ final GremlinAntlrToJava antlr = new GremlinAntlrToJava((GraphTraversalSource) o, context.getBindings(ScriptContext.ENGINE_SCOPE));
try {
return GremlinQueryParser.parse(script, antlr);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java
index f7fe412..45518dd 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java
@@ -34,6 +34,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
/**
* Visitor class to handle generic literal. All visitor methods return type is Object. It maybe used as a singleton
@@ -61,10 +62,6 @@ public class GenericLiteralVisitor extends GremlinBaseVisitor<Object> {
* Parse a string literal context and return the string literal.
*/
public String getStringLiteral(final GremlinParser.StringLiteralContext stringLiteral, final GremlinAntlrToJava antlr) {
- if (antlr != null && stringLiteral.variable() != null) {
- final String varName = stringLiteral.variable().getText();
- return tryBindings(antlr, varName);
- }
return (String) visitStringLiteral(stringLiteral);
}
@@ -265,6 +262,10 @@ public class GenericLiteralVisitor extends GremlinBaseVisitor<Object> {
*/
@Override
public Object visitGenericLiteralMap(final GremlinParser.GenericLiteralMapContext ctx) {
+ if (isPossibleVariable(antlr, ctx.variable())) {
+ return tryBindings(antlr, ctx.variable());
+ }
+
final HashMap<Object, Object> literalMap = new HashMap<>();
int childIndex = 1;
while (childIndex < ctx.getChildCount() && ctx.getChildCount() > 3) {
@@ -303,6 +304,10 @@ public class GenericLiteralVisitor extends GremlinBaseVisitor<Object> {
*/
@Override
public Object visitIntegerLiteral(final GremlinParser.IntegerLiteralContext ctx) {
+ if (isPossibleVariable(antlr, ctx.variable())) {
+ return tryBindings(antlr, ctx.variable());
+ }
+
String integerLiteral = ctx.getText().toLowerCase().replace("_", "");
// handle suffixes for specific types
final int lastCharIndex = integerLiteral.length() - 1;
@@ -369,6 +374,10 @@ public class GenericLiteralVisitor extends GremlinBaseVisitor<Object> {
*/
@Override
public Object visitFloatLiteral(final GremlinParser.FloatLiteralContext ctx) {
+ if (isPossibleVariable(antlr, ctx.variable())) {
+ return tryBindings(antlr, ctx.variable());
+ }
+
final String floatLiteral = ctx.getText().toLowerCase();
// check suffix
@@ -393,6 +402,10 @@ public class GenericLiteralVisitor extends GremlinBaseVisitor<Object> {
*/
@Override
public Object visitBooleanLiteral(final GremlinParser.BooleanLiteralContext ctx) {
+ if (isPossibleVariable(antlr, ctx.variable())) {
+ return tryBindings(antlr, ctx.variable());
+ }
+
return Boolean.valueOf(ctx.getText());
}
@@ -401,6 +414,10 @@ public class GenericLiteralVisitor extends GremlinBaseVisitor<Object> {
*/
@Override
public Object visitDateLiteral(final GremlinParser.DateLiteralContext ctx) {
+ if (isPossibleVariable(antlr, ctx.variable())) {
+ return tryBindings(antlr, ctx.variable());
+ }
+
return DatetimeHelper.parse((String) visitStringLiteral(ctx.stringLiteral()));
}
@@ -409,6 +426,10 @@ public class GenericLiteralVisitor extends GremlinBaseVisitor<Object> {
*/
@Override
public Object visitStringLiteral(final GremlinParser.StringLiteralContext ctx) {
+ if (isPossibleVariable(antlr, ctx.variable())) {
+ return tryBindings(antlr, ctx.variable());
+ }
+
// Using Java string unescaping because it coincides with the Groovy rules:
// https://docs.oracle.com/javase/tutorial/java/data/characters.html
// http://groovy-lang.org/syntax.html#_escaping_special_characters
@@ -512,10 +533,26 @@ public class GenericLiteralVisitor extends GremlinBaseVisitor<Object> {
return result;
}
- private static <T> T tryBindings(final GremlinAntlrToJava antlr, final String varName) {
- if (!antlr.bindings.containsKey(varName)) {
+ /**
+ * Determines if the currently parsed context is a variable and if it is potentially resolvable.
+ */
+ private static boolean isPossibleVariable(final GremlinAntlrToJava antlr, final GremlinParser.VariableContext variable) {
+ return antlr != null && variable != null;
+ }
+
+ /**
+ * Tries to extract a value for the variable from the bindings supplied to the parser.
+ * @param antlr must not be null
+ * @param variableCtx must not be null
+ */
+ private static <T> T tryBindings(final GremlinAntlrToJava antlr,
+ final GremlinParser.VariableContext variableCtx) {
+ Objects.requireNonNull(antlr);
+ Objects.requireNonNull(variableCtx);
+
+ final String varName = variableCtx.getText();
+ if (!antlr.bindings.containsKey(varName))
throw new UnboundIdentifierException(varName);
- }
return (T) antlr.bindings.get(varName);
}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinAntlrToJava.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinAntlrToJava.java
index cd9473a..364687b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinAntlrToJava.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinAntlrToJava.java
@@ -114,6 +114,14 @@ public class GremlinAntlrToJava extends GremlinBaseVisitor<Object> {
}
/**
+ * Constructs a new instance that is bound to the specified {@link GraphTraversalSource} and thus spawns the
+ * {@link Traversal} from this "g" rather than from a fresh one constructed from the {@link Graph} instance.
+ */
+ public GremlinAntlrToJava(final GraphTraversalSource g, final Map<String, Object> bindings) {
+ this(GraphTraversalSourceVisitor.TRAVERSAL_ROOT, g.getGraph(), __::start, g, bindings);
+ }
+
+ /**
* Constructs a new instance that is bound to the specified {@link Graph} instance with an override to using
* {@link __} for constructing anonymous {@link Traversal} instances. Assumes that "g" is the name of the
* {@link GraphTraversalSource}.
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/jsr223/GremlinLangScriptEngineTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/jsr223/GremlinLangScriptEngineTest.java
index aa4d714..9503b01 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/jsr223/GremlinLangScriptEngineTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/jsr223/GremlinLangScriptEngineTest.java
@@ -20,11 +20,21 @@ package org.apache.tinkerpop.gremlin.jsr223;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.structure.T;
import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
import org.junit.Test;
import javax.script.Bindings;
+import javax.script.ScriptContext;
import javax.script.ScriptException;
+import javax.script.SimpleBindings;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
@@ -36,7 +46,9 @@ public class GremlinLangScriptEngineTest {
private final static GraphTraversalSource g = EmptyGraph.instance().traversal();
static {
- scriptEngine.put("g", g);
+ final Bindings globalBindings = new SimpleBindings();
+ globalBindings.put("g", g);
+ scriptEngine.setBindings(globalBindings, ScriptContext.GLOBAL_SCOPE);
}
@Test
@@ -47,6 +59,38 @@ public class GremlinLangScriptEngineTest {
}
@Test
+ public void shouldEvalGremlinScriptWithVariables() throws ScriptException {
+ final Bindings b = new SimpleBindings();
+ b.put("int0", 0);
+ b.put("dec0", 0.0d);
+ b.put("string0", "knows");
+ b.put("string1", "created");
+ b.put("bool0", true);
+ b.put("t0", T.id);
+
+ final Date d = new Date();
+ b.put("date0", d);
+
+ final List<String> l = new ArrayList<>();
+ l.add("yes");
+ l.add("no");
+ b.put("list0", l);
+
+ final Map<String,Object> m = new HashMap<>();
+ m.put("x", 1);
+ m.put("y", 2);
+ b.put("map0", m);
+
+ final Object result = scriptEngine.eval("g.inject(bool0, date0, map0, int0, dec0, list0).V().out(string0).in(string1).project('tid')", b);
+ assertThat(result, instanceOf(Traversal.Admin.class));
+ assertEquals(g.inject(true, d, m, 0, 0.0d, l).
+ V().
+ out("knows").in("created").
+ project("tid").asAdmin().getBytecode(),
+ ((Traversal.Admin) result).getBytecode());
+ }
+
+ @Test
public void shouldEvalGremlinBytecode() throws ScriptException {
final Object result = scriptEngine.eval(g.V().asAdmin().getBytecode(), "g");
assertThat(result, instanceOf(Traversal.Admin.class));