]> Cypherpunks repositories - gostls13.git/commitdiff
internal/types/errors: generate Markdown files for compiler errors
authorCarlos Amedee <carlos@golang.org>
Wed, 17 May 2023 21:45:37 +0000 (17:45 -0400)
committerGopher Robot <gobot@golang.org>
Wed, 24 May 2023 03:14:42 +0000 (03:14 +0000)
This change adds a generator which creates a Markdown file for each
compiler error code which includes its associated documentation. The
Markdown files will be added to the x/website repository and used
to generate short error links on the Go website.

Change-Id: Ibabc3388d6ecc7f19151f3931554f72561e30b22
Reviewed-on: https://go-review.googlesource.com/c/go/+/495858
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Carlos Amedee <carlos@golang.org>
Run-TryBot: Carlos Amedee <carlos@golang.org>
Reviewed-by: Carlos Amedee <carlos@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/internal/types/errors/generrordocs.go [new file with mode: 0644]

diff --git a/src/internal/types/errors/generrordocs.go b/src/internal/types/errors/generrordocs.go
new file mode 100644 (file)
index 0000000..46343be
--- /dev/null
@@ -0,0 +1,117 @@
+//go:build ignore
+
+// Copyright 2023 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.
+
+// generrordocs creates a Markdown file for each (compiler) error code
+// and its associated documentation.
+// Note: this program must be run in this directory.
+//   go run generrordocs.go <dir>
+
+//go:generate go run generrordocs.go errors_markdown
+
+package main
+
+import (
+       "bytes"
+       "fmt"
+       "go/ast"
+       "go/importer"
+       "go/parser"
+       "go/token"
+       "log"
+       "os"
+       "path"
+       "strings"
+       "text/template"
+
+       . "go/types"
+)
+
+func main() {
+       if len(os.Args) != 2 {
+               log.Fatal("missing argument: generrordocs <dir>")
+       }
+       outDir := os.Args[1]
+       if err := os.MkdirAll(outDir, 0755); err != nil {
+               log.Fatal("unable to create output directory: %s", err)
+       }
+       walkCodes(func(name string, vs *ast.ValueSpec) {
+               // ignore unused errors
+               if name == "_" {
+                       return
+               }
+               // Ensure that < are represented correctly when its included in code
+               // blocks. The goldmark Markdown parser converts them to &amp;lt;
+               // when not escaped. It is the only known string with this issue.
+               desc := strings.ReplaceAll(vs.Doc.Text(), "<", `{{raw "<"}}`)
+               e := struct {
+                       Name        string
+                       Description string
+               }{
+                       Name:        name,
+                       Description: fmt.Sprintf("```\n%s```\n", desyc),
+               }
+               var buf bytes.Buffer
+               err := template.Must(template.New("eachError").Parse(markdownTemplate)).Execute(&buf, e)
+               if err != nil {
+                       log.Fatalf("template.Must: %s", err)
+               }
+               if err := os.WriteFile(path.Join(outDir, name+".md"), buf.Bytes(), 0660); err != nil {
+                       log.Fatalf("os.WriteFile: %s\n", err)
+               }
+       })
+       log.Printf("output directory: %s\n", outDir)
+}
+
+func walkCodes(f func(string, *ast.ValueSpec)) {
+       fset := token.NewFileSet()
+       file, err := parser.ParseFile(fset, "codes.go", nil, parser.ParseComments)
+       if err != nil {
+               log.Fatalf("ParseFile failed: %s", err)
+       }
+       conf := Config{Importer: importer.Default()}
+       info := &Info{
+               Types: make(map[ast.Expr]TypeAndValue),
+               Defs:  make(map[*ast.Ident]Object),
+               Uses:  make(map[*ast.Ident]Object),
+       }
+       _, err = conf.Check("types", fset, []*ast.File{file}, info)
+       if err != nil {
+               log.Fatalf("Check failed: %s", err)
+       }
+       for _, decl := range file.Decls {
+               decl, ok := decl.(*ast.GenDecl)
+               if !ok || decl.Tok != token.CONST {
+                       continue
+               }
+               for _, spec := range decl.Specs {
+                       spec, ok := spec.(*ast.ValueSpec)
+                       if !ok || len(spec.Names) == 0 {
+                               continue
+                       }
+                       obj := info.ObjectOf(spec.Names[0])
+                       if named, ok := obj.Type().(*Named); ok && named.Obj().Name() == "Code" {
+                               if len(spec.Names) != 1 {
+                                       log.Fatalf("bad Code declaration for %q: got %d names, want exactly 1", spec.Names[0].Name, len(spec.Names))
+                               }
+                               codename := spec.Names[0].Name
+                               f(codename, spec)
+                       }
+               }
+       }
+}
+
+const markdownTemplate = `---
+title: {{.Name}}
+layout: article
+---
+<!-- Copyright 2023 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. -->
+
+<!-- Code generated by generrordocs.go; DO NOT EDIT. -->
+
+{{.Description}}
+`