brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.1 KiB · 5a57987 Raw
226 lines · python
1#!/usr/bin/env python2#3# ====- Generate documentation for libc functions  ------------*- python -*--==#4#5# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.6# See https://llvm.org/LICENSE.txt for license information.7# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception8#9# ==-------------------------------------------------------------------------==#10from argparse import ArgumentParser, Namespace11from pathlib import Path12from typing import Dict13import os14import sys15import yaml16 17from header import Header18 19 20class DocgenAPIFormatError(Exception):21    """Raised on fatal formatting errors with a description of a formatting error"""22 23 24def check_api(header: Header, api: Dict):25    """26    Checks that docgen yaml files are properly formatted. If there are any27    fatal formatting errors, raises exceptions with error messages useful for28    fixing formatting. Warnings are printed to stderr on non-fatal formatting29    errors. The code that runs after ``check_api(api)`` is called expects that30    ``check_api`` executed without raising formatting exceptions so the yaml31    matches the formatting specified here.32 33    The yaml file may contain:34    * an optional macros object35    * an optional functions object36 37    Formatting of ``macros`` and ``functions`` objects38    ==================================================39 40    If a macros or functions object is present, then it may contain nested41    objects. Each of these nested objects should have a name matching a macro42    or function's name, and each nested object must have the property:43    ``"c-definition"`` or ``"posix-definition"``.44 45    Description of properties46    =========================47    The defined property is intended to be a reference to a part of the48    standard that defines the function or macro. For the ``"c-definition"`` property,49    this should be a C standard section number. For the ``"posix-definition"`` property,50    this should be a link to the definition.51 52    :param api: docgen yaml file contents parsed into a dict53    """54    errors = []55    # We require entries to have at least one of these.56    possible_keys = [57        "c-definition",58        "in-latest-posix",59        "removed-in-posix-2008",60        "removed-in-posix-2024",61    ]62 63    # Validate macros64    if "macros" in api:65        if not header.macro_file_exists():66            print(67                f"warning: Macro definitions are listed for {header.name}, but no macro file can be found in the directory tree rooted at {header.macros_dir}. All macros will be listed as not implemented.",68                file=sys.stderr,69            )70 71        macros = api["macros"]72 73        for name, obj in macros.items():74            if not any(k in obj for k in possible_keys):75                err = f"error: Macro {name} does not contain at least one required property: {possible_keys}"76                errors.append(err)77 78    # Validate functions79    if "functions" in api:80        if not header.fns_dir_exists():81            print(82                f"warning: Function definitions are listed for {header.name}, but no function implementation directory exists at {header.fns_dir}. All functions will be listed as not implemented.",83                file=sys.stderr,84            )85 86        fns = api["functions"]87        for name, obj in fns.items():88            if not any(k in obj for k in possible_keys):89                err = f"error: function {name} does not contain at least one required property: {possible_keys}"90                errors.append(err)91 92    if errors:93        raise DocgenAPIFormatError("\n".join(errors))94 95 96def load_api(header: Header) -> Dict:97    api = header.docgen_yaml.read_text(encoding="utf-8")98    return yaml.safe_load(api)99 100 101def print_tbl_dir(name):102    print(103        f"""104.. list-table::105  :widths: auto106  :align: center107  :header-rows: 1108 109  * - {name}110    - Implemented111    - C23 Standard Section112    - POSIX Docs"""113    )114 115 116def print_functions_rst(header: Header, functions: Dict):117    tbl_hdr = "Functions"118    print(tbl_hdr)119    print("=" * len(tbl_hdr))120 121    print_tbl_dir("Function")122 123    for name in sorted(functions.keys()):124        print(f"  * - {name}")125 126        if header.fns_dir_exists() and header.implements_fn(name):127            print("    - |check|")128        else:129            print("    -")130 131        if "c-definition" in functions[name]:132            print(f'    - {functions[name]["c-definition"]}')133        else:134            print("    -")135 136        if "in-latest-posix" in functions[name]:137            print(138                f"    - `POSIX.1-2024 <https://pubs.opengroup.org/onlinepubs/9799919799/functions/{name}.html>`__"139            )140        elif "removed-in-posix-2008" in functions[name]:141            print(142                f"    - `removed in POSIX.1-2008 <https://pubs.opengroup.org/onlinepubs/007904875/functions/{name}.html>`__"143            )144        elif "removed-in-posix-2024" in functions[name]:145            print(146                f"    - `removed in POSIX.1-2024 <https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/{name}.html>`__"147            )148        else:149            print("    -")150 151 152def print_macros_rst(header: Header, macros: Dict):153    tbl_hdr = "Macros"154    print(tbl_hdr)155    print("=" * len(tbl_hdr))156 157    print_tbl_dir("Macro")158 159    for name in sorted(macros.keys()):160        print(f"  * - {name}")161 162        if header.macro_file_exists() and header.implements_macro(name):163            print("    - |check|")164        else:165            print("    -")166 167        if "c-definition" in macros[name]:168            print(f'    - {macros[name]["c-definition"]}')169        else:170            print("    -")171 172        if "in-latest-posix" in macros[name]:173            print(174                f"    - `POSIX.1-2024 <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/{header.name}.html>`__"175            )176        else:177            print("    -")178    print()179 180 181def print_impl_status_rst(header: Header, api: Dict):182    if os.sep in header.name:183        print(".. include:: ../../check.rst\n")184    else:185        print(".. include:: ../check.rst\n")186 187    print("=" * len(header.name))188    print(header.name)189    print("=" * len(header.name))190    print()191 192    # the macro and function sections are both optional193    if "macros" in api:194        print_macros_rst(header, api["macros"])195 196    if "functions" in api:197        print_functions_rst(header, api["functions"])198 199 200# This code implicitly relies on docgen.py being in the same dir as the yaml201# files and is likely to need to be fixed when re-integrating docgen into202# hdrgen.203def get_choices() -> list:204    choices = []205    for path in Path(__file__).parent.rglob("*.yaml"):206        fname = path.with_suffix(".h").name207        if path.parent != Path(__file__).parent:208            fname = path.parent.name + os.sep + fname209        choices.append(fname)210    return choices211 212 213def parse_args() -> Namespace:214    parser = ArgumentParser()215    parser.add_argument("header_name", choices=get_choices())216    return parser.parse_args()217 218 219if __name__ == "__main__":220    args = parse_args()221    header = Header(args.header_name)222    api = load_api(header)223    check_api(header, api)224 225    print_impl_status_rst(header, api)226