mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-06-03 07:29:37 +00:00
137053f093
- Activate with option -rrig or -reportrig.
111 lines
5.0 KiB
Java
111 lines
5.0 KiB
Java
package dk.camelot64.kickc.passes.reports;
|
|
|
|
import dk.camelot64.kickc.model.Graph;
|
|
import dk.camelot64.kickc.model.ProcedureCompilation;
|
|
import dk.camelot64.kickc.model.Program;
|
|
import dk.camelot64.kickc.model.statements.Statement;
|
|
import dk.camelot64.kickc.model.statements.StatementCall;
|
|
import dk.camelot64.kickc.model.symbols.Procedure;
|
|
import dk.camelot64.kickc.model.values.LabelRef;
|
|
import dk.camelot64.kickc.model.values.ProcedureRef;
|
|
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* Create a report of the Control Block Flow Graph (CFG) of the whole Program.
|
|
* This class generates a markdown report with embedded mermaid graphics of
|
|
* the whole Program CFGs.
|
|
*/
|
|
public class ReportCFG extends Report {
|
|
|
|
private MermaidGraph mermaidGraph;
|
|
|
|
public ReportCFG(Program program, String pass, String extension) {
|
|
super(program, pass, extension);
|
|
}
|
|
|
|
public void mermaidCFGBlock(Graph graph, Graph.Block block, MermaidSubGraph mermaidSubGraph) {
|
|
|
|
String blockName = block.getLabel().getFullName();
|
|
|
|
MermaidNode node = mermaidSubGraph.addNode(new MermaidNode(blockName));
|
|
|
|
node.setStatements(block.getStatements());
|
|
|
|
List<Graph.Block> predecessors = program.getGraph().getPredecessors(block);
|
|
if(!predecessors.isEmpty()) {
|
|
for(Graph.Block predecessor : predecessors) {
|
|
|
|
String predecessorNodeName = predecessor.getLabel().getFullName();
|
|
String predecessorLocalNodeName = predecessor.getScope().getLocalName();
|
|
|
|
if (program.isProcedureEntry(block)) {
|
|
MermaidSubGraph procedureSubGraph = mermaidSubGraph.addProcedureSubGraph(predecessorLocalNodeName);
|
|
MermaidNode nodePredecessor = procedureSubGraph.addNode(predecessorNodeName);
|
|
mermaidSubGraph.addFlow(nodePredecessor, node, "call", MermaidFlow.Type.FULL, MermaidFlow.Direction.UNI);
|
|
String blockReturnName = block.getLabel().getLocalName() + "::@return";
|
|
MermaidNode nodeReturn = mermaidSubGraph.addNode(blockReturnName);
|
|
mermaidSubGraph.addFlow(nodeReturn, nodePredecessor, "return", MermaidFlow.Type.FULL, MermaidFlow.Direction.UNI);
|
|
} else {
|
|
MermaidNode nodePredecessor = mermaidSubGraph.addNode(predecessorNodeName);
|
|
LabelRef successorLabel = predecessor.getConditionalSuccessor();
|
|
Graph.Block successor = null;
|
|
if(successorLabel != null) {
|
|
successor = graph.getBlock(successorLabel);
|
|
}
|
|
if( successor != null && successor.equals(block)) {
|
|
mermaidSubGraph.addFlow(nodePredecessor, node, "true", MermaidFlow.Type.DOTTED, MermaidFlow.Direction.UNI);
|
|
} else {
|
|
mermaidSubGraph.addFlow(nodePredecessor, node, null, MermaidFlow.Type.DOTTED, MermaidFlow.Direction.UNI);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!block.getStatements().isEmpty()) {
|
|
for (Statement statement : block.getStatements()) {
|
|
if(statement instanceof StatementCall) {
|
|
String procedureName = ((StatementCall) statement).getProcedureName();
|
|
MermaidSubGraph procedureSubGraph = mermaidSubGraph.addProcedureSubGraph(procedureName);
|
|
MermaidNode procedureNode = procedureSubGraph.addNode(procedureName);
|
|
mermaidSubGraph.addFlow(node, procedureNode,"call", MermaidFlow.Type.FULL, MermaidFlow.Direction.BI);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private String mermaidCFGProcedure(Procedure procedure, Graph graph) {
|
|
String procedureName = procedure.getLocalName();
|
|
String procedureTitle = procedure.toString(program);
|
|
|
|
MermaidSubGraph subGraphProcedure = new MermaidSubGraph(procedureName, procedureTitle);
|
|
mermaidGraph.addProcedureSubGraph(subGraphProcedure);
|
|
for(Graph.Block block : graph.getAllBlocks()) {
|
|
mermaidCFGBlock(graph, block, subGraphProcedure);
|
|
}
|
|
|
|
return mermaidGraph.getText(program);
|
|
}
|
|
|
|
@Override
|
|
public String generateReport(Program program) {
|
|
StringBuilder report = new StringBuilder();
|
|
for(ProcedureCompilation procedureCompilation : program.getProcedureCompilations()) {
|
|
Procedure procedure = program.getScope().getProcedure(procedureCompilation.getProcedureRef());
|
|
Graph graph = procedureCompilation.getGraph();
|
|
if(graph != null) {
|
|
mermaidGraph = new MermaidGraph(MermaidGraph.Direction.TOP_DOWN);
|
|
report.append("Procedure " + procedure.getFullName() + "\n");
|
|
report.append("```mermaid\n");
|
|
report.append(configureReport());
|
|
report.append(mermaidCFGProcedure(procedure, graph));
|
|
report.append("```\n\n");
|
|
}
|
|
}
|
|
return report.toString();
|
|
}
|
|
}
|