From 494b79f39ab8e7b6f096b6c6088bd84bb8592dc4 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 3 Apr 2022 07:55:25 -0400 Subject: [PATCH] go/doc/comment: add data structures [This CL is part of a sequence implementing the proposal #51082. The design doc is at https://go.dev/s/godocfmt-design.] Implement just the data structures of the new API for parsing and printing doc comments, as well as a syntax tree form for inspecting and manipulating them. The API itself was discussed and accepted as part of the proposal process in #51082. For #51082. Change-Id: Iae7fbc85705964585273b970c5c62e394feb1288 Reviewed-on: https://go-review.googlesource.com/c/go/+/397276 Run-TryBot: Russ Cox Reviewed-by: Jonathan Amsterdam Reviewed-by: Ian Lance Taylor TryBot-Result: Gopher Robot --- api/next/51082.txt | 35 ++++++++ src/go/build/deps_test.go | 4 +- src/go/doc/comment/parse.go | 169 ++++++++++++++++++++++++++++++++++++ 3 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 api/next/51082.txt create mode 100644 src/go/doc/comment/parse.go diff --git a/api/next/51082.txt b/api/next/51082.txt new file mode 100644 index 0000000000..2127d2ee24 --- /dev/null +++ b/api/next/51082.txt @@ -0,0 +1,35 @@ +pkg go/doc/comment, method (*List) BlankBefore() bool #51082 +pkg go/doc/comment, method (*List) BlankBetween() bool #51082 +pkg go/doc/comment, type Block interface, unexported methods #51082 +pkg go/doc/comment, type Code struct #51082 +pkg go/doc/comment, type Code struct, Text string #51082 +pkg go/doc/comment, type Doc struct #51082 +pkg go/doc/comment, type Doc struct, Content []Block #51082 +pkg go/doc/comment, type Doc struct, Links []*LinkDef #51082 +pkg go/doc/comment, type DocLink struct #51082 +pkg go/doc/comment, type DocLink struct, ImportPath string #51082 +pkg go/doc/comment, type DocLink struct, Name string #51082 +pkg go/doc/comment, type DocLink struct, Recv string #51082 +pkg go/doc/comment, type DocLink struct, Text []Text #51082 +pkg go/doc/comment, type Heading struct #51082 +pkg go/doc/comment, type Heading struct, Text []Text #51082 +pkg go/doc/comment, type Italic string #51082 +pkg go/doc/comment, type Link struct #51082 +pkg go/doc/comment, type Link struct, Auto bool #51082 +pkg go/doc/comment, type Link struct, Text []Text #51082 +pkg go/doc/comment, type Link struct, URL string #51082 +pkg go/doc/comment, type LinkDef struct #51082 +pkg go/doc/comment, type LinkDef struct, Text string #51082 +pkg go/doc/comment, type LinkDef struct, URL string #51082 +pkg go/doc/comment, type LinkDef struct, Used bool #51082 +pkg go/doc/comment, type List struct #51082 +pkg go/doc/comment, type List struct, ForceBlankBefore bool #51082 +pkg go/doc/comment, type List struct, ForceBlankBetween bool #51082 +pkg go/doc/comment, type List struct, Items []*ListItem #51082 +pkg go/doc/comment, type ListItem struct #51082 +pkg go/doc/comment, type ListItem struct, Content []Block #51082 +pkg go/doc/comment, type ListItem struct, Number string #51082 +pkg go/doc/comment, type Paragraph struct #51082 +pkg go/doc/comment, type Paragraph struct, Text []Text #51082 +pkg go/doc/comment, type Plain string #51082 +pkg go/doc/comment, type Text interface, unexported methods #51082 diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 052e7ad9c0..7117e08c3b 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -288,9 +288,9 @@ var depsRules = ` < go/parser; FMT - < go/build/constraint; + < go/build/constraint, go/doc/comment; - go/build/constraint, go/parser, text/tabwriter + go/build/constraint, go/doc/comment, go/parser, text/tabwriter < go/printer < go/format; diff --git a/src/go/doc/comment/parse.go b/src/go/doc/comment/parse.go new file mode 100644 index 0000000000..672b115bf8 --- /dev/null +++ b/src/go/doc/comment/parse.go @@ -0,0 +1,169 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package comment + +// A Doc is a parsed Go doc comment. +type Doc struct { + // Content is the sequence of content blocks in the comment. + Content []Block + + // Links is the link definitions in the comment. + Links []*LinkDef +} + +// A LinkDef is a single link definition. +type LinkDef struct { + Text string // the link text + URL string // the link URL + Used bool // whether the comment uses the definition +} + +// A Block is block-level content in a doc comment, +// one of *[Code], *[Heading], *[List], or *[Paragraph]. +type Block interface { + block() +} + +// A Heading is a doc comment heading. +type Heading struct { + Text []Text // the heading text +} + +func (*Heading) block() {} + +// A List is a numbered or bullet list. +// Lists are always non-empty: len(Items) > 0. +// In a numbered list, every Items[i].Number is a non-empty string. +// In a bullet list, every Items[i].Number is an empty string. +type List struct { + // Items is the list items. + Items []*ListItem + + // ForceBlankBefore indicates that the list must be + // preceded by a blank line when reformatting the comment, + // overriding the usual conditions. See the BlankBefore method. + // + // The comment parser sets ForceBlankBefore for any list + // that is preceded by a blank line, to make sure + // the blank line is preserved when printing. + ForceBlankBefore bool + + // ForceBlankBetween indicates that list items must be + // separated by blank lines when reformatting the comment, + // overriding the usual conditions. See the BlankBetween method. + // + // The comment parser sets ForceBlankBetween for any list + // that has a blank line between any two of its items, to make sure + // the blank lines are preserved when printing. + ForceBlankBetween bool +} + +func (*List) block() {} + +// BlankBefore reports whether a reformatting of the comment +// should include a blank line before the list. +// The default rule is the same as for [BlankBetween]: +// if the list item content contains any blank lines +// (meaning at least one item has multiple paragraphs) +// then the list itself must be preceded by a blank line. +// A preceding blank line can be forced by setting [List].ForceBlankBefore. +func (l *List) BlankBefore() bool { + return l.ForceBlankBefore || l.BlankBetween() +} + +// BlankBetween reports whether a reformatting of the comment +// should include a blank line between each pair of list items. +// The default rule is that if the list item content contains any blank lines +// (meaning at least one item has multiple paragraphs) +// then list items must themselves be separated by blank lines. +// Blank line separators can be forced by setting [List].ForceBlankBetween. +func (l *List) BlankBetween() bool { + if l.ForceBlankBetween { + return true + } + for _, item := range l.Items { + if len(item.Content) != 1 { + // Unreachable for parsed comments today, + // since the only way to get multiple item.Content + // is multiple paragraphs, which must have been + // separated by a blank line. + return true + } + } + return false +} + +// A ListItem is a single item in a numbered or bullet list. +type ListItem struct { + // Number is a decimal string in a numbered list + // or an empty string in a bullet list. + Number string // "1", "2", ...; "" for bullet list + + // Content is the list content. + // Currently, restrictions in the parser and printer + // require every element of Content to be a *Paragraph. + Content []Block // Content of this item. +} + +// A Paragraph is a paragraph of text. +type Paragraph struct { + Text []Text +} + +func (*Paragraph) block() {} + +// A Code is a preformatted code block. +type Code struct { + // Text is the preformatted text, ending with a newline character. + // It may be multiple lines, each of which ends with a newline character. + // It is never empty, nor does it start or end with a blank line. + Text string +} + +func (*Code) block() {} + +// A Text is text-level content in a doc comment, +// one of [Plain], [Italic], *[Link], or *[DocLink]. +type Text interface { + text() +} + +// A Plain is a string rendered as plain text (not italicized). +type Plain string + +func (Plain) text() {} + +// An Italic is a string rendered as italicized text. +type Italic string + +func (Italic) text() {} + +// A Link is a link to a specific URL. +type Link struct { + Auto bool // is this an automatic (implicit) link of a literal URL? + Text []Text // text of link + URL string // target URL of link +} + +func (*Link) text() {} + +// A DocLink is a link to documentation for a Go package or symbol. +type DocLink struct { + Text []Text // text of link + + // ImportPath, Recv, and Name identify the Go package or symbol + // that is the link target. The potential combinations of + // non-empty fields are: + // - ImportPath: a link to another package + // - ImportPath, Name: a link to a const, func, type, or var in another package + // - ImportPath, Recv, Name: a link to a method in another package + // - Name: a link to a const, func, type, or var in this package + // - Recv, Name: a link to a method in this package + ImportPath string // import path + Recv string // receiver type, without any pointer star, for methods + Name string // const, func, type, var, or method name +} + +func (*DocLink) text() {} -- 2.50.0