forked from mirror/go-json
409 lines
9.5 KiB
Go
409 lines
9.5 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"go/format"
|
|
"io/ioutil"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"text/template"
|
|
)
|
|
|
|
type opType struct {
|
|
Op string
|
|
Code string
|
|
HeadToPtrHead func() string
|
|
HeadToOmitEmptyHead func() string
|
|
HeadToStringTagHead func() string
|
|
PtrHeadToHead func() string
|
|
FieldToEnd func() string
|
|
FieldToOmitEmptyField func() string
|
|
FieldToStringTagField func() string
|
|
}
|
|
|
|
func (t opType) IsHeadToPtrHead() bool {
|
|
return t.Op != t.HeadToPtrHead()
|
|
}
|
|
|
|
func (t opType) IsHeadToOmitEmptyHead() bool {
|
|
return t.Op != t.HeadToOmitEmptyHead()
|
|
}
|
|
|
|
func (t opType) IsHeadToStringTagHead() bool {
|
|
return t.Op != t.HeadToStringTagHead()
|
|
}
|
|
|
|
func (t opType) IsPtrHeadToHead() bool {
|
|
return t.Op != t.PtrHeadToHead()
|
|
}
|
|
|
|
func (t opType) IsFieldToEnd() bool {
|
|
return t.Op != t.FieldToEnd()
|
|
}
|
|
|
|
func (t opType) IsFieldToOmitEmptyField() bool {
|
|
return t.Op != t.FieldToOmitEmptyField()
|
|
}
|
|
|
|
func (t opType) IsFieldToStringTagField() bool {
|
|
return t.Op != t.FieldToStringTagField()
|
|
}
|
|
|
|
func createOpType(op, code string) opType {
|
|
return opType{
|
|
Op: op,
|
|
Code: code,
|
|
HeadToPtrHead: func() string { return op },
|
|
HeadToOmitEmptyHead: func() string { return op },
|
|
HeadToStringTagHead: func() string { return op },
|
|
PtrHeadToHead: func() string { return op },
|
|
FieldToEnd: func() string { return op },
|
|
FieldToOmitEmptyField: func() string { return op },
|
|
FieldToStringTagField: func() string { return op },
|
|
}
|
|
}
|
|
|
|
func _main() error {
|
|
tmpl, err := template.New("").Parse(`// Code generated by internal/cmd/generator. DO NOT EDIT!
|
|
package encoder
|
|
|
|
import (
|
|
"strings"
|
|
)
|
|
|
|
type CodeType int
|
|
|
|
const (
|
|
{{- range $index, $type := .CodeTypes }}
|
|
Code{{ $type }} CodeType = {{ $index }}
|
|
{{- end }}
|
|
)
|
|
|
|
var opTypeStrings = [{{ .OpLen }}]string{
|
|
{{- range $type := .OpTypes }}
|
|
"{{ $type.Op }}",
|
|
{{- end }}
|
|
}
|
|
|
|
type OpType int
|
|
|
|
const (
|
|
{{- range $index, $type := .OpTypes }}
|
|
Op{{ $type.Op }} OpType = {{ $index }}
|
|
{{- end }}
|
|
)
|
|
|
|
func (t OpType) String() string {
|
|
if int(t) >= {{ .OpLen }} {
|
|
return ""
|
|
}
|
|
return opTypeStrings[int(t)]
|
|
}
|
|
|
|
func (t OpType) CodeType() CodeType {
|
|
if strings.Contains(t.String(), "Struct") {
|
|
if strings.Contains(t.String(), "End") {
|
|
return CodeStructEnd
|
|
}
|
|
return CodeStructField
|
|
}
|
|
switch t {
|
|
case OpArray, OpArrayPtr:
|
|
return CodeArrayHead
|
|
case OpArrayElem:
|
|
return CodeArrayElem
|
|
case OpSlice, OpSlicePtr:
|
|
return CodeSliceHead
|
|
case OpSliceElem:
|
|
return CodeSliceElem
|
|
case OpMap, OpMapPtr:
|
|
return CodeMapHead
|
|
case OpMapKey:
|
|
return CodeMapKey
|
|
case OpMapValue:
|
|
return CodeMapValue
|
|
case OpMapEnd:
|
|
return CodeMapEnd
|
|
}
|
|
|
|
return CodeOp
|
|
}
|
|
|
|
func (t OpType) HeadToPtrHead() OpType {
|
|
if strings.Index(t.String(), "PtrHead") > 0 {
|
|
return t
|
|
}
|
|
|
|
idx := strings.Index(t.String(), "Head")
|
|
if idx == -1 {
|
|
return t
|
|
}
|
|
suffix := "PtrHead"+t.String()[idx+len("Head"):]
|
|
|
|
const toPtrOffset = 3
|
|
if strings.Contains(OpType(int(t) + toPtrOffset).String(), suffix) {
|
|
return OpType(int(t) + toPtrOffset)
|
|
}
|
|
return t
|
|
}
|
|
|
|
func (t OpType) HeadToOmitEmptyHead() OpType {
|
|
const toOmitEmptyOffset = 1
|
|
if strings.Contains(OpType(int(t) + toOmitEmptyOffset).String(), "OmitEmpty") {
|
|
return OpType(int(t) + toOmitEmptyOffset)
|
|
}
|
|
|
|
return t
|
|
}
|
|
|
|
func (t OpType) HeadToStringTagHead() OpType {
|
|
const toStringTagOffset = 2
|
|
if strings.Contains(OpType(int(t) + toStringTagOffset).String(), "StringTag") {
|
|
return OpType(int(t) + toStringTagOffset)
|
|
}
|
|
return t
|
|
}
|
|
|
|
func (t OpType) PtrHeadToHead() OpType {
|
|
idx := strings.Index(t.String(), "Ptr")
|
|
if idx == -1 {
|
|
return t
|
|
}
|
|
suffix := t.String()[idx+len("Ptr"):]
|
|
|
|
const toPtrOffset = 3
|
|
if strings.Contains(OpType(int(t) - toPtrOffset).String(), suffix) {
|
|
return OpType(int(t) - toPtrOffset)
|
|
}
|
|
return t
|
|
}
|
|
|
|
func (t OpType) FieldToEnd() OpType {
|
|
idx := strings.Index(t.String(), "Field")
|
|
if idx == -1 {
|
|
return t
|
|
}
|
|
suffix := t.String()[idx+len("Field"):]
|
|
if suffix == "" || suffix == "OmitEmpty" || suffix == "StringTag" {
|
|
return t
|
|
}
|
|
const toEndOffset = 3
|
|
if strings.Contains(OpType(int(t) + toEndOffset).String(), "End"+suffix) {
|
|
return OpType(int(t) + toEndOffset)
|
|
}
|
|
return t
|
|
}
|
|
|
|
func (t OpType) FieldToOmitEmptyField() OpType {
|
|
const toOmitEmptyOffset = 1
|
|
if strings.Contains(OpType(int(t) + toOmitEmptyOffset).String(), "OmitEmpty") {
|
|
return OpType(int(t) + toOmitEmptyOffset)
|
|
}
|
|
return t
|
|
}
|
|
|
|
func (t OpType) FieldToStringTagField() OpType {
|
|
const toStringTagOffset = 2
|
|
if strings.Contains(OpType(int(t) + toStringTagOffset).String(), "StringTag") {
|
|
return OpType(int(t) + toStringTagOffset)
|
|
}
|
|
return t
|
|
}
|
|
|
|
`)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
codeTypes := []string{
|
|
"Op",
|
|
"ArrayHead",
|
|
"ArrayElem",
|
|
"SliceHead",
|
|
"SliceElem",
|
|
"MapHead",
|
|
"MapKey",
|
|
"MapValue",
|
|
"MapEnd",
|
|
"StructFieldRecursive",
|
|
"StructField",
|
|
"StructEnd",
|
|
}
|
|
primitiveTypes := []string{
|
|
"int", "uint", "float32", "float64", "bool", "string", "bytes", "number",
|
|
"array", "map", "slice", "struct", "MarshalJSON", "MarshalText", "recursive",
|
|
"intString", "uintString",
|
|
"intPtr", "uintPtr", "float32Ptr", "float64Ptr", "boolPtr", "stringPtr", "bytesPtr", "numberPtr",
|
|
"arrayPtr", "mapPtr", "slicePtr", "marshalJSONPtr", "marshalTextPtr", "interfacePtr", "recursivePtr",
|
|
}
|
|
primitiveTypesUpper := []string{}
|
|
for _, typ := range primitiveTypes {
|
|
primitiveTypesUpper = append(primitiveTypesUpper, strings.ToUpper(string(typ[0]))+typ[1:])
|
|
}
|
|
opTypes := []opType{
|
|
createOpType("End", "Op"),
|
|
createOpType("Interface", "Op"),
|
|
createOpType("Ptr", "Op"),
|
|
createOpType("SliceElem", "SliceElem"),
|
|
createOpType("SliceEnd", "Op"),
|
|
createOpType("ArrayElem", "ArrayElem"),
|
|
createOpType("ArrayEnd", "Op"),
|
|
createOpType("MapKey", "MapKey"),
|
|
createOpType("MapValue", "MapValue"),
|
|
createOpType("MapEnd", "Op"),
|
|
createOpType("StructFieldRecursiveEnd", "Op"),
|
|
createOpType("StructAnonymousEnd", "StructEnd"),
|
|
}
|
|
for _, typ := range primitiveTypesUpper {
|
|
typ := typ
|
|
opTypes = append(opTypes, createOpType(typ, "Op"))
|
|
}
|
|
for _, typ := range append(primitiveTypesUpper, "") {
|
|
for _, ptrOrNot := range []string{"", "Ptr"} {
|
|
for _, opt := range []string{"", "OmitEmpty", "StringTag"} {
|
|
ptrOrNot := ptrOrNot
|
|
opt := opt
|
|
typ := typ
|
|
|
|
op := fmt.Sprintf(
|
|
"Struct%sHead%s%s",
|
|
ptrOrNot,
|
|
opt,
|
|
typ,
|
|
)
|
|
opTypes = append(opTypes, opType{
|
|
Op: op,
|
|
Code: "StructField",
|
|
HeadToPtrHead: func() string {
|
|
return fmt.Sprintf(
|
|
"StructPtrHead%s%s",
|
|
opt,
|
|
typ,
|
|
)
|
|
},
|
|
HeadToOmitEmptyHead: func() string {
|
|
return fmt.Sprintf(
|
|
"Struct%sHeadOmitEmpty%s",
|
|
ptrOrNot,
|
|
typ,
|
|
)
|
|
},
|
|
HeadToStringTagHead: func() string {
|
|
return fmt.Sprintf(
|
|
"Struct%sHeadStringTag%s",
|
|
ptrOrNot,
|
|
typ,
|
|
)
|
|
},
|
|
PtrHeadToHead: func() string {
|
|
return fmt.Sprintf(
|
|
"StructHead%s%s",
|
|
opt,
|
|
typ,
|
|
)
|
|
},
|
|
FieldToEnd: func() string { return op },
|
|
FieldToOmitEmptyField: func() string { return op },
|
|
FieldToStringTagField: func() string { return op },
|
|
})
|
|
}
|
|
}
|
|
}
|
|
for _, typ := range append(primitiveTypesUpper, "") {
|
|
for _, opt := range []string{"", "OmitEmpty", "StringTag"} {
|
|
opt := opt
|
|
typ := typ
|
|
|
|
op := fmt.Sprintf(
|
|
"StructField%s%s",
|
|
opt,
|
|
typ,
|
|
)
|
|
opTypes = append(opTypes, opType{
|
|
Op: op,
|
|
Code: "StructField",
|
|
HeadToPtrHead: func() string { return op },
|
|
HeadToOmitEmptyHead: func() string { return op },
|
|
HeadToStringTagHead: func() string { return op },
|
|
PtrHeadToHead: func() string { return op },
|
|
FieldToEnd: func() string {
|
|
switch typ {
|
|
case "", "Array", "Map", "Slice", "Struct", "Recursive":
|
|
return op
|
|
}
|
|
return fmt.Sprintf(
|
|
"StructEnd%s%s",
|
|
opt,
|
|
typ,
|
|
)
|
|
},
|
|
FieldToOmitEmptyField: func() string {
|
|
return fmt.Sprintf(
|
|
"StructFieldOmitEmpty%s",
|
|
typ,
|
|
)
|
|
},
|
|
FieldToStringTagField: func() string {
|
|
return fmt.Sprintf(
|
|
"StructFieldStringTag%s",
|
|
typ,
|
|
)
|
|
},
|
|
})
|
|
}
|
|
for _, opt := range []string{"", "OmitEmpty", "StringTag"} {
|
|
opt := opt
|
|
typ := typ
|
|
|
|
op := fmt.Sprintf(
|
|
"StructEnd%s%s",
|
|
opt,
|
|
typ,
|
|
)
|
|
opTypes = append(opTypes, opType{
|
|
Op: op,
|
|
Code: "StructEnd",
|
|
HeadToPtrHead: func() string { return op },
|
|
HeadToOmitEmptyHead: func() string { return op },
|
|
HeadToStringTagHead: func() string { return op },
|
|
PtrHeadToHead: func() string { return op },
|
|
FieldToEnd: func() string { return op },
|
|
FieldToOmitEmptyField: func() string { return op },
|
|
FieldToStringTagField: func() string { return op },
|
|
})
|
|
}
|
|
}
|
|
var b bytes.Buffer
|
|
if err := tmpl.Execute(&b, struct {
|
|
CodeTypes []string
|
|
OpTypes []opType
|
|
OpLen int
|
|
}{
|
|
CodeTypes: codeTypes,
|
|
OpTypes: opTypes,
|
|
OpLen: len(opTypes),
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
path := filepath.Join(repoRoot(), "internal", "encoder", "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("internal", "cmd", "generator")
|
|
return strings.TrimSuffix(filepath.Dir(file), relativePathFromRepoRoot)
|
|
}
|
|
|
|
//go:generate go run main.go
|
|
func main() {
|
|
if err := _main(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|