From bddc6c13fc8210966452fa1c205aa36ad93c4f06 Mon Sep 17 00:00:00 2001 From: Esteban Zimanyi Date: Mon, 26 Oct 2026 15:08:39 +0100 Subject: [PATCH] Read the MEOS Doxygen of pgtypes alike in every @param reader The readers of the MEOS @param Doxygen scan one list of sources, doxygen_sources: the src and include trees of meos/ and the sibling pgtypes/ tree, the vendored PostgreSQL base-type layer that defines public MEOS functions outside meos/ and documents them on its .c definitions. They also pair a Doxygen block with its function by one pattern, _FUNC, which steps over the preprocessor lines that separate the two where pgtypes/ guards the MEOS twin of a function with #if MEOS. extract_nullable and extract_param_docs read them as extract_param_names and extract_outparams do, so a parameter documented in pgtypes/ states its nullability to the catalog as its direction already does, on the function its block documents. Witness: the catalog derived from MobilityDB master f3d480c80a gains shape.nullable ["vars"] on jsonb_path_exists, jsonb_path_match, jsonb_path_query_array, jsonb_path_query_first and jsonb_path_query_all, whose @param lines in pgtypes/utils/jsonpath_exec.c state that vars may be NULL above an #if MEOS guard; no other function of the 6721 changes, and shape.outParams is unchanged. The 509 tests pass. --- parser/nullable.py | 27 +++++++++------------------ parser/outparam.py | 43 +++++++++++++++++++++++-------------------- 2 files changed, 32 insertions(+), 38 deletions(-) diff --git a/parser/nullable.py b/parser/nullable.py index 8407496..c828eb2 100644 --- a/parser/nullable.py +++ b/parser/nullable.py @@ -12,17 +12,14 @@ """ from __future__ import annotations -import glob import re from pathlib import Path -# Doxygen block immediately followed by a function definition (``name(...) {``). -_FUNC = re.compile( - r'/\*\*(?P.*?)\*/\s*\n' - r'(?:[A-Za-z_][\w\s\*]*?\n)?' # optional return-type line - r'(?P[a-z][a-z0-9_]*)\s*\(' - r'(?P[^;{]*?)\)\s*\{', - re.S) +# The Doxygen block of a function and the files that carry it are the ones every +# @param reader shares (#extract_outparams), so a block separated from its function +# by an `#if MEOS` guard in pgtypes/ is paired with it here too. +from parser.outparam import _FUNC, doxygen_sources + # One @param entry: capture the (possibly comma-separated) names + description. _PARAM = re.compile( r'@param\[[^\]]*\]\s+(?P\w+(?:\s*,\s*\w+)*)\s+(?P.*?)' @@ -32,13 +29,10 @@ def extract_nullable(meos_root: str | Path) -> dict[str, list[str]]: - """Return ``{function: [nullable params]}`` from the MEOS C sources under - ``meos_root`` (scans both ``src`` and ``include``).""" - root = Path(meos_root) + """Return ``{function: [nullable params]}`` from the MEOS C sources + (#doxygen_sources).""" out: dict[str, list[str]] = {} - files = glob.glob(str(root / "src/**/*.c"), recursive=True) - files += glob.glob(str(root / "include/**/*.h"), recursive=True) - for f in files: + for f in doxygen_sources(meos_root): txt = Path(f).read_text(errors="ignore") for m in _FUNC.finditer(txt): name = m.group("name") @@ -55,11 +49,8 @@ def extract_nullable(meos_root: str | Path) -> dict[str, list[str]]: def extract_param_docs(meos_root: str | Path) -> dict[str, dict[str, str]]: """Return ``{function: {parameter: description}}`` from the MEOS C Doxygen, the ``@param`` text #extract_nullable reads, whitespace collapsed, over the same files.""" - root = Path(meos_root) out: dict[str, dict[str, str]] = {} - files = glob.glob(str(root / "src/**/*.c"), recursive=True) - files += glob.glob(str(root / "include/**/*.h"), recursive=True) - for f in files: + for f in doxygen_sources(meos_root): txt = Path(f).read_text(errors="ignore") for m in _FUNC.finditer(txt): docs = out.setdefault(m.group("name"), {}) diff --git a/parser/outparam.py b/parser/outparam.py index 05544d4..76b1d81 100644 --- a/parser/outparam.py +++ b/parser/outparam.py @@ -20,7 +20,24 @@ import re from pathlib import Path -# Doxygen block immediately followed by a function definition (mirrors nullable.py). + +def doxygen_sources(meos_root: str | Path) -> list[str]: + """The files whose Doxygen documents the MEOS functions: the ``src`` and ``include`` + trees under ``meos_root`` and the sibling ``pgtypes/`` tree, the vendored PostgreSQL + base-type layer (json, date/interval, …) that defines public MEOS functions outside + ``meos/`` and documents them on its ``.c`` definitions (mirrors doxygroup/run.py + pgtypes). Every ``@param`` reader, here and in #extract_nullable, scans this one + list, so a function documented in ``pgtypes/`` states its parameters to all of them + alike.""" + root = Path(meos_root) + files = glob.glob(str(root / "src/**/*.c"), recursive=True) + files += glob.glob(str(root / "include/**/*.h"), recursive=True) + files += glob.glob(str(root.parent / "pgtypes/**/*.c"), recursive=True) + return files + + +# Doxygen block immediately followed by a function definition, the one every @param +# reader pairs a block with its function by (#extract_nullable imports it). # The doxygen block and the function it labels can be separated by preprocessor # guards (`#if MEOS` … `#endif`) and blank lines — the shape the vendored pgtypes # base sources use to guard the MEOS-build twin of a symbol (e.g. @@ -47,7 +64,7 @@ def extract_param_names(meos_root: str | Path) -> dict[str, set]: """Return ``{function: {every @param-documented parameter name}}`` from the MEOS C - Doxygen (scans both ``src`` and ``include``). + Doxygen (#doxygen_sources). Whichever direction a parameter carries, an ``@param`` entry names a parameter the function's documentation OWNS. A wrapper argument bound to such a parameter is a @@ -56,15 +73,8 @@ def extract_param_names(meos_root: str | Path) -> dict[str, set]: — never a hard-coded literal. ``boundargs`` consumes this set to skip those systematically, so a bare-identifier argument only drifts when its parameter is UNDOCUMENTED (the exceptional manual gap worth inspecting).""" - root = Path(meos_root) out: dict[str, set] = {} - files = glob.glob(str(root / "src/**/*.c"), recursive=True) - files += glob.glob(str(root / "include/**/*.h"), recursive=True) - # The vendored PostgreSQL base-type layer (json, date/interval, …) lives in the - # sibling `pgtypes/` tree, outside meos/, and carries its `@param[out]` tags on - # the `.c` definitions there — scan them too (mirrors doxygroup/run.py pgtypes). - files += glob.glob(str(root.parent / "pgtypes/**/*.c"), recursive=True) - for f in files: + for f in doxygen_sources(meos_root): txt = Path(f).read_text(errors="ignore") for m in _FUNC.finditer(txt): name = m.group("name") @@ -76,17 +86,10 @@ def extract_param_names(meos_root: str | Path) -> dict[str, set]: def extract_outparams(meos_root: str | Path) -> dict[str, list[str]]: - """Return ``{function: [params tagged @param[out]]}`` from the MEOS C sources under - ``meos_root`` (scans both ``src`` and ``include``).""" - root = Path(meos_root) + """Return ``{function: [params tagged @param[out]]}`` from the MEOS C sources + (#doxygen_sources).""" out: dict[str, list[str]] = {} - files = glob.glob(str(root / "src/**/*.c"), recursive=True) - files += glob.glob(str(root / "include/**/*.h"), recursive=True) - # The vendored PostgreSQL base-type layer (json, date/interval, …) lives in the - # sibling `pgtypes/` tree, outside meos/, and carries its `@param[out]` tags on - # the `.c` definitions there — scan them too (mirrors doxygroup/run.py pgtypes). - files += glob.glob(str(root.parent / "pgtypes/**/*.c"), recursive=True) - for f in files: + for f in doxygen_sources(meos_root): txt = Path(f).read_text(errors="ignore") for m in _FUNC.finditer(txt): name = m.group("name")