From: Carlos Amedee Date: Wed, 17 May 2023 21:45:37 +0000 (-0400) Subject: internal/types/errors: generate Markdown files for compiler errors X-Git-Tag: go1.21rc1~302 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=626d478d828ea4c41e09830215fd6f21df9b1ccc;p=gostls13.git internal/types/errors: generate Markdown files for compiler errors 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 Auto-Submit: Carlos Amedee Run-TryBot: Carlos Amedee Reviewed-by: Carlos Amedee TryBot-Result: Gopher Robot --- diff --git a/src/internal/types/errors/generrordocs.go b/src/internal/types/errors/generrordocs.go new file mode 100644 index 0000000000..46343be3ef --- /dev/null +++ b/src/internal/types/errors/generrordocs.go @@ -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 + +//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 ") + } + 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 &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 +--- + + + + +{{.Description}} +`