/*
* Copyright (c) 2013 Data Harmonisation Panel
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution. If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* Data Harmonisation Panel <http://www.dhpanel.eu>
*/
package eu.esdihumboldt.hale.ui.util.groovy.ast;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.codehaus.groovy.ast.ASTNode;
import com.google.common.collect.ImmutableList;
import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.blueprints.Graph;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.blueprints.impls.tg.TinkerGraph;
/**
* Creates a Tinkerpop {@link Graph} from a Groovy AST.
*
* @author Simon Templer
*/
public class ASTToGraphVisitor extends AbstractASTTreeVisitor<Vertex> implements ASTGraphConstants {
private final Graph graph;
private final List<Vertex> rootVertices = new ArrayList<>();
/**
* Default constructor.
*/
public ASTToGraphVisitor() {
super();
graph = new TinkerGraph();
}
@Override
public Vertex createNode(Object node) {
if (node instanceof ASTNode) {
ASTNode astn = (ASTNode) node;
Vertex v = graph.addVertex(null);
// fill vertex with info
v.setProperty(P_AST_NODE, astn);
v.setProperty(P_AST_TYPE, astn.getClass().getSimpleName());
v.setProperty(P_START_LINE, astn.getLineNumber());
v.setProperty(P_START_COL, astn.getColumnNumber());
v.setProperty(P_END_LINE, astn.getLastLineNumber());
v.setProperty(P_END_COL, astn.getLastColumnNumber());
return v;
}
return null;
}
@Override
protected void addRootNode(Vertex node) {
super.addRootNode(node);
// root node
rootVertices.add(node);
}
@Override
public void setParent(Vertex node, Vertex parent) {
// add child/parent relation between nodes
graph.addEdge(null, parent, node, E_CHILD);
graph.addEdge(null, node, parent, E_PARENT);
// set first edge if not set
if (!parent.getEdges(Direction.OUT, E_FIRST).iterator().hasNext()) {
graph.addEdge(null, parent, node, E_FIRST);
}
// set or update last
Iterator<Vertex> it = parent.getVertices(Direction.OUT, E_LAST).iterator();
if (it.hasNext()) {
// last already set
Vertex prev = it.next();
// remove existing last edge
graph.removeEdge(prev.getEdges(Direction.IN, E_LAST).iterator().next());
// add next/previous edge
graph.addEdge(null, prev, node, E_NEXT);
graph.addEdge(null, node, prev, E_PREV);
}
graph.addEdge(null, parent, node, E_LAST);
// verify/update parent positions, needed .e.g for BlockStatements
// update start position
int nodeLine = node.getProperty(P_START_LINE);
int nodeCol = node.getProperty(P_START_COL);
int parentLine = parent.getProperty(P_START_LINE);
int parentCol = parent.getProperty(P_START_COL);
if (nodeLine != -1) {
if (parentLine == -1) {
parentLine = nodeLine;
parentCol = nodeCol;
}
else {
if (nodeLine < parentLine) {
parentLine = nodeLine;
parentCol = nodeCol;
}
else if (nodeLine == parentLine && nodeCol < parentCol) {
parentCol = nodeCol;
}
}
parent.setProperty(P_START_LINE, parentLine);
parent.setProperty(P_START_COL, parentCol);
}
// update end position
int nodeLastLine = node.getProperty(P_END_LINE);
int nodeLastCol = node.getProperty(P_END_COL);
int parentLastLine = parent.getProperty(P_END_LINE);
int parentLastCol = parent.getProperty(P_END_COL);
if (nodeLastLine != -1) {
if (parentLastLine == -1) {
parentLastLine = nodeLastLine;
parentLastCol = nodeLastCol;
}
else {
if (nodeLastLine > parentLastLine) {
parentLastLine = nodeLastLine;
parentLastCol = nodeLastCol;
}
else if (nodeLastLine == parentLastLine && nodeLastCol > parentLastCol) {
parentLastCol = nodeLastCol;
}
}
parent.setProperty(P_END_LINE, parentLastLine);
parent.setProperty(P_END_COL, parentLastCol);
}
}
/**
* @return the graph
*/
public Graph getGraph() {
return graph;
}
/**
* @return the rootVertices
*/
public List<Vertex> getRootVertices() {
return ImmutableList.copyOf(rootVertices);
}
}