/*
* #%~
* The Overture Abstract Syntax Tree
* %%
* Copyright (C) 2008 - 2014 Overture
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #~%
*/
package org.overture.ast.preview;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.overture.ast.analysis.AnalysisException;
import org.overture.ast.analysis.QuestionAdaptor;
import org.overture.ast.lex.LexNameToken;
import org.overture.ast.node.ExternalNode;
import org.overture.ast.node.INode;
import org.overture.ast.node.IToken;
import org.overture.ast.node.NodeList;
public class DotGraphVisitor extends QuestionAdaptor<DotGraphVisitor.DotPair>
{
public static class DotPair
{
public DotNode parent;
public String childKey;
public DotPair(DotNode parent, String fieldKey)
{
this.parent = parent;
this.childKey = fieldKey;
}
}
public static class DotNode
{
public static int runningId = 0;
public DotNode()
{
runningId++;
this.id = "n" + runningId;
}
public String id;
public String name;
public Map<String, Object> childToId = new HashMap<String, Object>();
}
private StringBuilder resultString;
public boolean showNullPointers = false;
Set<INode> visitedNodes = null;
Set<String> filterClassNames = new HashSet<String>();
public DotGraphVisitor()
{
DotNode.runningId = 0;
resultString = new StringBuilder();
visitedNodes = new HashSet<INode>();
resultString.append("\tnode [shape=record];\n");
}
public DotGraphVisitor(Set<String> filterClassNames)
{
this();
this.filterClassNames = filterClassNames;
}
public String getResultString()
{
return "\ndigraph ast\n{\n" + resultString.toString() + "\n}";
}
public DotNode createDotNode(DotPair pair, INode node)
{
DotNode dn = new DotNode();
dn.name = node.getClass().getSimpleName();
String tmp = " [label=\"{" + dn.name + " |{";
boolean firstChild = true;
for (Entry<String, Object> s : node.getChildren(true).entrySet())
{
String id = dn.id + s.getKey();
dn.childToId.put(id, s.getValue());
if (!firstChild)
{
tmp += " | ";
}
firstChild = false;
tmp += " <" + id + "> " + s.getKey();
}
resultString.append("\t" + dn.id + tmp + "}}\"];\n");
if (pair != null && pair.parent != null)
{
String fieldId = pair.childKey;
resultString.append("\t" + pair.parent.id + ":" + fieldId + " -> "
+ dn.id + "\n");
}
return dn;
}
private void createDotNode(DotPair pair, Object node)
{
DotNode dn = new DotNode();
String colour = "lightgray";
if (node == null)
{
colour = "red2";
dn.name = "null";
} else
{
dn.name = node.getClass().getSimpleName();
}
if (node instanceof ExternalNode)
{
colour = "lightblue";
}
String tmp = " [color=" + colour + ",style=filled,label=\"{" + dn.name;
if (node != null)
{
tmp += " |{";
boolean firstChild = true;
Map<String, Object> children = new HashMap<String, Object>();
String nt = node.toString();
if (nt.length() > 150)
{
nt = nt.substring(0, 150);
}
children.put("" + nt.replaceAll("[^a-zA-Z0-9 ]", "") + "", null);
for (Entry<String, Object> s : children.entrySet())
{
String id = dn.id + s.getKey();
id = id.replaceAll("[^a-zA-Z0-9]", "");
dn.childToId.put(id, s.getValue());
if (!firstChild)
{
tmp += " | ";
}
firstChild = false;
tmp += " <" + id + "> " + s.getKey();
}
tmp += "}";
}
resultString.append("\t" + dn.id + tmp + "}\"];\n");
if (pair != null && pair.parent != null)
{
String fieldId = pair.childKey;
resultString.append("\t" + pair.parent.id + ":" + fieldId + " -> "
+ dn.id + "\n");
}
// return dn;
}
@Override
public void defaultINode(INode node, DotPair question)
throws AnalysisException
{
if (!(node instanceof LexNameToken) && visitedNodes.contains(node)
|| node == null)
{
return;
}
if (!(node instanceof LexNameToken))
{
visitedNodes.add(node);
}
DotPair parentNode = new DotPair(createDotNode(question, node), null);
for (Entry<String, Object> field : node.getChildren(true).entrySet())
{
Object fieldObject = field.getValue();
if (fieldObject == null
&& !showNullPointers
|| filterClassNames.contains(fieldObject.getClass().getSimpleName()))
{
continue;// do not show on diagram
}
parentNode = new DotPair(parentNode.parent, parentNode.parent.id
+ field.getKey());
if (fieldObject instanceof INode)
{
INode childNode = (INode) fieldObject;
childNode.apply(this, parentNode);
} else if (fieldObject instanceof NodeList)
{
@SuppressWarnings("unchecked")
NodeList<INode> childNodes = (NodeList<INode>) fieldObject;
for (INode childNode : childNodes)
{
childNode.apply(this, parentNode);
}
} else
// if (fieldObject instanceof ExternalNode)
{
createDotNode(parentNode, fieldObject);
}
}
}
@Override
public void defaultIToken(IToken node, DotPair question)
{
createDotNode(question, node);
}
}