Michael Flanders 2996cb7970
[libc][docs] use docgen to generate stdbit rst docs (#88540)
Closes #88066.

Compared to before, the function names in the stdbit table are sorted by
function name, not order-of-appearance in the standard. Since macros
aren't printed by docgen.py and are still a TODO in the code, they are
also not printed in the new stdbit.h docs.

Adds some checks to docgen.py for conditions that tripped me up.

Add code to docgen.py to add the include of the `|check|` rewriter,
since all other generated files need it.
2024-04-12 14:35:10 -07:00

94 lines
2.6 KiB
Python
Executable File

#!/usr/bin/env python
#
# ====- Generate documentation for libc functions ------------*- python -*--==#
#
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
# ==-------------------------------------------------------------------------==#
from argparse import ArgumentParser, Namespace
from pathlib import Path
from typing import Dict
import sys
import json
def load_api(hname: str) -> Dict:
p = Path(__file__).parent / Path(hname).with_suffix(".json")
api = p.read_text(encoding="utf-8")
return json.loads(api)
# TODO: we may need to get more sophisticated for less generic implementations.
# Does libc/src/{hname minus .h suffix}/{fname}.cpp exist?
def is_implemented(hname: str, fname: str) -> bool:
path = Path(
Path(__file__).parent.parent.parent,
"src",
hname.rstrip(".h")
)
if not path.exists():
raise FileNotFoundError(f"implementation dir does not exist: {path}")
if not path.is_dir():
raise NotADirectoryError(f"implementation dir is not a dir: {path}")
# Recursively search for the target source file in the subdirectories under
# libc/src/{hname}.
for _ in path.glob("**/" + fname + ".cpp"):
return True
return False
def print_functions(header: str, functions: Dict):
for key in sorted(functions.keys()):
print(f" * - {key}")
if is_implemented(header, key):
print(" - |check|")
else:
print(" -")
# defined is optional. Having any content is optional.
if functions[key] is not None and "defined" in functions[key]:
print(f' - {functions[key]["defined"]}')
else:
print(" -")
def print_header(header: str, api: Dict):
print(".. include:: check.rst\n")
fns = f"{header} Functions"
print(fns)
print("=" * (len(fns)))
print(
f"""
.. list-table::
:widths: auto
:align: center
:header-rows: 1
* - Function
- Implemented
- Standard"""
)
# TODO: how do we want to signal implementation of macros?
print_functions(header, api["functions"])
def parse_args() -> Namespace:
parser = ArgumentParser()
choices = [p.with_suffix(".h").name for p in Path(__file__).parent.glob("*.json")]
parser.add_argument("header_name", choices=choices)
return parser.parse_args()
if __name__ == "__main__":
args = parse_args()
api = load_api(args.header_name)
print_header(args.header_name, api)