go-json/cmd/generator/main.go

401 lines
12 KiB
Go

package main
import (
"bytes"
"fmt"
"go/format"
"io/ioutil"
"path/filepath"
"runtime"
"strings"
"text/template"
)
type opType struct {
Op string
IndentOp string
Code string
}
type headType struct {
Head string
PtrHead string
AnonymousHead string
AnonymousPtrHead string
OmitEmptyHead string
OmitEmptyPtrHead string
AnonymousOmitEmptyHead string
AnonymousOmitEmptyPtrHead string
StringTagHead string
StringTagPtrHead string
AnonymousStringTagHead string
AnonymousStringTagPtrHead string
}
type fieldType struct {
Field string
OmitEmptyField string
StringTagField string
}
func _main() error {
tmpl, err := template.New("").Parse(`// Code generated by cmd/generator. DO NOT EDIT!
package json
type codeType int
const (
{{- range $index, $type := .CodeTypes }}
code{{ $type }} codeType = {{ $index }}
{{- end }}
)
type opType int
const (
{{- range $index, $type := .OpTypes }}
op{{ $type.Op }} opType = {{ $index }}
{{- end }}
)
func (t opType) String() string {
switch t {
{{- range $type := .OpTypes }}
case op{{ $type.Op }}:
return "{{ $type.Op }}"
{{- end }}
}
return ""
}
func (t opType) codeType() codeType {
switch t {
{{- range $type := .OpTypes }}
case op{{ $type.Op }}:
return code{{ $type.Code }}
{{- end }}
}
return codeOp
}
func (t opType) toIndent() opType {
switch t {
{{- range $type := .OpTypes }}
case op{{ $type.Op }}:
return op{{ $type.IndentOp }}
{{- end }}
}
return t
}
func (t opType) headToPtrHead() opType {
switch t {
{{- range $type := .HeadTypes }}
case op{{ $type.Head }}:
return op{{ $type.PtrHead }}
case op{{ $type.AnonymousHead }}:
return op{{ $type.AnonymousPtrHead }}
case op{{ $type.OmitEmptyHead }}:
return op{{ $type.OmitEmptyPtrHead }}
case op{{ $type.AnonymousOmitEmptyHead }}:
return op{{ $type.AnonymousOmitEmptyPtrHead }}
case op{{ $type.StringTagHead }}:
return op{{ $type.StringTagPtrHead }}
case op{{ $type.AnonymousStringTagHead }}:
return op{{ $type.AnonymousStringTagPtrHead }}
{{- end }}
}
return t
}
func (t opType) headToAnonymousHead() opType {
switch t {
{{- range $type := .HeadTypes }}
case op{{ $type.Head }}:
return op{{ $type.AnonymousHead }}
case op{{ $type.PtrHead }}:
return op{{ $type.AnonymousPtrHead }}
case op{{ $type.OmitEmptyHead }}:
return op{{ $type.AnonymousOmitEmptyHead }}
case op{{ $type.OmitEmptyPtrHead }}:
return op{{ $type.AnonymousOmitEmptyPtrHead }}
case op{{ $type.StringTagHead }}:
return op{{ $type.AnonymousStringTagHead }}
case op{{ $type.StringTagPtrHead }}:
return op{{ $type.AnonymousStringTagPtrHead }}
{{- end }}
}
return t
}
func (t opType) headToOmitEmptyHead() opType {
switch t {
{{- range $type := .HeadTypes }}
case op{{ $type.Head }}:
return op{{ $type.OmitEmptyHead }}
case op{{ $type.PtrHead }}:
return op{{ $type.OmitEmptyPtrHead }}
{{- end }}
}
return t
}
func (t opType) headToStringTagHead() opType {
switch t {
{{- range $type := .HeadTypes }}
case op{{ $type.Head }}:
return op{{ $type.StringTagHead }}
case op{{ $type.PtrHead }}:
return op{{ $type.StringTagPtrHead }}
{{- end }}
}
return t
}
func (t opType) ptrHeadToHead() opType {
switch t {
{{- range $type := .HeadTypes }}
case op{{ $type.PtrHead }}:
return op{{ $type.Head }}
case op{{ $type.AnonymousPtrHead }}:
return op{{ $type.AnonymousHead }}
case op{{ $type.OmitEmptyPtrHead }}:
return op{{ $type.OmitEmptyHead }}
case op{{ $type.AnonymousOmitEmptyPtrHead }}:
return op{{ $type.AnonymousOmitEmptyHead }}
case op{{ $type.StringTagPtrHead }}:
return op{{ $type.StringTagHead }}
case op{{ $type.AnonymousStringTagPtrHead }}:
return op{{ $type.AnonymousStringTagHead }}
{{- end }}
}
return t
}
func (t opType) fieldToOmitEmptyField() opType {
switch t {
{{- range $type := .FieldTypes }}
case op{{ $type.Field }}:
return op{{ $type.OmitEmptyField }}
{{- end }}
}
return t
}
func (t opType) fieldToStringTagField() opType {
switch t {
{{- range $type := .FieldTypes }}
case op{{ $type.Field }}:
return op{{ $type.StringTagField }}
{{- end }}
}
return t
}
`)
if err != nil {
return err
}
codeTypes := []string{
"Op",
"ArrayHead",
"ArrayElem",
"SliceHead",
"SliceElem",
"MapHead",
"MapKey",
"MapValue",
"MapEnd",
"StructFieldRecursive",
"StructField",
}
primitiveTypes := []string{
"int", "int8", "int16", "int32", "int64",
"uint", "uint8", "uint16", "uint32", "uint64",
"float32", "float64", "bool", "string", "bytes",
"array", "map", "mapLoad", "slice", "struct", "MarshalJSON", "MarshalText", "recursive",
}
primitiveTypesUpper := []string{}
for _, typ := range primitiveTypes {
primitiveTypesUpper = append(primitiveTypesUpper, strings.ToUpper(string(typ[0]))+typ[1:])
}
opTypes := []opType{
{"End", "EndIndent", "Op"},
{"Interface", "InterfaceIndent", "Op"},
{"InterfaceEnd", "InterfaceEndIndent", "Op"},
{"Ptr", "PtrIndent", "Op"},
{"SliceHead", "SliceHeadIndent", "SliceHead"},
{"RootSliceHead", "RootSliceHeadIndent", "SliceHead"},
{"SliceElem", "SliceElemIndent", "SliceElem"},
{"RootSliceElem", "RootSliceElemIndent", "SliceElem"},
{"SliceEnd", "SliceEndIndent", "Op"},
{"ArrayHead", "ArrayHeadIndent", "ArrayHead"},
{"ArrayElem", "ArrayElemIndent", "ArrayElem"},
{"ArrayEnd", "ArrayEndIndent", "Op"},
{"MapHead", "MapHeadIndent", "MapHead"},
{"MapHeadLoad", "MapHeadLoadIndent", "MapHead"},
{"MapKey", "MapKeyIndent", "MapKey"},
{"MapValue", "MapValueIndent", "MapValue"},
{"MapEnd", "MapEndIndent", "Op"},
{"StructFieldHead", "StructFieldHeadIndent", "StructField"},
{"StructFieldHeadOmitEmpty", "StructFieldHeadOmitEmptyIndent", "StructField"},
{"StructFieldHeadStringTag", "StructFieldHeadStringTagIndent", "StructField"},
{"StructFieldAnonymousHead", "StructFieldAnonymousHeadIndent", "StructField"},
{"StructFieldAnonymousHeadOmitEmpty", "StructFieldAnonymousHeadOmitEmptyIndent", "StructField"},
{"StructFieldPtrAnonymousHeadOmitEmpty", "StructFieldPtrAnonymousHeadOmitEmptyIndent", "StructField"},
{"StructFieldAnonymousHeadStringTag", "StructFieldAnonymousHeadStringTagIndent", "StructField"},
{"StructFieldPtrAnonymousHeadStringTag", "StructFieldPtrAnonymousHeadStringTagIndent", "StructField"},
{"StructFieldPtrHead", "StructFieldPtrHeadIndent", "StructField"},
{"StructFieldPtrHeadOmitEmpty", "StructFieldPtrHeadOmitEmptyIndent", "StructField"},
{"StructFieldPtrHeadStringTag", "StructFieldPtrHeadStringTagIndent", "StructField"},
{"StructFieldPtrAnonymousHead", "StructFieldPtrAnonymousHeadIndent", "StructField"},
{"StructField", "StructFieldIndent", "StructField"},
{"StructFieldOmitEmpty", "StructFieldOmitEmptyIndent", "StructField"},
{"StructFieldStringTag", "StructFieldStringTagIndent", "StructField"},
{"StructFieldRecursiveEnd", "StructFieldRecursiveEndIndent", "Op"},
{"StructEnd", "StructEndIndent", "StructField"},
{"StructAnonymousEnd", "StructAnonymousEndIndent", "StructField"},
}
for _, typ := range primitiveTypesUpper {
opTypes = append(opTypes, opType{
Op: typ,
IndentOp: fmt.Sprintf("%sIndent", typ),
Code: "Op",
})
}
for _, prefix := range []string{
"StructFieldHead",
"StructFieldHeadOmitEmpty",
"StructFieldHeadStringTag",
"StructFieldAnonymousHead",
"StructFieldAnonymousHeadOmitEmpty",
"StructFieldAnonymousHeadStringTag",
"StructFieldPtrHead",
"StructFieldPtrHeadOmitEmpty",
"StructFieldPtrHeadStringTag",
"StructFieldPtrAnonymousHead",
"StructFieldPtrAnonymousHeadOmitEmpty",
"StructFieldPtrAnonymousHeadStringTag",
"StructField",
"StructFieldPtr",
"StructFieldOmitEmpty",
"StructFieldStringTag",
} {
for _, typ := range primitiveTypesUpper {
opTypes = append(opTypes, opType{
Op: fmt.Sprintf("%s%s", prefix, typ),
IndentOp: fmt.Sprintf("%s%sIndent", prefix, typ),
Code: "StructField",
})
}
}
for _, typ := range opTypes {
opTypes = append(opTypes, opType{
Op: typ.IndentOp,
IndentOp: typ.IndentOp,
Code: typ.Code,
})
}
base := headType{
Head: "StructFieldHead",
PtrHead: "StructFieldPtrHead",
AnonymousHead: "StructFieldAnonymousHead",
AnonymousPtrHead: "StructFieldPtrAnonymousHead",
OmitEmptyHead: "StructFieldHeadOmitEmpty",
OmitEmptyPtrHead: "StructFieldPtrHeadOmitEmpty",
StringTagHead: "StructFieldHeadStringTag",
StringTagPtrHead: "StructFieldPtrHeadStringTag",
AnonymousOmitEmptyHead: "StructFieldAnonymousHeadOmitEmpty",
AnonymousOmitEmptyPtrHead: "StructFieldPtrAnonymousHeadOmitEmpty",
AnonymousStringTagHead: "StructFieldAnonymousHeadStringTag",
AnonymousStringTagPtrHead: "StructFieldPtrAnonymousHeadStringTag",
}
headTypes := []headType{base}
for _, prim := range primitiveTypesUpper {
headTypes = append(headTypes, headType{
Head: fmt.Sprintf("%s%s", base.Head, prim),
PtrHead: fmt.Sprintf("%s%s", base.PtrHead, prim),
AnonymousHead: fmt.Sprintf("%s%s", base.AnonymousHead, prim),
AnonymousPtrHead: fmt.Sprintf("%s%s", base.AnonymousPtrHead, prim),
OmitEmptyHead: fmt.Sprintf("%s%s", base.OmitEmptyHead, prim),
OmitEmptyPtrHead: fmt.Sprintf("%s%s", base.OmitEmptyPtrHead, prim),
AnonymousOmitEmptyHead: fmt.Sprintf("%s%s", base.AnonymousOmitEmptyHead, prim),
AnonymousOmitEmptyPtrHead: fmt.Sprintf("%s%s", base.AnonymousOmitEmptyPtrHead, prim),
StringTagHead: fmt.Sprintf("%s%s", base.StringTagHead, prim),
StringTagPtrHead: fmt.Sprintf("%s%s", base.StringTagPtrHead, prim),
AnonymousStringTagHead: fmt.Sprintf("%s%s", base.AnonymousStringTagHead, prim),
AnonymousStringTagPtrHead: fmt.Sprintf("%s%s", base.AnonymousStringTagPtrHead, prim),
})
}
for _, typ := range headTypes {
headTypes = append(headTypes, headType{
Head: fmt.Sprintf("%sIndent", typ.Head),
PtrHead: fmt.Sprintf("%sIndent", typ.PtrHead),
AnonymousHead: fmt.Sprintf("%sIndent", typ.AnonymousHead),
AnonymousPtrHead: fmt.Sprintf("%sIndent", typ.AnonymousPtrHead),
OmitEmptyHead: fmt.Sprintf("%sIndent", typ.OmitEmptyHead),
OmitEmptyPtrHead: fmt.Sprintf("%sIndent", typ.OmitEmptyPtrHead),
AnonymousOmitEmptyHead: fmt.Sprintf("%sIndent", typ.AnonymousOmitEmptyHead),
AnonymousOmitEmptyPtrHead: fmt.Sprintf("%sIndent", typ.AnonymousOmitEmptyPtrHead),
StringTagHead: fmt.Sprintf("%sIndent", typ.StringTagHead),
StringTagPtrHead: fmt.Sprintf("%sIndent", typ.StringTagPtrHead),
AnonymousStringTagHead: fmt.Sprintf("%sIndent", typ.AnonymousStringTagHead),
AnonymousStringTagPtrHead: fmt.Sprintf("%sIndent", typ.AnonymousStringTagPtrHead),
})
}
baseField := fieldType{
Field: "StructField",
OmitEmptyField: "StructFieldOmitEmpty",
StringTagField: "StructFieldStringTag",
}
fieldTypes := []fieldType{baseField}
for _, prim := range primitiveTypesUpper {
fieldTypes = append(fieldTypes, fieldType{
Field: fmt.Sprintf("%s%s", baseField.Field, prim),
OmitEmptyField: fmt.Sprintf("%s%s", baseField.OmitEmptyField, prim),
StringTagField: fmt.Sprintf("%s%s", baseField.StringTagField, prim),
})
}
for _, typ := range fieldTypes {
fieldTypes = append(fieldTypes, fieldType{
Field: fmt.Sprintf("%sIndent", typ.Field),
OmitEmptyField: fmt.Sprintf("%sIndent", typ.OmitEmptyField),
StringTagField: fmt.Sprintf("%sIndent", typ.StringTagField),
})
}
var b bytes.Buffer
if err := tmpl.Execute(&b, struct {
CodeTypes []string
OpTypes []opType
HeadTypes []headType
FieldTypes []fieldType
}{
CodeTypes: codeTypes,
OpTypes: opTypes,
HeadTypes: headTypes,
FieldTypes: fieldTypes,
}); err != nil {
return err
}
path := filepath.Join(repoRoot(), "encode_optype.go")
buf, err := format.Source(b.Bytes())
if err != nil {
return err
}
return ioutil.WriteFile(path, buf, 0644)
}
func repoRoot() string {
_, file, _, _ := runtime.Caller(0)
relativePathFromRepoRoot := filepath.Join("cmd", "generator")
return strings.TrimSuffix(filepath.Dir(file), relativePathFromRepoRoot)
}
func main() {
if err := _main(); err != nil {
panic(err)
}
}