[PATCH 20/38] docs: kdoc_re: add support on NestedMatch for argument replacement

Mauro Carvalho Chehab
2026-02-18T10:13:25Z

Currently, NestedMatch has very limited support for aguments
replacement: it is all or nothing.

Add support to allow replacing individual arguments as well.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
tools/lib/python/kdoc/kdoc_re.py | 84 ++++++++++++++++++++++----------
1 file changed, 59 insertions(+), 25 deletions(-)

diff --git a/tools/lib/python/kdoc/kdoc_re.py b/tools/lib/python/kdoc/kdoc_re.py
index fed9894a5c71..05f36d665b70 100644
--- a/tools/lib/python/kdoc/kdoc_re.py
+++ b/tools/lib/python/kdoc/kdoc_re.py
@@ -177,29 +177,6 @@ class NestedMatch:
will ignore the search string.
"""

- # TODO: make NestedMatch handle multiple match groups
- #
- # Right now, regular expressions to match it are defined only up to
- # the start delimiter, e.g.:
- #
- # \bSTRUCT_GROUP\(
- #
- # is similar to: STRUCT_GROUP\((.*)\)
- # except that the content inside the match group is delimiter-aligned.
- #
- # The content inside parentheses is converted into a single replace
- # group (e.g. r`\1').
- #
- # It would be nice to change such definition to support multiple
- # match groups, allowing a regex equivalent to:
- #
- # FOO\((.*), (.*), (.*)\)
- #
- # it is probably easier to define it not as a regular expression, but
- # with some lexical definition like:
- #
- # FOO(arg1, arg2, arg3)
-
def __init__(self, regex):
self.regex = KernRe(regex)

@@ -285,6 +262,59 @@ class NestedMatch:

yield line[t[0]:t[2]]

+ @staticmethod
+ def _split_args(all_args, delim=","):
+ """
+ Helper method to split comma-separated function arguments
+ or struct elements, if delim is set to ";".
+
+ It returns a list of arguments that can be used later on by
+ the sub() method.
+ """
+ args = [all_args]
+ stack = []
+ arg_start = 0
+ string_char = None
+ escape = False
+
+ for idx, d in enumerate(all_args):
+ if escape:
+ escape = False
+ continue
+
+ if string_char:
+ if d == '\\':
+ escape = True
+ elif d == string_char:
+ string_char = None
+
+ continue
+
+ if d in ('"', "'"):
+ string_char = d
+ continue
+
+ if d in DELIMITER_PAIRS:
+ end = DELIMITER_PAIRS[d]
+
+ stack.append(end)
+ continue
+
+ if stack and d == stack[-1]:
+ stack.pop()
+ continue
+
+ if d == delim and not stack:
+ args.append(all_args[arg_start:idx].strip())
+ arg_start = idx + 1
+
+ # Add the last argument (if any)
+ last = all_args[arg_start:].strip()
+ if last:
+ args.append(last)
+
+ return args
+
def sub(self, sub, line, count=0):
"""
This is similar to re.sub:
@@ -313,9 +343,13 @@ class NestedMatch:
# Value, ignoring start/end delimiters
value = line[end:pos - 1]

- # replaces \0 at the sub string, if \0 is used there
+ # replace arguments
new_sub = sub
- new_sub = new_sub.replace(r'\0', value)
+ if "\\" in sub:
+ args = self._split_args(value)
+
+ new_sub = re.sub(r'\\(\d+)',
+ lambda m: args[int(m.group(1))], new_sub)

out += new_sub

--
2.52.0