go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
// Copyright 2014 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.
|
|
|
|
|
2016-11-03 16:15:48 -06:00
|
|
|
// +build !go1.8
|
|
|
|
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
// Stringer is a tool to automate the creation of methods that satisfy the fmt.Stringer
|
|
|
|
// interface. Given the name of a (signed or unsigned) integer type T that has constants
|
|
|
|
// defined, stringer will create a new self-contained Go source file implementing
|
|
|
|
// func (t T) String() string
|
|
|
|
// The file is created in the same package and directory as the package that defines T.
|
|
|
|
// It has helpful defaults designed for use with go generate.
|
|
|
|
//
|
|
|
|
// Stringer works best with constants that are consecutive values such as created using iota,
|
|
|
|
// but creates good code regardless. In the future it might also provide custom support for
|
|
|
|
// constant sets that are bit patterns.
|
|
|
|
//
|
|
|
|
// For example, given this snippet,
|
|
|
|
//
|
|
|
|
// package painkiller
|
|
|
|
//
|
|
|
|
// type Pill int
|
|
|
|
//
|
|
|
|
// const (
|
2014-09-04 15:16:59 -06:00
|
|
|
// Placebo Pill = iota
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
// Aspirin
|
|
|
|
// Ibuprofen
|
2014-09-04 15:16:59 -06:00
|
|
|
// Paracetamol
|
|
|
|
// Acetaminophen = Paracetamol
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
// )
|
|
|
|
//
|
|
|
|
// running this command
|
|
|
|
//
|
2014-09-09 14:29:38 -06:00
|
|
|
// stringer -type=Pill
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
//
|
|
|
|
// in the same directory will create the file pill_string.go, in package painkiller,
|
|
|
|
// containing a definition of
|
|
|
|
//
|
|
|
|
// func (Pill) String() string
|
|
|
|
//
|
|
|
|
// That method will translate the value of a Pill constant to the string representation
|
|
|
|
// of the respective constant name, so that the call fmt.Print(painkiller.Aspirin) will
|
|
|
|
// print the string "Aspirin".
|
|
|
|
//
|
|
|
|
// Typically this process would be run using go generate, like this:
|
|
|
|
//
|
2014-09-09 14:29:38 -06:00
|
|
|
// //go:generate stringer -type=Pill
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
//
|
2014-09-04 15:16:59 -06:00
|
|
|
// If multiple constants have the same value, the lexically first matching name will
|
|
|
|
// be used (in the example, Acetaminophen will print as "Paracetamol").
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
//
|
|
|
|
// With no arguments, it processes the package in the current directory.
|
|
|
|
// Otherwise, the arguments must name a single directory holding a Go package
|
|
|
|
// or a set of Go source files that represent a single Go package.
|
|
|
|
//
|
|
|
|
// The -type flag accepts a comma-separated list of types so a single run can
|
|
|
|
// generate methods for multiple types. The default output file is t_string.go,
|
|
|
|
// where t is the lower-cased name of the first type listed. It can be overridden
|
|
|
|
// with the -output flag.
|
|
|
|
//
|
2014-12-08 21:00:58 -07:00
|
|
|
package main // import "golang.org/x/tools/cmd/stringer"
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
|
|
|
"go/ast"
|
|
|
|
"go/build"
|
2015-12-29 11:06:30 -07:00
|
|
|
exact "go/constant"
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
"go/format"
|
2015-12-29 11:06:30 -07:00
|
|
|
"go/importer"
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
"go/parser"
|
|
|
|
"go/token"
|
2015-12-29 11:06:30 -07:00
|
|
|
"go/types"
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
typeNames = flag.String("type", "", "comma-separated list of type names; must be set")
|
|
|
|
output = flag.String("output", "", "output file name; default srcdir/<type>_string.go")
|
|
|
|
)
|
|
|
|
|
|
|
|
// Usage is a replacement usage function for the flags package.
|
|
|
|
func Usage() {
|
|
|
|
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
|
|
|
|
fmt.Fprintf(os.Stderr, "\tstringer [flags] -type T [directory]\n")
|
2016-04-16 11:19:34 -06:00
|
|
|
fmt.Fprintf(os.Stderr, "\tstringer [flags] -type T files... # Must be a single package\n")
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
fmt.Fprintf(os.Stderr, "For more information, see:\n")
|
2014-11-09 14:50:40 -07:00
|
|
|
fmt.Fprintf(os.Stderr, "\thttp://godoc.org/golang.org/x/tools/cmd/stringer\n")
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
fmt.Fprintf(os.Stderr, "Flags:\n")
|
|
|
|
flag.PrintDefaults()
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
log.SetFlags(0)
|
|
|
|
log.SetPrefix("stringer: ")
|
|
|
|
flag.Usage = Usage
|
|
|
|
flag.Parse()
|
2014-09-05 16:42:23 -06:00
|
|
|
if len(*typeNames) == 0 {
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
flag.Usage()
|
|
|
|
os.Exit(2)
|
|
|
|
}
|
2014-09-05 16:42:23 -06:00
|
|
|
types := strings.Split(*typeNames, ",")
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
|
|
|
|
// We accept either one directory or a list of files. Which do we have?
|
|
|
|
args := flag.Args()
|
|
|
|
if len(args) == 0 {
|
|
|
|
// Default: process whole package in current directory.
|
|
|
|
args = []string{"."}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the package once.
|
|
|
|
var (
|
|
|
|
dir string
|
|
|
|
g Generator
|
|
|
|
)
|
|
|
|
if len(args) == 1 && isDirectory(args[0]) {
|
|
|
|
dir = args[0]
|
|
|
|
g.parsePackageDir(args[0])
|
|
|
|
} else {
|
|
|
|
dir = filepath.Dir(args[0])
|
|
|
|
g.parsePackageFiles(args)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Print the header and package clause.
|
2015-09-27 07:47:35 -06:00
|
|
|
g.Printf("// Code generated by \"stringer %s\"; DO NOT EDIT\n", strings.Join(os.Args[1:], " "))
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
g.Printf("\n")
|
|
|
|
g.Printf("package %s", g.pkg.name)
|
|
|
|
g.Printf("\n")
|
|
|
|
g.Printf("import \"fmt\"\n") // Used by all methods.
|
|
|
|
|
|
|
|
// Run generate for each type.
|
|
|
|
for _, typeName := range types {
|
|
|
|
g.generate(typeName)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Format the output.
|
2014-09-04 15:16:59 -06:00
|
|
|
src := g.format()
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
|
|
|
|
// Write to file.
|
|
|
|
outputName := *output
|
|
|
|
if outputName == "" {
|
|
|
|
baseName := fmt.Sprintf("%s_string.go", types[0])
|
|
|
|
outputName = filepath.Join(dir, strings.ToLower(baseName))
|
|
|
|
}
|
2014-09-04 15:16:59 -06:00
|
|
|
err := ioutil.WriteFile(outputName, src, 0644)
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("writing output: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// isDirectory reports whether the named file is a directory.
|
|
|
|
func isDirectory(name string) bool {
|
|
|
|
info, err := os.Stat(name)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
return info.IsDir()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generator holds the state of the analysis. Primarily used to buffer
|
|
|
|
// the output for format.Source.
|
|
|
|
type Generator struct {
|
|
|
|
buf bytes.Buffer // Accumulated output.
|
|
|
|
pkg *Package // Package we are scanning.
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *Generator) Printf(format string, args ...interface{}) {
|
|
|
|
fmt.Fprintf(&g.buf, format, args...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// File holds a single parsed file and associated data.
|
|
|
|
type File struct {
|
|
|
|
pkg *Package // Package to which this file belongs.
|
|
|
|
file *ast.File // Parsed AST.
|
|
|
|
// These fields are reset for each type being generated.
|
|
|
|
typeName string // Name of the constant type.
|
|
|
|
values []Value // Accumulator for constant values of that type.
|
|
|
|
}
|
|
|
|
|
|
|
|
type Package struct {
|
|
|
|
dir string
|
|
|
|
name string
|
|
|
|
defs map[*ast.Ident]types.Object
|
|
|
|
files []*File
|
|
|
|
typesPkg *types.Package
|
|
|
|
}
|
|
|
|
|
|
|
|
// parsePackageDir parses the package residing in the directory.
|
|
|
|
func (g *Generator) parsePackageDir(directory string) {
|
|
|
|
pkg, err := build.Default.ImportDir(directory, 0)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("cannot process directory %s: %s", directory, err)
|
|
|
|
}
|
|
|
|
var names []string
|
|
|
|
names = append(names, pkg.GoFiles...)
|
|
|
|
names = append(names, pkg.CgoFiles...)
|
|
|
|
// TODO: Need to think about constants in test files. Maybe write type_string_test.go
|
|
|
|
// in a separate pass? For later.
|
|
|
|
// names = append(names, pkg.TestGoFiles...) // These are also in the "foo" package.
|
|
|
|
names = append(names, pkg.SFiles...)
|
|
|
|
names = prefixDirectory(directory, names)
|
2014-09-04 17:06:51 -06:00
|
|
|
g.parsePackage(directory, names, nil)
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// parsePackageFiles parses the package occupying the named files.
|
|
|
|
func (g *Generator) parsePackageFiles(names []string) {
|
2014-09-04 17:06:51 -06:00
|
|
|
g.parsePackage(".", names, nil)
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// prefixDirectory places the directory name on the beginning of each name in the list.
|
|
|
|
func prefixDirectory(directory string, names []string) []string {
|
|
|
|
if directory == "." {
|
|
|
|
return names
|
|
|
|
}
|
|
|
|
ret := make([]string, len(names))
|
|
|
|
for i, name := range names {
|
|
|
|
ret[i] = filepath.Join(directory, name)
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
2014-09-04 17:06:51 -06:00
|
|
|
// parsePackage analyzes the single package constructed from the named files.
|
2014-09-04 15:16:59 -06:00
|
|
|
// If text is non-nil, it is a string to be used instead of the content of the file,
|
2014-09-04 17:06:51 -06:00
|
|
|
// to be used for testing. parsePackage exits if there is an error.
|
2014-09-04 15:16:59 -06:00
|
|
|
func (g *Generator) parsePackage(directory string, names []string, text interface{}) {
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
var files []*File
|
|
|
|
var astFiles []*ast.File
|
|
|
|
g.pkg = new(Package)
|
|
|
|
fs := token.NewFileSet()
|
|
|
|
for _, name := range names {
|
|
|
|
if !strings.HasSuffix(name, ".go") {
|
|
|
|
continue
|
|
|
|
}
|
2014-09-04 15:16:59 -06:00
|
|
|
parsedFile, err := parser.ParseFile(fs, name, text, 0)
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("parsing package: %s: %s", name, err)
|
|
|
|
}
|
|
|
|
astFiles = append(astFiles, parsedFile)
|
|
|
|
files = append(files, &File{
|
|
|
|
file: parsedFile,
|
|
|
|
pkg: g.pkg,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
if len(astFiles) == 0 {
|
|
|
|
log.Fatalf("%s: no buildable Go files", directory)
|
|
|
|
}
|
|
|
|
g.pkg.name = astFiles[0].Name.Name
|
|
|
|
g.pkg.files = files
|
|
|
|
g.pkg.dir = directory
|
|
|
|
// Type check the package.
|
|
|
|
g.pkg.check(fs, astFiles)
|
|
|
|
}
|
|
|
|
|
|
|
|
// check type-checks the package. The package must be OK to proceed.
|
|
|
|
func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) {
|
|
|
|
pkg.defs = make(map[*ast.Ident]types.Object)
|
2015-12-29 11:06:30 -07:00
|
|
|
config := types.Config{Importer: importer.Default(), FakeImportC: true}
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
info := &types.Info{
|
|
|
|
Defs: pkg.defs,
|
|
|
|
}
|
|
|
|
typesPkg, err := config.Check(pkg.dir, fs, astFiles, info)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("checking package: %s", err)
|
|
|
|
}
|
|
|
|
pkg.typesPkg = typesPkg
|
|
|
|
}
|
|
|
|
|
|
|
|
// generate produces the String method for the named type.
|
|
|
|
func (g *Generator) generate(typeName string) {
|
|
|
|
values := make([]Value, 0, 100)
|
|
|
|
for _, file := range g.pkg.files {
|
|
|
|
// Set the state for this run of the walker.
|
|
|
|
file.typeName = typeName
|
|
|
|
file.values = nil
|
|
|
|
if file.file != nil {
|
|
|
|
ast.Inspect(file.file, file.genDecl)
|
|
|
|
values = append(values, file.values...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(values) == 0 {
|
|
|
|
log.Fatalf("no values defined for type %s", typeName)
|
|
|
|
}
|
|
|
|
runs := splitIntoRuns(values)
|
|
|
|
// The decision of which pattern to use depends on the number of
|
|
|
|
// runs in the numbers. If there's only one, it's easy. For more than
|
|
|
|
// one, there's a tradeoff between complexity and size of the data
|
|
|
|
// and code vs. the simplicity of a map. A map takes more space,
|
|
|
|
// but so does the code. The decision here (crossover at 10) is
|
|
|
|
// arbitrary, but considers that for large numbers of runs the cost
|
|
|
|
// of the linear scan in the switch might become important, and
|
|
|
|
// rather than use yet another algorithm such as binary search,
|
|
|
|
// we punt and use a map. In any case, the likelihood of a map
|
|
|
|
// being necessary for any realistic example other than bitmasks
|
|
|
|
// is very low. And bitmasks probably deserve their own analysis,
|
|
|
|
// to be done some other day.
|
|
|
|
switch {
|
|
|
|
case len(runs) == 1:
|
|
|
|
g.buildOneRun(runs, typeName)
|
|
|
|
case len(runs) <= 10:
|
|
|
|
g.buildMultipleRuns(runs, typeName)
|
|
|
|
default:
|
|
|
|
g.buildMap(runs, typeName)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// splitIntoRuns breaks the values into runs of contiguous sequences.
|
|
|
|
// For example, given 1,2,3,5,6,7 it returns {1,2,3},{5,6,7}.
|
|
|
|
// The input slice is known to be non-empty.
|
|
|
|
func splitIntoRuns(values []Value) [][]Value {
|
|
|
|
// We use stable sort so the lexically first name is chosen for equal elements.
|
|
|
|
sort.Stable(byValue(values))
|
2014-09-04 15:16:59 -06:00
|
|
|
// Remove duplicates. Stable sort has put the one we want to print first,
|
|
|
|
// so use that one. The String method won't care about which named constant
|
|
|
|
// was the argument, so the first name for the given value is the only one to keep.
|
|
|
|
// We need to do this because identical values would cause the switch or map
|
|
|
|
// to fail to compile.
|
|
|
|
j := 1
|
|
|
|
for i := 1; i < len(values); i++ {
|
|
|
|
if values[i].value != values[i-1].value {
|
|
|
|
values[j] = values[i]
|
|
|
|
j++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
values = values[:j]
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
runs := make([][]Value, 0, 10)
|
|
|
|
for len(values) > 0 {
|
|
|
|
// One contiguous sequence per outer loop.
|
|
|
|
i := 1
|
|
|
|
for i < len(values) && values[i].value == values[i-1].value+1 {
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
runs = append(runs, values[:i])
|
|
|
|
values = values[i:]
|
|
|
|
}
|
|
|
|
return runs
|
|
|
|
}
|
|
|
|
|
2014-09-04 15:16:59 -06:00
|
|
|
// format returns the gofmt-ed contents of the Generator's buffer.
|
|
|
|
func (g *Generator) format() []byte {
|
|
|
|
src, err := format.Source(g.buf.Bytes())
|
|
|
|
if err != nil {
|
|
|
|
// Should never happen, but can arise when developing this code.
|
|
|
|
// The user can compile the output to see the error.
|
|
|
|
log.Printf("warning: internal error: invalid Go generated: %s", err)
|
|
|
|
log.Printf("warning: compile the package to analyze the error")
|
|
|
|
return g.buf.Bytes()
|
|
|
|
}
|
|
|
|
return src
|
|
|
|
}
|
|
|
|
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
// Value represents a declared constant.
|
|
|
|
type Value struct {
|
|
|
|
name string // The name of the constant.
|
|
|
|
// The value is stored as a bit pattern alone. The boolean tells us
|
|
|
|
// whether to interpret it as an int64 or a uint64; the only place
|
|
|
|
// this matters is when sorting.
|
|
|
|
// Much of the time the str field is all we need; it is printed
|
|
|
|
// by Value.String.
|
|
|
|
value uint64 // Will be converted to int64 when needed.
|
|
|
|
signed bool // Whether the constant is a signed type.
|
|
|
|
str string // The string representation given by the "go/exact" package.
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *Value) String() string {
|
|
|
|
return v.str
|
|
|
|
}
|
|
|
|
|
|
|
|
// byValue lets us sort the constants into increasing order.
|
|
|
|
// We take care in the Less method to sort in signed or unsigned order,
|
|
|
|
// as appropriate.
|
|
|
|
type byValue []Value
|
|
|
|
|
|
|
|
func (b byValue) Len() int { return len(b) }
|
|
|
|
func (b byValue) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
|
|
|
|
func (b byValue) Less(i, j int) bool {
|
|
|
|
if b[i].signed {
|
|
|
|
return int64(b[i].value) < int64(b[j].value)
|
|
|
|
}
|
|
|
|
return b[i].value < b[j].value
|
|
|
|
}
|
|
|
|
|
|
|
|
// genDecl processes one declaration clause.
|
|
|
|
func (f *File) genDecl(node ast.Node) bool {
|
|
|
|
decl, ok := node.(*ast.GenDecl)
|
|
|
|
if !ok || decl.Tok != token.CONST {
|
|
|
|
// We only care about const declarations.
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
// The name of the type of the constants we are declaring.
|
|
|
|
// Can change if this is a multi-element declaration.
|
|
|
|
typ := ""
|
|
|
|
// Loop over the elements of the declaration. Each element is a ValueSpec:
|
|
|
|
// a list of names possibly followed by a type, possibly followed by values.
|
|
|
|
// If the type and value are both missing, we carry down the type (and value,
|
|
|
|
// but the "go/types" package takes care of that).
|
|
|
|
for _, spec := range decl.Specs {
|
2016-11-03 16:15:48 -06:00
|
|
|
vspec := spec.(*ast.ValueSpec) // Guaranteed to succeed as this is CONST.
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
if vspec.Type == nil && len(vspec.Values) > 0 {
|
|
|
|
// "X = 1". With no type but a value, the constant is untyped.
|
|
|
|
// Skip this vspec and reset the remembered type.
|
|
|
|
typ = ""
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if vspec.Type != nil {
|
|
|
|
// "X T". We have a type. Remember it.
|
|
|
|
ident, ok := vspec.Type.(*ast.Ident)
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
typ = ident.Name
|
|
|
|
}
|
|
|
|
if typ != f.typeName {
|
|
|
|
// This is not the type we're looking for.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
// We now have a list of names (from one line of source code) all being
|
|
|
|
// declared with the desired type.
|
|
|
|
// Grab their names and actual values and store them in f.values.
|
|
|
|
for _, name := range vspec.Names {
|
|
|
|
if name.Name == "_" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
// This dance lets the type checker find the values for us. It's a
|
|
|
|
// bit tricky: look up the object declared by the name, find its
|
|
|
|
// types.Const, and extract its value.
|
|
|
|
obj, ok := f.pkg.defs[name]
|
|
|
|
if !ok {
|
|
|
|
log.Fatalf("no value for constant %s", name)
|
|
|
|
}
|
|
|
|
info := obj.Type().Underlying().(*types.Basic).Info()
|
|
|
|
if info&types.IsInteger == 0 {
|
|
|
|
log.Fatalf("can't handle non-integer constant type %s", typ)
|
|
|
|
}
|
|
|
|
value := obj.(*types.Const).Val() // Guaranteed to succeed as this is CONST.
|
|
|
|
if value.Kind() != exact.Int {
|
|
|
|
log.Fatalf("can't happen: constant is not an integer %s", name)
|
|
|
|
}
|
|
|
|
i64, isInt := exact.Int64Val(value)
|
|
|
|
u64, isUint := exact.Uint64Val(value)
|
|
|
|
if !isInt && !isUint {
|
|
|
|
log.Fatalf("internal error: value of %s is not an integer: %s", name, value.String())
|
|
|
|
}
|
|
|
|
if !isInt {
|
|
|
|
u64 = uint64(i64)
|
|
|
|
}
|
|
|
|
v := Value{
|
|
|
|
name: name.Name,
|
|
|
|
value: u64,
|
|
|
|
signed: info&types.IsUnsigned == 0,
|
|
|
|
str: value.String(),
|
|
|
|
}
|
|
|
|
f.values = append(f.values, v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// Helpers
|
|
|
|
|
|
|
|
// usize returns the number of bits of the smallest unsigned integer
|
|
|
|
// type that will hold n. Used to create the smallest possible slice of
|
|
|
|
// integers to use as indexes into the concatenated strings.
|
|
|
|
func usize(n int) int {
|
|
|
|
switch {
|
|
|
|
case n < 1<<8:
|
|
|
|
return 8
|
|
|
|
case n < 1<<16:
|
|
|
|
return 16
|
|
|
|
default:
|
2014-09-04 11:51:38 -06:00
|
|
|
// 2^32 is enough constants for anyone.
|
|
|
|
return 32
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-04 17:06:51 -06:00
|
|
|
// declareIndexAndNameVars declares the index slices and concatenated names
|
|
|
|
// strings representing the runs of values.
|
|
|
|
func (g *Generator) declareIndexAndNameVars(runs [][]Value, typeName string) {
|
|
|
|
var indexes, names []string
|
|
|
|
for i, run := range runs {
|
|
|
|
index, name := g.createIndexAndNameDecl(run, typeName, fmt.Sprintf("_%d", i))
|
|
|
|
indexes = append(indexes, index)
|
|
|
|
names = append(names, name)
|
|
|
|
}
|
|
|
|
g.Printf("const (\n")
|
|
|
|
for _, name := range names {
|
|
|
|
g.Printf("\t%s\n", name)
|
|
|
|
}
|
|
|
|
g.Printf(")\n\n")
|
|
|
|
g.Printf("var (")
|
|
|
|
for _, index := range indexes {
|
|
|
|
g.Printf("\t%s\n", index)
|
|
|
|
}
|
|
|
|
g.Printf(")\n\n")
|
|
|
|
}
|
|
|
|
|
|
|
|
// declareIndexAndNameVar is the single-run version of declareIndexAndNameVars
|
|
|
|
func (g *Generator) declareIndexAndNameVar(run []Value, typeName string) {
|
|
|
|
index, name := g.createIndexAndNameDecl(run, typeName, "")
|
|
|
|
g.Printf("const %s\n", name)
|
|
|
|
g.Printf("var %s\n", index)
|
|
|
|
}
|
|
|
|
|
|
|
|
// createIndexAndNameDecl returns the pair of declarations for the run. The caller will add "const" and "var".
|
|
|
|
func (g *Generator) createIndexAndNameDecl(run []Value, typeName string, suffix string) (string, string) {
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
b := new(bytes.Buffer)
|
|
|
|
indexes := make([]int, len(run))
|
|
|
|
for i := range run {
|
|
|
|
b.WriteString(run[i].name)
|
|
|
|
indexes[i] = b.Len()
|
|
|
|
}
|
2014-09-04 17:06:51 -06:00
|
|
|
nameConst := fmt.Sprintf("_%s_name%s = %q", typeName, suffix, b.String())
|
|
|
|
nameLen := b.Len()
|
|
|
|
b.Reset()
|
stringer: avoid if's in the generated code
Suggestion by dsymonds: Save code not data.
Add an extra element to the index array and an if can be eliminated.
Old generated code:
const _Day_name = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
var _Day_index = [...]uint8{6, 13, 22, 30, 36, 44, 50}
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_index)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_index[i]
lo := uint8(0)
if i > 0 {
lo = _Day_index[i-1]
}
return _Day_name[lo:hi]
}
New generated code:
const _Day_name = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
var _Day_index = [...]uint8{0, 6, 13, 22, 30, 36, 44, 50}
func (i Day) String() string {
if i < 0 || i+1 >= Day(len(_Day_index)) {
return fmt.Sprintf("Day(%d)", i)
}
return _Day_name[_Day_index[i]:_Day_index[i+1]]
}
Change-Id: I6f46a4892d5813a12ec1ad01738c6a21c7e45172
Reviewed-on: https://go-review.googlesource.com/1990
Reviewed-by: David Symonds <dsymonds@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2014-12-22 13:20:51 -07:00
|
|
|
fmt.Fprintf(b, "_%s_index%s = [...]uint%d{0, ", typeName, suffix, usize(nameLen))
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
for i, v := range indexes {
|
|
|
|
if i > 0 {
|
2014-09-04 17:06:51 -06:00
|
|
|
fmt.Fprintf(b, ", ")
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
}
|
2014-09-04 17:06:51 -06:00
|
|
|
fmt.Fprintf(b, "%d", v)
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
}
|
2014-09-04 17:06:51 -06:00
|
|
|
fmt.Fprintf(b, "}")
|
|
|
|
return b.String(), nameConst
|
|
|
|
}
|
|
|
|
|
|
|
|
// declareNameVars declares the concatenated names string representing all the values in the runs.
|
|
|
|
func (g *Generator) declareNameVars(runs [][]Value, typeName string, suffix string) {
|
|
|
|
g.Printf("const _%s_name%s = \"", typeName, suffix)
|
|
|
|
for _, run := range runs {
|
|
|
|
for i := range run {
|
|
|
|
g.Printf("%s", run[i].name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g.Printf("\"\n")
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// buildOneRun generates the variables and String method for a single run of contiguous values.
|
|
|
|
func (g *Generator) buildOneRun(runs [][]Value, typeName string) {
|
|
|
|
values := runs[0]
|
2014-09-04 17:06:51 -06:00
|
|
|
g.Printf("\n")
|
|
|
|
g.declareIndexAndNameVar(values, typeName)
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
// The generated code is simple enough to write as a Printf format.
|
|
|
|
lessThanZero := ""
|
|
|
|
if values[0].signed {
|
|
|
|
lessThanZero = "i < 0 || "
|
|
|
|
}
|
|
|
|
if values[0].value == 0 { // Signed or unsigned, 0 is still 0.
|
|
|
|
g.Printf(stringOneRun, typeName, usize(len(values)), lessThanZero)
|
|
|
|
} else {
|
|
|
|
g.Printf(stringOneRunWithOffset, typeName, values[0].String(), usize(len(values)), lessThanZero)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Arguments to format are:
|
|
|
|
// [1]: type name
|
|
|
|
// [2]: size of index element (8 for uint8 etc.)
|
|
|
|
// [3]: less than zero check (for signed types)
|
|
|
|
const stringOneRun = `func (i %[1]s) String() string {
|
2015-04-23 15:54:52 -06:00
|
|
|
if %[3]si >= %[1]s(len(_%[1]s_index)-1) {
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
return fmt.Sprintf("%[1]s(%%d)", i)
|
|
|
|
}
|
stringer: avoid if's in the generated code
Suggestion by dsymonds: Save code not data.
Add an extra element to the index array and an if can be eliminated.
Old generated code:
const _Day_name = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
var _Day_index = [...]uint8{6, 13, 22, 30, 36, 44, 50}
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_index)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_index[i]
lo := uint8(0)
if i > 0 {
lo = _Day_index[i-1]
}
return _Day_name[lo:hi]
}
New generated code:
const _Day_name = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
var _Day_index = [...]uint8{0, 6, 13, 22, 30, 36, 44, 50}
func (i Day) String() string {
if i < 0 || i+1 >= Day(len(_Day_index)) {
return fmt.Sprintf("Day(%d)", i)
}
return _Day_name[_Day_index[i]:_Day_index[i+1]]
}
Change-Id: I6f46a4892d5813a12ec1ad01738c6a21c7e45172
Reviewed-on: https://go-review.googlesource.com/1990
Reviewed-by: David Symonds <dsymonds@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2014-12-22 13:20:51 -07:00
|
|
|
return _%[1]s_name[_%[1]s_index[i]:_%[1]s_index[i+1]]
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
}
|
|
|
|
`
|
|
|
|
|
|
|
|
// Arguments to format are:
|
|
|
|
// [1]: type name
|
|
|
|
// [2]: lowest defined value for type, as a string
|
|
|
|
// [3]: size of index element (8 for uint8 etc.)
|
|
|
|
// [4]: less than zero check (for signed types)
|
|
|
|
/*
|
|
|
|
*/
|
|
|
|
const stringOneRunWithOffset = `func (i %[1]s) String() string {
|
|
|
|
i -= %[2]s
|
2015-04-23 15:54:52 -06:00
|
|
|
if %[4]si >= %[1]s(len(_%[1]s_index)-1) {
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
return fmt.Sprintf("%[1]s(%%d)", i + %[2]s)
|
|
|
|
}
|
stringer: avoid if's in the generated code
Suggestion by dsymonds: Save code not data.
Add an extra element to the index array and an if can be eliminated.
Old generated code:
const _Day_name = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
var _Day_index = [...]uint8{6, 13, 22, 30, 36, 44, 50}
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_index)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_index[i]
lo := uint8(0)
if i > 0 {
lo = _Day_index[i-1]
}
return _Day_name[lo:hi]
}
New generated code:
const _Day_name = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
var _Day_index = [...]uint8{0, 6, 13, 22, 30, 36, 44, 50}
func (i Day) String() string {
if i < 0 || i+1 >= Day(len(_Day_index)) {
return fmt.Sprintf("Day(%d)", i)
}
return _Day_name[_Day_index[i]:_Day_index[i+1]]
}
Change-Id: I6f46a4892d5813a12ec1ad01738c6a21c7e45172
Reviewed-on: https://go-review.googlesource.com/1990
Reviewed-by: David Symonds <dsymonds@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2014-12-22 13:20:51 -07:00
|
|
|
return _%[1]s_name[_%[1]s_index[i] : _%[1]s_index[i+1]]
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
}
|
|
|
|
`
|
|
|
|
|
|
|
|
// buildMultipleRuns generates the variables and String method for multiple runs of contiguous values.
|
|
|
|
// For this pattern, a single Printf format won't do.
|
|
|
|
func (g *Generator) buildMultipleRuns(runs [][]Value, typeName string) {
|
2014-09-04 17:06:51 -06:00
|
|
|
g.Printf("\n")
|
|
|
|
g.declareIndexAndNameVars(runs, typeName)
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
g.Printf("func (i %s) String() string {\n", typeName)
|
|
|
|
g.Printf("\tswitch {\n")
|
|
|
|
for i, values := range runs {
|
|
|
|
if len(values) == 1 {
|
|
|
|
g.Printf("\tcase i == %s:\n", &values[0])
|
2014-09-04 17:06:51 -06:00
|
|
|
g.Printf("\t\treturn _%s_name_%d\n", typeName, i)
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
continue
|
|
|
|
}
|
2014-09-05 16:42:23 -06:00
|
|
|
g.Printf("\tcase %s <= i && i <= %s:\n", &values[0], &values[len(values)-1])
|
2014-09-05 18:05:28 -06:00
|
|
|
if values[0].value != 0 {
|
|
|
|
g.Printf("\t\ti -= %s\n", &values[0])
|
|
|
|
}
|
stringer: avoid if's in the generated code
Suggestion by dsymonds: Save code not data.
Add an extra element to the index array and an if can be eliminated.
Old generated code:
const _Day_name = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
var _Day_index = [...]uint8{6, 13, 22, 30, 36, 44, 50}
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_index)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_index[i]
lo := uint8(0)
if i > 0 {
lo = _Day_index[i-1]
}
return _Day_name[lo:hi]
}
New generated code:
const _Day_name = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
var _Day_index = [...]uint8{0, 6, 13, 22, 30, 36, 44, 50}
func (i Day) String() string {
if i < 0 || i+1 >= Day(len(_Day_index)) {
return fmt.Sprintf("Day(%d)", i)
}
return _Day_name[_Day_index[i]:_Day_index[i+1]]
}
Change-Id: I6f46a4892d5813a12ec1ad01738c6a21c7e45172
Reviewed-on: https://go-review.googlesource.com/1990
Reviewed-by: David Symonds <dsymonds@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2014-12-22 13:20:51 -07:00
|
|
|
g.Printf("\t\treturn _%s_name_%d[_%s_index_%d[i]:_%s_index_%d[i+1]]\n",
|
|
|
|
typeName, i, typeName, i, typeName, i)
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
}
|
|
|
|
g.Printf("\tdefault:\n")
|
|
|
|
g.Printf("\t\treturn fmt.Sprintf(\"%s(%%d)\", i)\n", typeName)
|
|
|
|
g.Printf("\t}\n")
|
|
|
|
g.Printf("}\n")
|
|
|
|
}
|
|
|
|
|
|
|
|
// buildMap handles the case where the space is so sparse a map is a reasonable fallback.
|
|
|
|
// It's a rare situation but has simple code.
|
|
|
|
func (g *Generator) buildMap(runs [][]Value, typeName string) {
|
2014-09-04 17:06:51 -06:00
|
|
|
g.Printf("\n")
|
|
|
|
g.declareNameVars(runs, typeName, "")
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
g.Printf("\nvar _%s_map = map[%s]string{\n", typeName, typeName)
|
2014-09-04 17:06:51 -06:00
|
|
|
n := 0
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
for _, values := range runs {
|
|
|
|
for _, value := range values {
|
2014-09-04 17:18:38 -06:00
|
|
|
g.Printf("\t%s: _%s_name[%d:%d],\n", &value, typeName, n, n+len(value.name))
|
2014-09-04 17:06:51 -06:00
|
|
|
n += len(value.name)
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
g.Printf("}\n\n")
|
|
|
|
g.Printf(stringMap, typeName)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Argument to format is the type name.
|
|
|
|
const stringMap = `func (i %[1]s) String() string {
|
2014-09-04 15:16:59 -06:00
|
|
|
if str, ok := _%[1]s_map[i]; ok {
|
|
|
|
return str
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
}
|
2014-09-04 15:16:59 -06:00
|
|
|
return fmt.Sprintf("%[1]s(%%d)", i)
|
go.tools/cmd/stringer: new tool
This tool creates String methods from constant definitions.
It's a time-saver designed to be used from go generate.
The methods generated are efficient, more so than one
is likely to create by hand.
Given
package date
type Day int
const (
Monday Day = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
the command
stringer -type Day
will create the file day_string.go containing
package date
import "fmt"
var (
_Day_indexes = []uint8{6, 13, 22, 30, 36, 44, 50}
_Day_names = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
)
func (i Day) String() string {
if i < 0 || i >= Day(len(_Day_indexes)) {
return fmt.Sprintf("Day(%d)", i)
}
hi := _Day_indexes[i]
lo := uint8(0)
if i > 0 {
lo = _Day_indexes[i-1]
}
return _Day_names[lo:hi]
}
There are several strategies for the created method chosen according to
the structure of the sequence of constants.
Handles integer types only, both signed and unsigned. That's probably
all that is needed.
Tests to follow, but the test structure will be large so sending this out
separately. The code has been heavily hand-tested but there are
some bugs. Don't depend on this until the tests are installed.
LGTM=gri
R=gri, josharian
CC=golang-codereviews
https://golang.org/cl/136180043
2014-09-03 18:27:48 -06:00
|
|
|
}
|
|
|
|
`
|