| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.apache.tinkerpop.gremlin.python.jsr223; |
| |
| import org.apache.commons.configuration.ConfigurationConverter; |
| import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; |
| import org.apache.tinkerpop.gremlin.process.traversal.Operator; |
| import org.apache.tinkerpop.gremlin.process.traversal.P; |
| import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions; |
| import org.apache.tinkerpop.gremlin.process.traversal.Translator; |
| import org.apache.tinkerpop.gremlin.process.traversal.Traversal; |
| import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource; |
| import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy; |
| import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; |
| import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent; |
| import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy; |
| import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP; |
| import org.apache.tinkerpop.gremlin.process.traversal.util.OrP; |
| import org.apache.tinkerpop.gremlin.structure.Edge; |
| import org.apache.tinkerpop.gremlin.structure.Element; |
| import org.apache.tinkerpop.gremlin.structure.T; |
| import org.apache.tinkerpop.gremlin.structure.Vertex; |
| import org.apache.tinkerpop.gremlin.structure.VertexProperty; |
| import org.apache.tinkerpop.gremlin.structure.util.StringFactory; |
| import org.apache.tinkerpop.gremlin.util.function.Lambda; |
| import org.apache.tinkerpop.gremlin.util.iterator.ArrayIterator; |
| import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; |
| |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.stream.Collectors; |
| import java.util.stream.Stream; |
| |
| /** |
| * @deprecated As of release 3.3.10, not replaced - see TINKERPOP-2317 |
| * |
| * @author Marko A. Rodriguez (http://markorodriguez.com) |
| * @author Stephen Mallette (http://stephen.genoprime.com) |
| */ |
| @Deprecated |
| public class PythonTranslator implements Translator.ScriptTranslator { |
| |
| private static final Set<String> STEP_NAMES = Stream.of(GraphTraversal.class.getMethods()).filter(method -> Traversal.class.isAssignableFrom(method.getReturnType())).map(Method::getName).collect(Collectors.toSet()); |
| private static final Set<String> NO_STATIC = Stream.of(T.values(), Operator.values()) |
| .flatMap(arg -> IteratorUtils.stream(new ArrayIterator<>(arg))) |
| .map(arg -> ((Enum) arg).name()) |
| .collect(Collectors.toCollection(() -> new HashSet<>(Collections.singleton("not")))); |
| |
| private final String traversalSource; |
| private final boolean importStatics; |
| |
| PythonTranslator(final String traversalSource, final boolean importStatics) { |
| this.traversalSource = traversalSource; |
| this.importStatics = importStatics; |
| } |
| |
| public static PythonTranslator of(final String traversalSource, final boolean importStatics) { |
| return new PythonTranslator(traversalSource, importStatics); |
| } |
| |
| public static PythonTranslator of(final String traversalSource) { |
| return new PythonTranslator(traversalSource, false); |
| } |
| |
| @Override |
| public String getTraversalSource() { |
| return this.traversalSource; |
| } |
| |
| @Override |
| public String translate(final Bytecode bytecode) { |
| return this.internalTranslate(this.traversalSource, bytecode); |
| } |
| |
| @Override |
| public String getTargetLanguage() { |
| return "gremlin-python"; |
| } |
| |
| @Override |
| public String toString() { |
| return StringFactory.translatorString(this); |
| } |
| |
| /////// |
| |
| private String internalTranslate(final String start, final Bytecode bytecode) { |
| final StringBuilder traversalScript = new StringBuilder(start); |
| for (final Bytecode.Instruction instruction : bytecode.getInstructions()) { |
| final String methodName = instruction.getOperator(); |
| final Object[] arguments = instruction.getArguments(); |
| if (0 == arguments.length) |
| traversalScript.append(".").append(resolveSymbol(methodName)).append("()"); |
| else if (methodName.equals("range") && 2 == arguments.length) |
| if (((Number) arguments[0]).longValue() + 1 == ((Number) arguments[1]).longValue()) |
| traversalScript.append("[").append(arguments[0]).append("]"); |
| else |
| traversalScript.append("[").append(arguments[0]).append(":").append(arguments[1]).append("]"); |
| else if (methodName.equals("limit") && 1 == arguments.length) |
| traversalScript.append("[0:").append(arguments[0]).append("]"); |
| else if (methodName.equals("values") && 1 == arguments.length && traversalScript.length() > 3 && !STEP_NAMES.contains(arguments[0].toString())) |
| traversalScript.append(".").append(arguments[0]); |
| else { |
| traversalScript.append("."); |
| String temp = resolveSymbol(methodName) + "("; |
| |
| // jython has trouble with java varargs...wrapping in collection seems to solve the problem |
| final boolean varargsBeware = instruction.getOperator().equals(TraversalSource.Symbols.withStrategies) |
| || instruction.getOperator().equals(TraversalSource.Symbols.withoutStrategies); |
| if (varargsBeware) temp = temp + "["; |
| |
| for (final Object object : arguments) { |
| temp = temp + convertToString(object) + ","; |
| } |
| temp = temp.substring(0, temp.length() - 1); |
| |
| if (varargsBeware) temp = temp + "]"; |
| |
| traversalScript.append(temp).append(")"); |
| } |
| // clip off __. |
| if (this.importStatics && traversalScript.substring(0, 3).startsWith("__.") |
| && !NO_STATIC.stream().filter(name -> traversalScript.substring(3).startsWith(resolveSymbol(name))).findAny().isPresent()) { |
| traversalScript.delete(0, 3); |
| } |
| } |
| return traversalScript.toString(); |
| } |
| |
| protected String convertToString(final Object object) { |
| if (object instanceof Bytecode.Binding) |
| return ((Bytecode.Binding) object).variable(); |
| else if (object instanceof Bytecode) |
| return this.internalTranslate("__", (Bytecode) object); |
| else if (object instanceof Traversal) |
| return convertToString(((Traversal) object).asAdmin().getBytecode()); |
| else if (object instanceof String) |
| return ((String) object).contains("\"") ? "\"\"\"" + object + "\"\"\"" : "\"" + object + "\""; |
| else if (object instanceof Set) { |
| final Set<String> set = new LinkedHashSet<>(((Set) object).size()); |
| for (final Object item : (Set) object) { |
| set.add(convertToString(item)); |
| } |
| return "set(" + set.toString() + ")"; |
| } else if (object instanceof List) { |
| final List<String> list = new ArrayList<>(((List) object).size()); |
| for (final Object item : (List) object) { |
| list.add(convertToString(item)); |
| } |
| return list.toString(); |
| } else if (object instanceof Map) { |
| final StringBuilder map = new StringBuilder("{"); |
| for (final Map.Entry<?, ?> entry : ((Map<?, ?>) object).entrySet()) { |
| map.append(convertToString(entry.getKey())). |
| append(":"). |
| append(convertToString(entry.getValue())). |
| append(","); |
| } |
| return map.length() > 1 ? map.substring(0, map.length() - 1) + "}" : map.append("}").toString(); |
| } else if (object instanceof Long) |
| return object + "L"; |
| else if (object instanceof TraversalStrategyProxy) { |
| return resolveTraversalStrategyProxy((TraversalStrategyProxy) object); |
| } else if (object instanceof TraversalStrategy) { |
| return convertToString(new TraversalStrategyProxy((TraversalStrategy) object)); |
| } else if (object instanceof Boolean) |
| return object.equals(Boolean.TRUE) ? "True" : "False"; |
| else if (object instanceof Class) |
| return ((Class) object).getCanonicalName(); |
| else if (object instanceof VertexProperty.Cardinality) |
| return "Cardinality." + resolveSymbol(object.toString()); |
| else if (object instanceof SackFunctions.Barrier) |
| return "Barrier." + resolveSymbol(object.toString()); |
| else if (object instanceof TraversalOptionParent.Pick) |
| return "Pick." + resolveSymbol(object.toString()); |
| else if (object instanceof Enum) |
| return convertStatic(((Enum) object).getDeclaringClass().getSimpleName() + ".") + resolveSymbol(object.toString()); |
| else if (object instanceof P) |
| return convertPToString((P) object, new StringBuilder()).toString(); |
| else if (object instanceof Element) { |
| if (object instanceof Vertex) { |
| final Vertex vertex = (Vertex) object; |
| return "Vertex(" + convertToString(vertex.id()) + "," + convertToString(vertex.label()) + ")"; |
| } else if (object instanceof Edge) { |
| final Edge edge = (Edge) object; |
| return "Edge(" + convertToString(edge.id()) + "," + |
| convertToString(edge.outVertex()) + "," + |
| convertToString(edge.label()) + "," + |
| convertToString(edge.inVertex()) + ")"; |
| } else { |
| final VertexProperty vertexProperty = (VertexProperty) object; |
| return "VertexProperty(" + convertToString(vertexProperty.id()) + "," + |
| convertToString(vertexProperty.label()) + "," + |
| convertToString(vertexProperty.value()) + ")"; |
| } |
| } else if (object instanceof Lambda) |
| return convertLambdaToString((Lambda) object); |
| else |
| return null == object ? "None" : object.toString(); |
| } |
| |
| private String convertStatic(final String name) { |
| return this.importStatics ? "" : name; |
| } |
| |
| private StringBuilder convertPToString(final P p, final StringBuilder current) { |
| if (p instanceof ConnectiveP) { |
| final List<P<?>> list = ((ConnectiveP) p).getPredicates(); |
| for (int i = 0; i < list.size(); i++) { |
| convertPToString(list.get(i), current); |
| if (i < list.size() - 1) |
| current.append(p instanceof OrP ? ".or_(" : ".and_("); |
| } |
| current.append(")"); |
| } else |
| current.append(convertStatic("P.")).append(p.getBiPredicate().toString()).append("(").append(convertToString(p.getValue())).append(")"); |
| return current; |
| } |
| |
| protected String convertLambdaToString(final Lambda lambda) { |
| final String lambdaString = lambda.getLambdaScript().trim(); |
| return lambdaString.startsWith("lambda") ? lambdaString : "lambda " + lambdaString; |
| } |
| |
| protected String resolveSymbol(final String methodName) { |
| return SymbolHelper.toPython(methodName); |
| } |
| |
| protected String resolveTraversalStrategyProxy(final TraversalStrategyProxy proxy) { |
| if (proxy.getConfiguration().isEmpty()) |
| return "TraversalStrategy(\"" + proxy.getStrategyClass().getSimpleName() + "\")"; |
| else |
| return "TraversalStrategy(\"" + proxy.getStrategyClass().getSimpleName() + "\"," + convertToString(ConfigurationConverter.getMap(proxy.getConfiguration())) + ")"; |
| } |
| } |