github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/cmd/stringer/stringer.go (about)

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Stringer is a tool to automate the creation of methods that satisfy the fmt.Stringer
     6  // interface. Given the name of a (signed or unsigned) integer type T that has constants
     7  // defined, stringer will create a new self-contained Go source file implementing
     8  //	func (t T) String() string
     9  // The file is created in the same package and directory as the package that defines T.
    10  // It has helpful defaults designed for use with go generate.
    11  //
    12  // Stringer works best with constants that are consecutive values such as created using iota,
    13  // but creates good code regardless. In the future it might also provide custom support for
    14  // constant sets that are bit patterns.
    15  //
    16  // For example, given this snippet,
    17  //
    18  //	package painkiller
    19  //
    20  //	type Pill int
    21  //
    22  //	const (
    23  //		Placebo Pill = iota
    24  //		Aspirin
    25  //		Ibuprofen
    26  //		Paracetamol
    27  //		Acetaminophen = Paracetamol
    28  //	)
    29  //
    30  // running this command
    31  //
    32  //	stringer -type=Pill
    33  //
    34  // in the same directory will create the file pill_string.go, in package painkiller,
    35  // containing a definition of
    36  //
    37  //	func (Pill) String() string
    38  //
    39  // That method will translate the value of a Pill constant to the string representation
    40  // of the respective constant name, so that the call fmt.Print(painkiller.Aspirin) will
    41  // print the string "Aspirin".
    42  //
    43  // Typically this process would be run using go generate, like this:
    44  //
    45  //	//go:generate stringer -type=Pill
    46  //
    47  // If multiple constants have the same value, the lexically first matching name will
    48  // be used (in the example, Acetaminophen will print as "Paracetamol").
    49  //
    50  // With no arguments, it processes the package in the current directory.
    51  // Otherwise, the arguments must name a single directory holding a Go package
    52  // or a set of Go source files that represent a single Go package.
    53  //
    54  // The -type flag accepts a comma-separated list of types so a single run can
    55  // generate methods for multiple types. The default output file is t_string.go,
    56  // where t is the lower-cased name of the first type listed. It can be overridden
    57  // with the -output flag.
    58  //
    59  package main // import "golang.org/x/tools/cmd/stringer"
    60  
    61  import (
    62  	"bytes"
    63  	"flag"
    64  	"fmt"
    65  	"go/ast"
    66  	"go/build"
    67  	exact "go/constant"
    68  	"go/format"
    69  	"go/importer"
    70  	"go/parser"
    71  	"go/token"
    72  	"go/types"
    73  	"io/ioutil"
    74  	"log"
    75  	"os"
    76  	"path/filepath"
    77  	"sort"
    78  	"strings"
    79  )
    80  
    81  var (
    82  	typeNames = flag.String("type", "", "comma-separated list of type names; must be set")
    83  	output    = flag.String("output", "", "output file name; default srcdir/<type>_string.go")
    84  )
    85  
    86  // Usage is a replacement usage function for the flags package.
    87  func Usage() {
    88  	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
    89  	fmt.Fprintf(os.Stderr, "\tstringer [flags] -type T [directory]\n")
    90  	fmt.Fprintf(os.Stderr, "\tstringer [flags[ -type T files... # Must be a single package\n")
    91  	fmt.Fprintf(os.Stderr, "For more information, see:\n")
    92  	fmt.Fprintf(os.Stderr, "\thttp://godoc.org/golang.org/x/tools/cmd/stringer\n")
    93  	fmt.Fprintf(os.Stderr, "Flags:\n")
    94  	flag.PrintDefaults()
    95  }
    96  
    97  func main() {
    98  	log.SetFlags(0)
    99  	log.SetPrefix("stringer: ")
   100  	flag.Usage = Usage
   101  	flag.Parse()
   102  	if len(*typeNames) == 0 {
   103  		flag.Usage()
   104  		os.Exit(2)
   105  	}
   106  	types := strings.Split(*typeNames, ",")
   107  
   108  	// We accept either one directory or a list of files. Which do we have?
   109  	args := flag.Args()
   110  	if len(args) == 0 {
   111  		// Default: process whole package in current directory.
   112  		args = []string{"."}
   113  	}
   114  
   115  	// Parse the package once.
   116  	var (
   117  		dir string
   118  		g   Generator
   119  	)
   120  	if len(args) == 1 && isDirectory(args[0]) {
   121  		dir = args[0]
   122  		g.parsePackageDir(args[0])
   123  	} else {
   124  		dir = filepath.Dir(args[0])
   125  		g.parsePackageFiles(args)
   126  	}
   127  
   128  	// Print the header and package clause.
   129  	g.Printf("// Code generated by \"stringer %s\"; DO NOT EDIT\n", strings.Join(os.Args[1:], " "))
   130  	g.Printf("\n")
   131  	g.Printf("package %s", g.pkg.name)
   132  	g.Printf("\n")
   133  	g.Printf("import \"fmt\"\n") // Used by all methods.
   134  
   135  	// Run generate for each type.
   136  	for _, typeName := range types {
   137  		g.generate(typeName)
   138  	}
   139  
   140  	// Format the output.
   141  	src := g.format()
   142  
   143  	// Write to file.
   144  	outputName := *output
   145  	if outputName == "" {
   146  		baseName := fmt.Sprintf("%s_string.go", types[0])
   147  		outputName = filepath.Join(dir, strings.ToLower(baseName))
   148  	}
   149  	err := ioutil.WriteFile(outputName, src, 0644)
   150  	if err != nil {
   151  		log.Fatalf("writing output: %s", err)
   152  	}
   153  }
   154  
   155  // isDirectory reports whether the named file is a directory.
   156  func isDirectory(name string) bool {
   157  	info, err := os.Stat(name)
   158  	if err != nil {
   159  		log.Fatal(err)
   160  	}
   161  	return info.IsDir()
   162  }
   163  
   164  // Generator holds the state of the analysis. Primarily used to buffer
   165  // the output for format.Source.
   166  type Generator struct {
   167  	buf bytes.Buffer // Accumulated output.
   168  	pkg *Package     // Package we are scanning.
   169  }
   170  
   171  func (g *Generator) Printf(format string, args ...interface{}) {
   172  	fmt.Fprintf(&g.buf, format, args...)
   173  }
   174  
   175  // File holds a single parsed file and associated data.
   176  type File struct {
   177  	pkg  *Package  // Package to which this file belongs.
   178  	file *ast.File // Parsed AST.
   179  	// These fields are reset for each type being generated.
   180  	typeName string  // Name of the constant type.
   181  	values   []Value // Accumulator for constant values of that type.
   182  }
   183  
   184  type Package struct {
   185  	dir      string
   186  	name     string
   187  	defs     map[*ast.Ident]types.Object
   188  	files    []*File
   189  	typesPkg *types.Package
   190  }
   191  
   192  // parsePackageDir parses the package residing in the directory.
   193  func (g *Generator) parsePackageDir(directory string) {
   194  	pkg, err := build.Default.ImportDir(directory, 0)
   195  	if err != nil {
   196  		log.Fatalf("cannot process directory %s: %s", directory, err)
   197  	}
   198  	var names []string
   199  	names = append(names, pkg.GoFiles...)
   200  	names = append(names, pkg.CgoFiles...)
   201  	// TODO: Need to think about constants in test files. Maybe write type_string_test.go
   202  	// in a separate pass? For later.
   203  	// names = append(names, pkg.TestGoFiles...) // These are also in the "foo" package.
   204  	names = append(names, pkg.SFiles...)
   205  	names = prefixDirectory(directory, names)
   206  	g.parsePackage(directory, names, nil)
   207  }
   208  
   209  // parsePackageFiles parses the package occupying the named files.
   210  func (g *Generator) parsePackageFiles(names []string) {
   211  	g.parsePackage(".", names, nil)
   212  }
   213  
   214  // prefixDirectory places the directory name on the beginning of each name in the list.
   215  func prefixDirectory(directory string, names []string) []string {
   216  	if directory == "." {
   217  		return names
   218  	}
   219  	ret := make([]string, len(names))
   220  	for i, name := range names {
   221  		ret[i] = filepath.Join(directory, name)
   222  	}
   223  	return ret
   224  }
   225  
   226  // parsePackage analyzes the single package constructed from the named files.
   227  // If text is non-nil, it is a string to be used instead of the content of the file,
   228  // to be used for testing. parsePackage exits if there is an error.
   229  func (g *Generator) parsePackage(directory string, names []string, text interface{}) {
   230  	var files []*File
   231  	var astFiles []*ast.File
   232  	g.pkg = new(Package)
   233  	fs := token.NewFileSet()
   234  	for _, name := range names {
   235  		if !strings.HasSuffix(name, ".go") {
   236  			continue
   237  		}
   238  		parsedFile, err := parser.ParseFile(fs, name, text, 0)
   239  		if err != nil {
   240  			log.Fatalf("parsing package: %s: %s", name, err)
   241  		}
   242  		astFiles = append(astFiles, parsedFile)
   243  		files = append(files, &File{
   244  			file: parsedFile,
   245  			pkg:  g.pkg,
   246  		})
   247  	}
   248  	if len(astFiles) == 0 {
   249  		log.Fatalf("%s: no buildable Go files", directory)
   250  	}
   251  	g.pkg.name = astFiles[0].Name.Name
   252  	g.pkg.files = files
   253  	g.pkg.dir = directory
   254  	// Type check the package.
   255  	g.pkg.check(fs, astFiles)
   256  }
   257  
   258  // check type-checks the package. The package must be OK to proceed.
   259  func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) {
   260  	pkg.defs = make(map[*ast.Ident]types.Object)
   261  	config := types.Config{Importer: importer.Default(), FakeImportC: true}
   262  	info := &types.Info{
   263  		Defs: pkg.defs,
   264  	}
   265  	typesPkg, err := config.Check(pkg.dir, fs, astFiles, info)
   266  	if err != nil {
   267  		log.Fatalf("checking package: %s", err)
   268  	}
   269  	pkg.typesPkg = typesPkg
   270  }
   271  
   272  // generate produces the String method for the named type.
   273  func (g *Generator) generate(typeName string) {
   274  	values := make([]Value, 0, 100)
   275  	for _, file := range g.pkg.files {
   276  		// Set the state for this run of the walker.
   277  		file.typeName = typeName
   278  		file.values = nil
   279  		if file.file != nil {
   280  			ast.Inspect(file.file, file.genDecl)
   281  			values = append(values, file.values...)
   282  		}
   283  	}
   284  
   285  	if len(values) == 0 {
   286  		log.Fatalf("no values defined for type %s", typeName)
   287  	}
   288  	runs := splitIntoRuns(values)
   289  	// The decision of which pattern to use depends on the number of
   290  	// runs in the numbers. If there's only one, it's easy. For more than
   291  	// one, there's a tradeoff between complexity and size of the data
   292  	// and code vs. the simplicity of a map. A map takes more space,
   293  	// but so does the code. The decision here (crossover at 10) is
   294  	// arbitrary, but considers that for large numbers of runs the cost
   295  	// of the linear scan in the switch might become important, and
   296  	// rather than use yet another algorithm such as binary search,
   297  	// we punt and use a map. In any case, the likelihood of a map
   298  	// being necessary for any realistic example other than bitmasks
   299  	// is very low. And bitmasks probably deserve their own analysis,
   300  	// to be done some other day.
   301  	switch {
   302  	case len(runs) == 1:
   303  		g.buildOneRun(runs, typeName)
   304  	case len(runs) <= 10:
   305  		g.buildMultipleRuns(runs, typeName)
   306  	default:
   307  		g.buildMap(runs, typeName)
   308  	}
   309  }
   310  
   311  // splitIntoRuns breaks the values into runs of contiguous sequences.
   312  // For example, given 1,2,3,5,6,7 it returns {1,2,3},{5,6,7}.
   313  // The input slice is known to be non-empty.
   314  func splitIntoRuns(values []Value) [][]Value {
   315  	// We use stable sort so the lexically first name is chosen for equal elements.
   316  	sort.Stable(byValue(values))
   317  	// Remove duplicates. Stable sort has put the one we want to print first,
   318  	// so use that one. The String method won't care about which named constant
   319  	// was the argument, so the first name for the given value is the only one to keep.
   320  	// We need to do this because identical values would cause the switch or map
   321  	// to fail to compile.
   322  	j := 1
   323  	for i := 1; i < len(values); i++ {
   324  		if values[i].value != values[i-1].value {
   325  			values[j] = values[i]
   326  			j++
   327  		}
   328  	}
   329  	values = values[:j]
   330  	runs := make([][]Value, 0, 10)
   331  	for len(values) > 0 {
   332  		// One contiguous sequence per outer loop.
   333  		i := 1
   334  		for i < len(values) && values[i].value == values[i-1].value+1 {
   335  			i++
   336  		}
   337  		runs = append(runs, values[:i])
   338  		values = values[i:]
   339  	}
   340  	return runs
   341  }
   342  
   343  // format returns the gofmt-ed contents of the Generator's buffer.
   344  func (g *Generator) format() []byte {
   345  	src, err := format.Source(g.buf.Bytes())
   346  	if err != nil {
   347  		// Should never happen, but can arise when developing this code.
   348  		// The user can compile the output to see the error.
   349  		log.Printf("warning: internal error: invalid Go generated: %s", err)
   350  		log.Printf("warning: compile the package to analyze the error")
   351  		return g.buf.Bytes()
   352  	}
   353  	return src
   354  }
   355  
   356  // Value represents a declared constant.
   357  type Value struct {
   358  	name string // The name of the constant.
   359  	// The value is stored as a bit pattern alone. The boolean tells us
   360  	// whether to interpret it as an int64 or a uint64; the only place
   361  	// this matters is when sorting.
   362  	// Much of the time the str field is all we need; it is printed
   363  	// by Value.String.
   364  	value  uint64 // Will be converted to int64 when needed.
   365  	signed bool   // Whether the constant is a signed type.
   366  	str    string // The string representation given by the "go/exact" package.
   367  }
   368  
   369  func (v *Value) String() string {
   370  	return v.str
   371  }
   372  
   373  // byValue lets us sort the constants into increasing order.
   374  // We take care in the Less method to sort in signed or unsigned order,
   375  // as appropriate.
   376  type byValue []Value
   377  
   378  func (b byValue) Len() int      { return len(b) }
   379  func (b byValue) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
   380  func (b byValue) Less(i, j int) bool {
   381  	if b[i].signed {
   382  		return int64(b[i].value) < int64(b[j].value)
   383  	}
   384  	return b[i].value < b[j].value
   385  }
   386  
   387  // genDecl processes one declaration clause.
   388  func (f *File) genDecl(node ast.Node) bool {
   389  	decl, ok := node.(*ast.GenDecl)
   390  	if !ok || decl.Tok != token.CONST {
   391  		// We only care about const declarations.
   392  		return true
   393  	}
   394  	// The name of the type of the constants we are declaring.
   395  	// Can change if this is a multi-element declaration.
   396  	typ := ""
   397  	// Loop over the elements of the declaration. Each element is a ValueSpec:
   398  	// a list of names possibly followed by a type, possibly followed by values.
   399  	// If the type and value are both missing, we carry down the type (and value,
   400  	// but the "go/types" package takes care of that).
   401  	for _, spec := range decl.Specs {
   402  		vspec := spec.(*ast.ValueSpec) // Guaranteed to succeed as this is CONST.
   403  		if vspec.Type == nil && len(vspec.Values) > 0 {
   404  			// "X = 1". With no type but a value, the constant is untyped.
   405  			// Skip this vspec and reset the remembered type.
   406  			typ = ""
   407  			continue
   408  		}
   409  		if vspec.Type != nil {
   410  			// "X T". We have a type. Remember it.
   411  			ident, ok := vspec.Type.(*ast.Ident)
   412  			if !ok {
   413  				continue
   414  			}
   415  			typ = ident.Name
   416  		}
   417  		if typ != f.typeName {
   418  			// This is not the type we're looking for.
   419  			continue
   420  		}
   421  		// We now have a list of names (from one line of source code) all being
   422  		// declared with the desired type.
   423  		// Grab their names and actual values and store them in f.values.
   424  		for _, name := range vspec.Names {
   425  			if name.Name == "_" {
   426  				continue
   427  			}
   428  			// This dance lets the type checker find the values for us. It's a
   429  			// bit tricky: look up the object declared by the name, find its
   430  			// types.Const, and extract its value.
   431  			obj, ok := f.pkg.defs[name]
   432  			if !ok {
   433  				log.Fatalf("no value for constant %s", name)
   434  			}
   435  			info := obj.Type().Underlying().(*types.Basic).Info()
   436  			if info&types.IsInteger == 0 {
   437  				log.Fatalf("can't handle non-integer constant type %s", typ)
   438  			}
   439  			value := obj.(*types.Const).Val() // Guaranteed to succeed as this is CONST.
   440  			if value.Kind() != exact.Int {
   441  				log.Fatalf("can't happen: constant is not an integer %s", name)
   442  			}
   443  			i64, isInt := exact.Int64Val(value)
   444  			u64, isUint := exact.Uint64Val(value)
   445  			if !isInt && !isUint {
   446  				log.Fatalf("internal error: value of %s is not an integer: %s", name, value.String())
   447  			}
   448  			if !isInt {
   449  				u64 = uint64(i64)
   450  			}
   451  			v := Value{
   452  				name:   name.Name,
   453  				value:  u64,
   454  				signed: info&types.IsUnsigned == 0,
   455  				str:    value.String(),
   456  			}
   457  			f.values = append(f.values, v)
   458  		}
   459  	}
   460  	return false
   461  }
   462  
   463  // Helpers
   464  
   465  // usize returns the number of bits of the smallest unsigned integer
   466  // type that will hold n. Used to create the smallest possible slice of
   467  // integers to use as indexes into the concatenated strings.
   468  func usize(n int) int {
   469  	switch {
   470  	case n < 1<<8:
   471  		return 8
   472  	case n < 1<<16:
   473  		return 16
   474  	default:
   475  		// 2^32 is enough constants for anyone.
   476  		return 32
   477  	}
   478  }
   479  
   480  // declareIndexAndNameVars declares the index slices and concatenated names
   481  // strings representing the runs of values.
   482  func (g *Generator) declareIndexAndNameVars(runs [][]Value, typeName string) {
   483  	var indexes, names []string
   484  	for i, run := range runs {
   485  		index, name := g.createIndexAndNameDecl(run, typeName, fmt.Sprintf("_%d", i))
   486  		indexes = append(indexes, index)
   487  		names = append(names, name)
   488  	}
   489  	g.Printf("const (\n")
   490  	for _, name := range names {
   491  		g.Printf("\t%s\n", name)
   492  	}
   493  	g.Printf(")\n\n")
   494  	g.Printf("var (")
   495  	for _, index := range indexes {
   496  		g.Printf("\t%s\n", index)
   497  	}
   498  	g.Printf(")\n\n")
   499  }
   500  
   501  // declareIndexAndNameVar is the single-run version of declareIndexAndNameVars
   502  func (g *Generator) declareIndexAndNameVar(run []Value, typeName string) {
   503  	index, name := g.createIndexAndNameDecl(run, typeName, "")
   504  	g.Printf("const %s\n", name)
   505  	g.Printf("var %s\n", index)
   506  }
   507  
   508  // createIndexAndNameDecl returns the pair of declarations for the run. The caller will add "const" and "var".
   509  func (g *Generator) createIndexAndNameDecl(run []Value, typeName string, suffix string) (string, string) {
   510  	b := new(bytes.Buffer)
   511  	indexes := make([]int, len(run))
   512  	for i := range run {
   513  		b.WriteString(run[i].name)
   514  		indexes[i] = b.Len()
   515  	}
   516  	nameConst := fmt.Sprintf("_%s_name%s = %q", typeName, suffix, b.String())
   517  	nameLen := b.Len()
   518  	b.Reset()
   519  	fmt.Fprintf(b, "_%s_index%s = [...]uint%d{0, ", typeName, suffix, usize(nameLen))
   520  	for i, v := range indexes {
   521  		if i > 0 {
   522  			fmt.Fprintf(b, ", ")
   523  		}
   524  		fmt.Fprintf(b, "%d", v)
   525  	}
   526  	fmt.Fprintf(b, "}")
   527  	return b.String(), nameConst
   528  }
   529  
   530  // declareNameVars declares the concatenated names string representing all the values in the runs.
   531  func (g *Generator) declareNameVars(runs [][]Value, typeName string, suffix string) {
   532  	g.Printf("const _%s_name%s = \"", typeName, suffix)
   533  	for _, run := range runs {
   534  		for i := range run {
   535  			g.Printf("%s", run[i].name)
   536  		}
   537  	}
   538  	g.Printf("\"\n")
   539  }
   540  
   541  // buildOneRun generates the variables and String method for a single run of contiguous values.
   542  func (g *Generator) buildOneRun(runs [][]Value, typeName string) {
   543  	values := runs[0]
   544  	g.Printf("\n")
   545  	g.declareIndexAndNameVar(values, typeName)
   546  	// The generated code is simple enough to write as a Printf format.
   547  	lessThanZero := ""
   548  	if values[0].signed {
   549  		lessThanZero = "i < 0 || "
   550  	}
   551  	if values[0].value == 0 { // Signed or unsigned, 0 is still 0.
   552  		g.Printf(stringOneRun, typeName, usize(len(values)), lessThanZero)
   553  	} else {
   554  		g.Printf(stringOneRunWithOffset, typeName, values[0].String(), usize(len(values)), lessThanZero)
   555  	}
   556  }
   557  
   558  // Arguments to format are:
   559  //	[1]: type name
   560  //	[2]: size of index element (8 for uint8 etc.)
   561  //	[3]: less than zero check (for signed types)
   562  const stringOneRun = `func (i %[1]s) String() string {
   563  	if %[3]si >= %[1]s(len(_%[1]s_index)-1) {
   564  		return fmt.Sprintf("%[1]s(%%d)", i)
   565  	}
   566  	return _%[1]s_name[_%[1]s_index[i]:_%[1]s_index[i+1]]
   567  }
   568  `
   569  
   570  // Arguments to format are:
   571  //	[1]: type name
   572  //	[2]: lowest defined value for type, as a string
   573  //	[3]: size of index element (8 for uint8 etc.)
   574  //	[4]: less than zero check (for signed types)
   575  /*
   576   */
   577  const stringOneRunWithOffset = `func (i %[1]s) String() string {
   578  	i -= %[2]s
   579  	if %[4]si >= %[1]s(len(_%[1]s_index)-1) {
   580  		return fmt.Sprintf("%[1]s(%%d)", i + %[2]s)
   581  	}
   582  	return _%[1]s_name[_%[1]s_index[i] : _%[1]s_index[i+1]]
   583  }
   584  `
   585  
   586  // buildMultipleRuns generates the variables and String method for multiple runs of contiguous values.
   587  // For this pattern, a single Printf format won't do.
   588  func (g *Generator) buildMultipleRuns(runs [][]Value, typeName string) {
   589  	g.Printf("\n")
   590  	g.declareIndexAndNameVars(runs, typeName)
   591  	g.Printf("func (i %s) String() string {\n", typeName)
   592  	g.Printf("\tswitch {\n")
   593  	for i, values := range runs {
   594  		if len(values) == 1 {
   595  			g.Printf("\tcase i == %s:\n", &values[0])
   596  			g.Printf("\t\treturn _%s_name_%d\n", typeName, i)
   597  			continue
   598  		}
   599  		g.Printf("\tcase %s <= i && i <= %s:\n", &values[0], &values[len(values)-1])
   600  		if values[0].value != 0 {
   601  			g.Printf("\t\ti -= %s\n", &values[0])
   602  		}
   603  		g.Printf("\t\treturn _%s_name_%d[_%s_index_%d[i]:_%s_index_%d[i+1]]\n",
   604  			typeName, i, typeName, i, typeName, i)
   605  	}
   606  	g.Printf("\tdefault:\n")
   607  	g.Printf("\t\treturn fmt.Sprintf(\"%s(%%d)\", i)\n", typeName)
   608  	g.Printf("\t}\n")
   609  	g.Printf("}\n")
   610  }
   611  
   612  // buildMap handles the case where the space is so sparse a map is a reasonable fallback.
   613  // It's a rare situation but has simple code.
   614  func (g *Generator) buildMap(runs [][]Value, typeName string) {
   615  	g.Printf("\n")
   616  	g.declareNameVars(runs, typeName, "")
   617  	g.Printf("\nvar _%s_map = map[%s]string{\n", typeName, typeName)
   618  	n := 0
   619  	for _, values := range runs {
   620  		for _, value := range values {
   621  			g.Printf("\t%s: _%s_name[%d:%d],\n", &value, typeName, n, n+len(value.name))
   622  			n += len(value.name)
   623  		}
   624  	}
   625  	g.Printf("}\n\n")
   626  	g.Printf(stringMap, typeName)
   627  }
   628  
   629  // Argument to format is the type name.
   630  const stringMap = `func (i %[1]s) String() string {
   631  	if str, ok := _%[1]s_map[i]; ok {
   632  		return str
   633  	}
   634  	return fmt.Sprintf("%[1]s(%%d)", i)
   635  }
   636  `