mirror of
https://github.com/syssec-utd/pylingual.git
synced 2026-05-10 18:39:03 -07:00
cflow script
This commit is contained in:
+20
-9
@@ -81,12 +81,12 @@ def run(file: Path, out_dir: Path, version: PythonVersion, print=False):
|
|||||||
result = compare_pyc(in_pyc, out_pyc)
|
result = compare_pyc(in_pyc, out_pyc)
|
||||||
if print:
|
if print:
|
||||||
print_result(f"Equivalance results for {file}", result)
|
print_result(f"Equivalance results for {file}", result)
|
||||||
return Result.Success if all(x.success for x in result) else Result.Failure, file
|
return Result.Success if all(x.success for x in result) else Result.Failure, file, out_dir
|
||||||
except (CompileError, SyntaxError):
|
except (CompileError, SyntaxError):
|
||||||
return Result.CompileError, file
|
return Result.CompileError, file, out_dir
|
||||||
except Exception:
|
except Exception:
|
||||||
rich.get_console().print_exception()
|
rich.get_console().print_exception()
|
||||||
return Result.Error, file
|
return Result.Error, file, out_dir
|
||||||
|
|
||||||
|
|
||||||
class NoPool:
|
class NoPool:
|
||||||
@@ -94,12 +94,21 @@ class NoPool:
|
|||||||
|
|
||||||
|
|
||||||
def print_diff(a: Path, b: Path):
|
def print_diff(a: Path, b: Path):
|
||||||
a_lines = a.read_text().split("\n")
|
a_text = a.read_text()
|
||||||
b_lines = b.read_text().split("\n")
|
b_text = b.read_text()
|
||||||
|
a_lines = a_text.split("\n")
|
||||||
|
b_lines = b_text.split("\n")
|
||||||
console = rich.console.Console(highlight=False)
|
console = rich.console.Console(highlight=False)
|
||||||
|
print(a_text)
|
||||||
|
print("=" * 40)
|
||||||
|
print(b_text)
|
||||||
|
print("=" * 40)
|
||||||
|
line = None
|
||||||
for line in difflib.unified_diff(a_lines, b_lines, str(a), str(b)):
|
for line in difflib.unified_diff(a_lines, b_lines, str(a), str(b)):
|
||||||
style = "red" if line[0] == "-" else "green" if line[0] == "+" else "blue" if line[0] == "@" else ""
|
style = "red" if line[0] == "-" else "green" if line[0] == "+" else "blue" if line[0] == "@" else ""
|
||||||
console.print(line, style=style)
|
console.print(line, style=style)
|
||||||
|
if line is None:
|
||||||
|
print("equal")
|
||||||
|
|
||||||
|
|
||||||
def get_unused(a: Path, _=True):
|
def get_unused(a: Path, _=True):
|
||||||
@@ -138,10 +147,10 @@ def main(input: Path, output: str, version: PythonVersion, graph: str | None, pr
|
|||||||
if results in [Result.CompileError, Result.Error]:
|
if results in [Result.CompileError, Result.Error]:
|
||||||
print(results)
|
print(results)
|
||||||
else:
|
else:
|
||||||
print_diff(o / input.name / "a.py", o / input.name / "b.py")
|
print_diff(o / input.stem / "a.py", o / input.stem / "b.py")
|
||||||
else:
|
else:
|
||||||
if not output:
|
if not output:
|
||||||
out_dir = get_unused(prefix / input.stem)
|
out_dir = get_unused(prefix / str(version) / input.stem)
|
||||||
else:
|
else:
|
||||||
out_dir = prefix / output
|
out_dir = prefix / output
|
||||||
print(f"Saving results to {out_dir}")
|
print(f"Saving results to {out_dir}")
|
||||||
@@ -156,16 +165,18 @@ def main(input: Path, output: str, version: PythonVersion, graph: str | None, pr
|
|||||||
pool = multiprocessing.Pool(processes=processes)
|
pool = multiprocessing.Pool(processes=processes)
|
||||||
else:
|
else:
|
||||||
pool = contextlib.nullcontext(NoPool)
|
pool = contextlib.nullcontext(NoPool)
|
||||||
|
dir_map = {}
|
||||||
with pool as p:
|
with pool as p:
|
||||||
for result, input in track(p.imap_unordered(f, files), total=len(files)):
|
for result, input, od in track(p.imap_unordered(f, files), total=len(files)):
|
||||||
results[result].append(input)
|
results[result].append(input)
|
||||||
|
dir_map[str(input)] = str(od)
|
||||||
|
|
||||||
for res in Result:
|
for res in Result:
|
||||||
print(f"{res}: {len(results[res])}")
|
print(f"{res}: {len(results[res])}")
|
||||||
total = sum(len(x) for x in results.values())
|
total = sum(len(x) for x in results.values())
|
||||||
if total:
|
if total:
|
||||||
print(f"{len(results[Result.Success])} / {total} succeeded ({len(results[Result.Success]) / total:.3%})")
|
print(f"{len(results[Result.Success])} / {total} succeeded ({len(results[Result.Success]) / total:.3%})")
|
||||||
res = json.dumps({k.value: list(map(str, v)) for k, v in results.items()})
|
res = json.dumps({k.value: list(map(str, v)) for k, v in results.items()} | {'map': dir_map})
|
||||||
(out_dir / "results.json").write_text(res)
|
(out_dir / "results.json").write_text(res)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class CFG(DiGraph_CFT):
|
|||||||
CFG.graph_format = fmt
|
CFG.graph_format = fmt
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_graph(cfg: nx.DiGraph, bytecode: EditableBytecode) -> CFG:
|
def from_graph(cfg: nx.DiGraph, bytecode: EditableBytecode, iterate=True) -> CFG:
|
||||||
self = CFG(cfg)
|
self = CFG(cfg)
|
||||||
|
|
||||||
self.bytecode = bytecode
|
self.bytecode = bytecode
|
||||||
@@ -55,6 +55,8 @@ class CFG(DiGraph_CFT):
|
|||||||
self.add_edges_from((node, self.end, EdgeKind.Meta.prop()) for node in self.nodes if isinstance(node, InstTemplate) and self.out_degree(node) == 0)
|
self.add_edges_from((node, self.end, EdgeKind.Meta.prop()) for node in self.nodes if isinstance(node, InstTemplate) and self.out_degree(node) == 0)
|
||||||
|
|
||||||
BlockTemplate.match_all(self)
|
BlockTemplate.match_all(self)
|
||||||
|
if iterate:
|
||||||
|
self.iterate()
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ class BlockTemplate(ControlFlowTemplate):
|
|||||||
continue
|
continue
|
||||||
BlockTemplate.try_match(cfg, node)
|
BlockTemplate.try_match(cfg, node)
|
||||||
cfg.iterate = it
|
cfg.iterate = it
|
||||||
cfg.iterate()
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -207,8 +207,8 @@ def compare_pyc(pyc_a: PYCFile | Path, pyc_b: PYCFile | Path) -> list[TestResult
|
|||||||
continue
|
continue
|
||||||
cfg_a = bytecode_to_control_flow_graph(bytecode_a)
|
cfg_a = bytecode_to_control_flow_graph(bytecode_a)
|
||||||
cfg_b = bytecode_to_control_flow_graph(bytecode_b)
|
cfg_b = bytecode_to_control_flow_graph(bytecode_b)
|
||||||
block_graph_a = CFG.from_graph(cfg_a, bytecode_a)
|
block_graph_a = CFG.from_graph(cfg_a, bytecode_a, False)
|
||||||
block_graph_b = CFG.from_graph(cfg_b, bytecode_b)
|
block_graph_b = CFG.from_graph(cfg_b, bytecode_b, False)
|
||||||
if not is_control_flow_equivalent(block_graph_a, block_graph_b):
|
if not is_control_flow_equivalent(block_graph_a, block_graph_b):
|
||||||
test_result = TestResult(False, "Different control flow", bytecode_a, bytecode_b)
|
test_result = TestResult(False, "Different control flow", bytecode_a, bytecode_b)
|
||||||
results.append(test_result)
|
results.append(test_result)
|
||||||
|
|||||||
Reference in New Issue
Block a user