Add nac3/find_ndarray_anomalies.py
This commit is contained in:
parent
c4b5957e3a
commit
fdd770b498
109
nac3/find_ndarray_anomalies.py
Normal file
109
nac3/find_ndarray_anomalies.py
Normal file
@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# # PLACE ME IN nac3standalone/demo/find_ndarray_anomalies.py AND DO `chmod +x` ON ME!!
|
||||
|
||||
from __future__ import annotations
|
||||
from pathlib import Path
|
||||
from typing import *
|
||||
import argparse
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
class SourceTemplate(NamedTuple):
|
||||
source: str
|
||||
|
||||
def _list_all_functions(self) -> list[str]:
|
||||
# Find all `def ???()` functions
|
||||
pattern = re.compile(
|
||||
r"^def\s+(?P<name>.+?)\s*\(.*?\)\s*:\s*$",
|
||||
re.MULTILINE
|
||||
)
|
||||
|
||||
results = pattern.findall(self.source)
|
||||
if not results:
|
||||
raise RuntimeError("Something is wrong with the regex")
|
||||
|
||||
return results
|
||||
|
||||
def list_all_test_functions(self) -> Iterator[str]:
|
||||
# Find all `def test_*()` functions
|
||||
return [ n for n in self._list_all_functions() if n.startswith("test_") ]
|
||||
|
||||
def subst_function(self, func_name: str) -> str:
|
||||
# Append a `def run()` at the end of `source`
|
||||
return self.source + f"""
|
||||
|
||||
def run() -> int32:
|
||||
{func_name}()
|
||||
return 0
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def load(cls) -> SourceTemplate:
|
||||
# What this function does:
|
||||
# 1. Read src/ndarray.py
|
||||
# 2. Chop off the `run()` function, leaving behind everything else.
|
||||
# - This is done by finding the `def run() -> int32:` line and
|
||||
# remove that line and everything below it.
|
||||
original_source = Path("src/ndarray.py").read_text()
|
||||
|
||||
# Read the function's comment
|
||||
pattern = re.compile(
|
||||
r"(?P<source>.+?)^\s+^def\s+run\(\)\s*->\s*int32\s*:\s*$.*",
|
||||
re.MULTILINE | re.DOTALL
|
||||
)
|
||||
|
||||
regex_result = pattern.fullmatch(original_source)
|
||||
if regex_result is None:
|
||||
raise RuntimeError("Regex cannot find `def run() -> int32:`!")
|
||||
|
||||
# source is now original_source but without the
|
||||
# `def run() -> int32:` line and everything below it.
|
||||
source = regex_result.group("source")
|
||||
return cls(source=source)
|
||||
|
||||
def proc_nac3(
|
||||
py_path: Path,
|
||||
size_t: int,
|
||||
lli: bool,
|
||||
nac3args: Optional[list[str]] = None
|
||||
) -> subprocess.CompletedProcess:
|
||||
# Prepare args
|
||||
args = ["./run_demo.sh"]
|
||||
if lli:
|
||||
args.append("--lli")
|
||||
|
||||
args.extend(["--out", "/dev/stdout"])
|
||||
|
||||
if nac3args is not None:
|
||||
args.extend(nac3args)
|
||||
|
||||
args.extend(["-s", str(size_t)])
|
||||
args.append(str(py_path))
|
||||
|
||||
# Run
|
||||
return subprocess.run(args, capture_output=True)
|
||||
|
||||
def main():
|
||||
template = SourceTemplate.load()
|
||||
|
||||
tmp_py_path = Path("_ndarray_tmp.py")
|
||||
|
||||
for test_func in template.list_all_test_functions():
|
||||
source = template.subst_function(test_func)
|
||||
tmp_py_path.write_text(source)
|
||||
|
||||
# We only want to find LLVM codegen defects,
|
||||
# therefore we don't need to run them, and `--lli` doesn't matter.
|
||||
nac3result = proc_nac3(tmp_py_path, 32, lli=False, nac3args=["--debug"])
|
||||
if nac3result.returncode != 0:
|
||||
print(f"\n\n\n>>>>>>>>>>>>>> Error in {test_func}")
|
||||
# utf8 decode content
|
||||
# There should be no raw bytes output from nac3core when compiling
|
||||
error = nac3result.stderr.decode()
|
||||
print(error)
|
||||
|
||||
print("\n\n\nDone")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in New Issue
Block a user