#!/usr/bin/env python3 """Generate wolfram-cpp owned-handle typedefs from wolfram's wf_*_free set. Scans the wolfram C public headers for ``void wf__free(wf_ *...)`` and emits a header declaring ``wolfram::unique_handle, wf__free>`` typedefs plus the ``#include``s needed to make those symbols visible. This mirrors the project convention of generating C-adjacent code from the C headers with Python. Usage: python3 tools/gen_owners.py """ import re import sys from pathlib import Path # Match `void wf__free(wf_ *name)`. The backreference ensures the freed # type matches the function prefix. Excludes `wf_*_json_free(char*)` (strings). HEADER_RE = re.compile( r"void\s+wf_([A-Za-z0-9_]+)_free\s*\(\s*wf_\1\s*\*\s*\w+\s*\)" ) def main() -> int: inc_dir = Path(sys.argv[1] if len(sys.argv) > 1 else "include/wolfram") out = Path(sys.argv[2]) if len(sys.argv) > 2 else Path("generated_owners.hpp") types: dict[str, str] = {} includes: set[str] = set() # Recursively scan all .h files (including oauth/, repo/ subdirectories) for h in sorted(inc_dir.rglob("*.h")): # Skip the json-enhanced vendored copy — it duplicates json.h symbols. if "json-enhanced" in h.parts: continue text = h.read_text(encoding="utf-8", errors="ignore") for m in HEADER_RE.finditer(text): t = m.group(1) if t not in types: rel = h.relative_to(inc_dir) inc = f"wolfram/{rel.as_posix()}" types[t] = inc includes.add(inc) lines = [ "/* Generated by cpp/wolfram-cpp/tools/gen_owners.py; do not edit. */", "#ifndef WOLFRAM_CPP_GENERATED_OWNERS_HPP", "#define WOLFRAM_CPP_GENERATED_OWNERS_HPP", "", ] for inc in sorted(includes): lines.append(f'#include <{inc}>') lines += [ "", '#include "wolfram/unique_handle.hpp"', "", "namespace wolfram {", "", ] for t in sorted(types): lines.append(f"using wf_{t}_handle = unique_handle;") lines += [ "", "} // namespace wolfram", "", "#endif", ] out.write_text("\n".join(lines) + "\n", encoding="utf-8") print(f"wrote {out}: {len(types)} owned handles from {len(includes)} headers") return 0 if __name__ == "__main__": raise SystemExit(main())