Skip to content

Commit

Permalink
Minor Graph typing fixes (#38)
Browse files Browse the repository at this point in the history
  • Loading branch information
gabrielbessler committed May 5, 2021
1 parent c589495 commit 40f00b6
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 43 deletions.
3 changes: 2 additions & 1 deletion src/core/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -754,7 +754,8 @@ def do_to_klee_format(self, flags: Options, file_path: str) -> None:
return
self.data.klee_formatted_files = {**self.data.klee_formatted_files,
**klee_formatted_files}
self.logger.v_msg(f"Created {Colors.MAGENTA.value}{' '.join(list(klee_formatted_files.keys()))}{Colors.ENDC.value}")
log_str = f"Created {Colors.MAGENTA.value}{' '.join(list(klee_formatted_files.keys()))}{Colors.ENDC.value}"
self.logger.v_msg(log_str)

def klee_output_indices(self, klee_output: str) -> tuple[int, int, int]:
"""Get the indicies of statistics we care about in the Klee output string."""
Expand Down
18 changes: 9 additions & 9 deletions src/core/command_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from enum import Enum
from typing import Optional, Union, cast

import pandas as pd
import pandas as pd # type: ignore
from rich.console import Console
from rich.table import Table

Expand Down Expand Up @@ -74,15 +74,15 @@ def export_metrics(self, name: str, new_name: str) -> None:
self.logger.i_msg(f"Made file {new_name}_metrics in /app/code/exports/")
elif name == "*":
data = pd.DataFrame({"graph_name": [], "apc": [],
"cyclo": [], "npath": []})
for m_name in self.metrics:
"cyclo": [], "npath": []})
for m_name in self.metrics:
metric_value = self.metrics[m_name]
new_row: dict = {"graph_name": m_name, "apc": metric_value[2][1],
"cyclo": metric_value[0][1], "npath": metric_value[1][1]}
new_row = {"graph_name": m_name, "apc": metric_value[2][1],
"cyclo": metric_value[0][1], "npath": metric_value[1][1]}
data = data.append(new_row, ignore_index=True)

data.to_csv("/app/code/exports/metrics.csv")
self.logger.i_msg(f"Made file metrics.csv in /app/code/exports/")
self.logger.i_msg("Made file metrics.csv in /app/code/exports/")
else:
self.logger.e_msg(f"{str(ObjTypes.METRIC).capitalize()} {name} not found.")

Expand Down Expand Up @@ -216,8 +216,8 @@ def show_graphs(self, name: str, names: list[str]) -> None:
if self.rich:
rows = self.graphs[graph_name].rich_repr()
table = Table(title=f"Graph {graph_name}")
table.add_column("Graph Property",style="cyan")
table.add_column("Value",style="magenta")
table.add_column("Graph Property", style="cyan")
table.add_column("Value", style="magenta")
for row in rows:
table.add_row(*row)
Console().print(table)
Expand Down
54 changes: 26 additions & 28 deletions src/graph/control_flow_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,9 @@ def __str__(self) -> str:
out += f"Calls: {self.calls}"
return out


def rich_repr(self) -> List[str]:
"""Returns a list of rows that can be used to represent the graph in Rich."""
return [("Metadata", self.__str__())]
def rich_repr(self) -> list[list[str]]:
"""Return a list of rows that can be used to represent the graph in Rich."""
return [["Metadata", self.__str__()]]

@staticmethod
def with_loc(loc: int) -> Option:
Expand Down Expand Up @@ -97,11 +96,10 @@ def __str__(self) -> str:

return str(self.graph)

def rich_repr(self) -> List[str]:
"""Returns a list of rows that can be used to represent the graph in Rich."""
def rich_repr(self) -> list[list[str]]:
"""Return a list of rows that can be used to represent the graph in Rich."""
return self.metadata.rich_repr() + self.graph.rich_repr()


@staticmethod
def check_call(match: Match[str]) -> Optional[dict[int, str]]:
"""Find and return any functions called on a node."""
Expand Down Expand Up @@ -170,7 +168,7 @@ def from_file(filename: str, graph_type: Type[Graph] = AdjListGraph,
return ControlFlowGraph(graph, Metadata(*options, Metadata.with_calls(calls)))

@staticmethod
def get_calls_structure(graphs: dict[str, ControlFlowGraph]) -> Tuple[list[list[str]], list[str]]:
def get_calls_structure(graphs: dict[str, ControlFlowGraph]) -> Optional[Tuple[list[list[str]], list[str]]]:
"""Create lists describing the hierarchy of a program's function calls."""
calls_list = []
simple_funcs = []
Expand All @@ -189,31 +187,31 @@ def get_calls_structure(graphs: dict[str, ControlFlowGraph]) -> Tuple[list[list[
@staticmethod
def stitch(graphs: dict[str, ControlFlowGraph]) -> ControlFlowGraph:
"""Create new CFG by substituting function calls with their graphs."""
calls_list, simple_funcs = ControlFlowGraph.get_calls_structure(graphs)
call_structure = ControlFlowGraph.get_calls_structure(graphs)
if call_structure is not None:
calls_list, simple_funcs = call_structure

while calls_list:
for func_pair in calls_list:
if func_pair[0] == func_pair[1]:
for _ in range(len(
calls_function(graphs[func_pair[0]].metadata.calls, func_pair[1])
)):
node = calls_function(graphs[func_pair[0]].metadata.calls, func_pair[1])[0]
graphs[func_pair[0]] = ControlFlowGraph.recursify(graphs[func_pair[0]], node)
func0, func1 = func_pair
if func0 == func1:
for _ in range(len(calls_function(graphs[func0].metadata.calls, func1))):
node = calls_function(graphs[func0].metadata.calls, func1)[0]
graphs[func0] = ControlFlowGraph.recursify(graphs[func0], node)
calls_list.remove(func_pair)
if func_pair[0] not in [i[0] for i in calls_list]:
simple_funcs.append(func_pair[0])

elif func_pair[1] in simple_funcs:
for _ in range(len(
calls_function(graphs[func_pair[0]].metadata.calls, func_pair[1])
)):
cfg1, cfg2 = graphs[func_pair[0]], graphs[func_pair[1]]
node = calls_function(graphs[func_pair[0]].metadata.calls, func_pair[1])[0]
cfg1.metadata.calls.pop(node)
graphs[func_pair[0]] = ControlFlowGraph.compose(cfg1, cfg2, node)
if func0 not in [i[0] for i in calls_list]:
simple_funcs.append(func0)

elif func1 in simple_funcs:
for _ in range(len(calls_function(graphs[func0].metadata.calls, func1))):
cfg1, cfg2 = graphs[func0], graphs[func1]
if cfg1.metadata.calls is not None:
node = calls_function(cfg1.metadata.calls, func1)[0]
cfg1.metadata.calls.pop(node)
graphs[func0] = ControlFlowGraph.compose(cfg1, cfg2, node)
calls_list.remove(func_pair)
if func_pair[0] not in [i[0] for i in calls_list]:
simple_funcs.append(func_pair[0])
if func0 not in [i[0] for i in calls_list]:
simple_funcs.append(func0)

return graphs[simple_funcs[-1]]

Expand Down
8 changes: 4 additions & 4 deletions src/graph/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ def update_with_edge(self, match: Match[str]) -> None:
"""

@abstractmethod
def rich_repr(self) -> list[str]:
"""Returns a list of rows that can be used to construct a table representation in Rich."""
def rich_repr(self) -> list[list[str]]:
"""Return a list of rows that can be used to construct a table representation in Rich."""


class GenericGraph(Graph, Generic[Type], ABC):
Expand Down Expand Up @@ -183,8 +183,8 @@ def _initialize_dot_file(self) -> str:

return out

def rich_repr(self) -> list[list[[str]]]:
"""Returns a list of rows that can be used to construct a table representation in Rich."""
def rich_repr(self) -> list[list[str]]:
"""Return a list of rows that can be used to construct a table representation in Rich."""
return [
["Edges", str(self.edge_rules())],
["Total Edges", str(self.edge_count())],
Expand Down
2 changes: 1 addition & 1 deletion src/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def show_func_defs(filename: str) -> Dict[str, str]:
return names


def calls_function(calls_dict: Dict[int, str], function_cfg: str) -> List[int]:
def calls_function(calls_dict: Optional[dict[int, str]], function_cfg: str) -> list[int]:
"""Check if a CFG contains a call to another function."""
nodes = []
func_name = os.path.splitext(os.path.splitext(function_cfg)[0])[1][1:]
Expand Down

0 comments on commit 40f00b6

Please sign in to comment.