On Thu, May 16, 2024, 5:34 AM Markus Armbruster <arm...@redhat.com> wrote:
> John Snow <js...@redhat.com> writes: > > > Add a semantic tag to paragraphs that appear *before* tagged > > sections/members/features and those that appear after. This will control > > how they are inlined when doc sections are merged and flattened. > > This future use is not obvious to me now. I guess the effective way to > help me see it is actual patches, which will come in due time. > Head recursion and tail recursion, respectively :) * intro * inherited intro * members [ancestor-descendent] * features [ancestor-descendent] * inherited outro * outro Child gets the first and final words. Inherited stuff goes in the sandwich fillings. It feels like a simple rule that's easy to internalize. As a bonus, you can explain it by analogy to Americans as a burger, which is the only metaphor we understand. > > Signed-off-by: John Snow <js...@redhat.com> > > --- > > scripts/qapi/parser.py | 22 +++++++++++++++++----- > > 1 file changed, 17 insertions(+), 5 deletions(-) > > > > diff --git a/scripts/qapi/parser.py b/scripts/qapi/parser.py > > index cf4cbca1c1f..b1794f71e12 100644 > > --- a/scripts/qapi/parser.py > > +++ b/scripts/qapi/parser.py > > @@ -503,6 +503,10 @@ def get_doc(self) -> 'QAPIDoc': > > self.accept(False) > > line = self.get_doc_line() > > no_more_args = False > > + # Paragraphs before members/features/tagged are "intro" > paragraphs. > > + # Any appearing subsequently are "outro" paragraphs. > > + # This is only semantic metadata for the doc generator. > > Not sure about the last sentence. Isn't it true for almost everything > around here? > I guess I was trying to say "There's no real difference between the two mechanically, it's purely based on where it appears in the doc block, which offers only a heuristic for its semantic value- introductory statements or additional detail." In my mind: the other "kind" values have some more mechanical difference to them, but intro/outro don't. > Also, long line. > > > + intro = True > > > > while line is not None: > > # Blank lines > > @@ -532,6 +536,7 @@ def get_doc(self) -> 'QAPIDoc': > > raise QAPIParseError( > > self, 'feature descriptions expected') > > no_more_args = True > > + intro = False > > After feature descriptions. > > > elif match := self._match_at_name_colon(line): > > # description > > if no_more_args: > > @@ -547,6 +552,7 @@ def get_doc(self) -> 'QAPIDoc': > > doc.append_line(text) > > line = self.get_doc_indented(doc) > > no_more_args = True > > + intro = False > > Or after member descriptions. > > > elif match := re.match( > > r'(Returns|Errors|Since|Notes?|Examples?|TODO): > *', > > line): > > @@ -557,13 +563,14 @@ def get_doc(self) -> 'QAPIDoc': > > doc.append_line(text) > > line = self.get_doc_indented(doc) > > no_more_args = True > > + intro = False > > Or after the first tagged section. > > Okay, it does what it says on the tin. > > > elif line.startswith('='): > > raise QAPIParseError( > > self, > > "unexpected '=' markup in definition > documentation") > > else: > > # tag-less paragraph > > - doc.ensure_untagged_section(self.info) > > + doc.ensure_untagged_section(self.info, intro) > > doc.append_line(line) > > line = self.get_doc_paragraph(doc) > > else: > > @@ -617,7 +624,7 @@ def __init__( > > self, > > info: QAPISourceInfo, > > tag: Optional[str] = None, > > - kind: str = 'paragraph', > > + kind: str = 'intro-paragraph', > > The question "why is this optional?" crossed my mind when reviewing the > previous patch. I left it unasked, because I felt challenging the > overlap between @kind and @tag was more useful. However, the new > default value 'intro-paragraph' feels more arbitrary to me than the old > one 'paragraph', and that makes the question pop right back into my > mind. > Just "don't break API" habit, nothing more. I can make it mandatory. > Unless I'm mistaken, all calls but one @tag and @kind. Making that one > pass it too feels simpler to me. > > Moot if we fuse @tag and @kind, of course. > > ): > > # section source info, i.e. where it begins > > self.info = info > > @@ -625,7 +632,7 @@ def __init__( > > self.tag = tag > > # section text without tag > > self.text = '' > > - # section type - {paragraph, feature, member, tagged} > > + # section type - {<intro|outro>-paragraph, feature, member, > tagged} > > Long line. Oops, default for black is longer. Forgot to enable the "I still use email patches as part of my penance" setting > > self.kind = kind > > > > def append_line(self, line: str) -> None: > > @@ -666,7 +673,11 @@ def end(self) -> None: > > raise QAPISemError( > > section.info, "text required after '%s:'" % > section.tag) > > > > - def ensure_untagged_section(self, info: QAPISourceInfo) -> None: > > + def ensure_untagged_section( > > + self, > > + info: QAPISourceInfo, > > + intro: bool = True, > > Two callers, one passes @info, one doesn't. Passing it always might be > simpler. > Okeydokey. > > + ) -> None: > > if self.all_sections and not self.all_sections[-1].tag: > > section = self.all_sections[-1] > > # Section is empty so far; update info to start *here*. > > @@ -677,7 +688,8 @@ def ensure_untagged_section(self, info: > QAPISourceInfo) -> None: > > self.all_sections[-1].text += '\n' > > return > > # start new section > > - section = self.Section(info) > > + kind = ("intro" if intro else "outro") + "-paragraph" > > + section = self.Section(info, kind=kind) > > self.sections.append(section) > > self.all_sections.append(section) > >