/**
* Copyright (C) 2013-2014 Olaf Lessenich
* Copyright (C) 2014-2015 University of Passau, Germany
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Contributors:
* Olaf Lessenich <lessenic@fim.uni-passau.de>
* Georg Seibt <seibt@fim.uni-passau.de>
*/
package de.fosd.jdime.gui;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javafx.concurrent.Task;
import javafx.scene.control.TreeItem;
/**
* A <code>Task</code> parsing a <code>String</code> produced by JDime using '-mode dumpgraph' into a <code>List</code>
* of <code>TreeItem</code>s representing root nodes for trees of AST nodes.
*/
class GraphvizParser extends Task<List<TreeItem<TreeDumpNode>>> {
private static final Pattern digraphStart = Pattern.compile(".*digraph ast \\{");
private static final Pattern digraphEnd = Pattern.compile("\\}");
private static final Pattern node = Pattern.compile("\"?([^\"]+)\"?\\[label=\"\\([0-9]+\\) (.+)\"(, fillcolor = (.+),)?.*\\];");
private static final Pattern connection = Pattern.compile("\"?([^\"]+)\"?->\"?([^\"]+)\"?;");
private List<String> text;
/**
* Constructs a new <code>GraphvizParser</code> parsing the given lines when {@link #call()} is
* called.
*
* @param text
* the lines to parse
*/
public GraphvizParser(List<String> text) {
this.text = text;
}
@Override
protected List<TreeItem<TreeDumpNode>> call() {
List<TreeItem<TreeDumpNode>> roots = new ArrayList<>();
Map<String, TreeItem<TreeDumpNode>> nodes = new HashMap<>();
List<TreeItem<TreeDumpNode>> noParent = new ArrayList<>();
for (String line : text) {
if (digraphStart.matcher(line).matches()) {
nodes.clear();
noParent.clear();
} else if (digraphEnd.matcher(line).matches()) {
if (noParent.size() == 1) {
roots.add(noParent.get(0));
} else {
System.err.println("Connections in the Graphviz format are wrong, there are " + noParent.size() +
" nodes without a parent node.");
}
} else {
Matcher matcher;
if ((matcher = node.matcher(line)).matches()) {
String id = matcher.group(1);
String label = matcher.group(2);
String color = matcher.group(4);
TreeDumpNode node = new TreeDumpNode(id, label);
TreeItem<TreeDumpNode> item = new TreeItem<>(node);
if (color != null) {
node.setFillColor(color);
}
nodes.put(id, item);
noParent.add(item);
} else if ((matcher = connection.matcher(line)).matches()) {
String leftId = matcher.group(1);
String rightId = matcher.group(2);
TreeItem<TreeDumpNode> left = nodes.get(leftId);
TreeItem<TreeDumpNode> right = nodes.get(rightId);
left.getChildren().add(right);
noParent.remove(right);
}
}
}
return roots;
}
}