/*
* ******************************************************************************
* MontiCore Language Workbench
* Copyright (c) 2015, MontiCore, All rights reserved.
*
* This project 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 3.0 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 project. If not, see <http://www.gnu.org/licenses/>.
* ******************************************************************************
*/
package de.monticore.generating.templateengine.reporting.reporter;
import java.io.File;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import com.google.common.collect.Maps;
import de.monticore.ast.ASTNode;
import de.monticore.generating.templateengine.reporting.commons.AReporter;
import de.monticore.generating.templateengine.reporting.commons.Layouter;
import de.monticore.generating.templateengine.reporting.commons.MapUtil;
import de.monticore.generating.templateengine.reporting.commons.ObjectCountVisitor;
import de.monticore.generating.templateengine.reporting.commons.ReportingConstants;
import de.se_rwth.commons.SourcePosition;
/**
* TODO: Write me!
*
* @author (last commit) $Author$
* @version $Revision$, $Date$
* @since TODO: add version number
*/
public class NodeTypesReporter extends AReporter {
final static String SIMPLE_FILE_NAME = "12_TypesOfNodes";
private Map<String, Integer> nodeTypeCount = Maps.newTreeMap();
private Map<String, Integer> nodeTypeCountPos = Maps.newTreeMap();
public NodeTypesReporter(String outputDir, String modelName) {
super(outputDir + File.separator + ReportingConstants.REPORTING_DIR
+ File.separator + modelName, SIMPLE_FILE_NAME,
ReportingConstants.REPORT_FILE_EXTENSION);
}
@Override
protected void writeHeader() {
writeLine("======================================== Types of Nodes (all)");
writeLine("#Objects #Visits Nonterminal-Name");
}
public void writeContent(ASTNode ast) {
if (ast == null) {
return;
}
ObjectCountVisitor ocv = new ObjectCountVisitor();
ocv.handle(ast);
Map<String, Integer> type2count = ocv.getObjectCountMap();
writeMaps(nodeTypeCount, type2count);
writeLine("======================================== Types of Nodes (With Source Pos)");
writeLine("#Objects #Visits Nonterminal-Name");
Map<String, Integer> type2countPos = ocv.getObjectCountMapPos();
writeMaps(nodeTypeCountPos, type2countPos);
writeLine("======================================== Types of Nodes (No Source Pos)");
writeLine("#Objects #Visits Nonterminal-Name");
Map<String, Integer> nodeTypeCountNoPos = getMapDiff(nodeTypeCount, nodeTypeCountPos);
Map<String, Integer> type2countNoPos = getMapDiff(type2count, type2countPos);
writeMaps(nodeTypeCountNoPos, type2countNoPos);
}
/**
* @param nodeTypeCount2: Map contains all ASTNodes
* @param nodetypeCountPos2: Map contains ASTNodes with a source position
* @return Map containing ASTNodes without source position
*/
private Map<String, Integer> getMapDiff(Map<String, Integer> nodeTypeCount2,
Map<String, Integer> nodetypeCountPos2) {
Map<String, Integer> dif = Maps.newTreeMap();
// merging keys of objects and visits
Set<String> allKeys = new TreeSet<String>();
allKeys.addAll(nodetypeCountPos2.keySet());
allKeys.addAll(nodeTypeCount2.keySet());
for (String key : allKeys) {
int val1, val2;
if (nodeTypeCount2.containsKey(key)) {
val1 = nodeTypeCount2.get(key);
}
else {
val1 = 0;
}
if (nodetypeCountPos2.containsKey(key)) {
val2 = nodetypeCountPos2.get(key);
}
else {
val2 = 0;
}
dif.put(key, val1 - val2);
}
return dif;
}
/**
* helper method: print these 2 maps the same way
*
* @param nodeTypeCount2
* @param type2count
*/
private void writeMaps(Map<String, Integer> nodeTypeCount2, Map<String, Integer> type2count) {
// merging keys of objects and visits
Set<String> allKeys = new TreeSet<String>();
allKeys.addAll(type2count.keySet());
allKeys.addAll(nodeTypeCount2.keySet());
for (String key : allKeys) {
String objectCount, s;
if (!type2count.containsKey(key)) {
objectCount = "0x";
}
else {
objectCount = type2count.get(key) + "x";
}
if (!nodeTypeCount2.containsKey(key)) {
s = "0x";
}
else {
s = nodeTypeCount2.get(key) + "x";
}
// evading 0x objects 0x visits line
if (!(s.equals("0x") && objectCount.equals("0x"))) {
writeLine(objectCount
+ Layouter.getSpaceString(10 - objectCount.length()) + s
+ Layouter.getSpaceString(9 - s.length()) + key);
}
}
}
private void writeFooter() {
writeLine("========================================================== Explanation");
writeLine("Types of Nodes: Shows a List of all AST-Node-Types that occur in the final AST.");
writeLine("Types of Nodes (with Source Position): Shows the subset of all AST Node Types");
writeLine("which occurred in the initial AST after the parsing step.");
writeLine("Types of Nodes (without Source Position): Shows the subset of all AST Node Types");
writeLine("which have been added to the initial AST after the parsing step (e.g. by model");
writeLine("transformation).");
writeLine("For each AST type entry in the lists the following information is reported: ");
writeLine(" - #Objects: number of its instances of the corresponding AST type");
writeLine(" - #Visits: how often nodes of that type have been visited by a");
writeLine(" call/includeTemplate");
writeLine("(EOF)");
}
@Override
public void reportTemplateStart(String templatename, ASTNode ast) {
String key = Layouter.nodeName(ast);
MapUtil.incMapValue(nodeTypeCount, key);
if (!ast.get_SourcePositionStart().equals(SourcePosition.getDefaultSourcePosition())) {
MapUtil.incMapValue(nodeTypeCountPos, key);
}
}
@Override
public void flush(ASTNode ast) {
writeContent(ast);
writeFooter();
nodeTypeCount.clear();
super.flush(ast);
}
}