Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 9 additions & 18 deletions parser/nullable.py
Original file line number Diff line number Diff line change
Expand Up @@ -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<doc>.*?)\*/\s*\n'
r'(?:[A-Za-z_][\w\s\*]*?\n)?' # optional return-type line
r'(?P<name>[a-z][a-z0-9_]*)\s*\('
r'(?P<params>[^;{]*?)\)\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<names>\w+(?:\s*,\s*\w+)*)\s+(?P<desc>.*?)'
Expand All @@ -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")
Expand All @@ -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"), {})
Expand Down
43 changes: 23 additions & 20 deletions parser/outparam.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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")
Expand All @@ -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")
Expand Down
Loading