go-json/cmd/generator/main.go

414 lines
9.7 KiB
Go
Raw Normal View History

2020-08-15 11:41:38 +03:00
package main
import (
"bytes"
"fmt"
2020-11-12 18:25:57 +03:00
"go/format"
2020-08-15 11:41:38 +03:00
"io/ioutil"
"path/filepath"
"runtime"
"strings"
"text/template"
)
type opType struct {
2020-12-25 10:06:25 +03:00
Op string
Code string
HeadToPtrHead func() string
HeadToOmitEmptyHead func() string
HeadToStringTagHead func() string
PtrHeadToHead func() string
2020-12-29 18:13:45 +03:00
FieldToEnd func() string
2020-12-25 10:06:25 +03:00
FieldToOmitEmptyField func() string
FieldToStringTagField func() string
2020-08-15 11:41:38 +03:00
}
2020-12-29 21:50:19 +03:00
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()
}
2020-12-25 10:06:25 +03:00
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 },
2020-12-29 18:13:45 +03:00
FieldToEnd: func() string { return op },
2020-12-25 10:06:25 +03:00
FieldToOmitEmptyField: func() string { return op },
FieldToStringTagField: func() string { return op },
}
2020-08-15 11:41:38 +03:00
}
func _main() error {
tmpl, err := template.New("").Parse(`// Code generated by cmd/generator. DO NOT EDIT!
package json
2021-01-10 14:21:58 +03:00
import (
"strings"
)
2020-08-15 11:41:38 +03:00
type codeType int
const (
{{- range $index, $type := .CodeTypes }}
code{{ $type }} codeType = {{ $index }}
{{- end }}
)
2021-01-17 16:23:28 +03:00
var opTypeStrings = [{{ .OpLen }}]string{
{{- range $type := .OpTypes }}
"{{ $type.Op }}",
{{- end }}
}
2020-08-15 11:41:38 +03:00
type opType int
const (
{{- range $index, $type := .OpTypes }}
op{{ $type.Op }} opType = {{ $index }}
{{- end }}
)
func (t opType) String() string {
2021-01-17 16:23:28 +03:00
if int(t) >= {{ .OpLen }} {
return ""
2020-08-15 11:41:38 +03:00
}
2021-01-17 16:23:28 +03:00
return opTypeStrings[int(t)]
2020-08-15 11:41:38 +03:00
}
func (t opType) codeType() codeType {
2021-01-10 18:48:20 +03:00
if strings.Contains(t.String(), "Struct") {
if strings.Contains(t.String(), "End") {
return codeStructEnd
}
return codeStructField
}
2021-03-09 19:11:48 +03:00
if t.String() == "Array" || t.String() == "ArrayPtr" {
2021-01-10 18:48:20 +03:00
return codeArrayHead
}
if strings.Contains(t.String(), "ArrayElem") {
return codeArrayElem
}
2021-03-09 19:11:48 +03:00
if t.String() == "Slice" || t.String() == "SlicePtr" {
2021-01-10 18:48:20 +03:00
return codeSliceHead
}
if strings.Contains(t.String(), "SliceElem") {
return codeSliceElem
}
2021-03-09 19:11:48 +03:00
if t.String() == "Map" || t.String() == "MapPtr" {
2021-01-10 18:48:20 +03:00
return codeMapHead
}
if strings.Contains(t.String(), "MapKey") {
return codeMapKey
}
if strings.Contains(t.String(), "MapValue") {
return codeMapValue
}
if strings.Contains(t.String(), "MapEnd") {
return codeMapEnd
2020-08-15 11:41:38 +03:00
}
2021-01-10 18:48:20 +03:00
2020-08-15 11:41:38 +03:00
return codeOp
}
func (t opType) headToPtrHead() opType {
2021-01-10 18:48:20 +03:00
if strings.Index(t.String(), "PtrHead") > 0 {
return t
}
2020-12-30 10:13:33 +03:00
2021-01-10 18:48:20 +03:00
idx := strings.Index(t.String(), "Field")
if idx == -1 {
return t
}
suffix := "Ptr"+t.String()[idx+len("Field"):]
2021-03-09 19:11:48 +03:00
const toPtrOffset = 3
2021-01-10 18:48:20 +03:00
if strings.Contains(opType(int(t) + toPtrOffset).String(), suffix) {
return opType(int(t) + toPtrOffset)
2020-12-23 07:13:34 +03:00
}
return t
}
2020-08-15 11:41:38 +03:00
func (t opType) headToOmitEmptyHead() opType {
const toOmitEmptyOffset = 1
2021-01-10 18:48:20 +03:00
if strings.Contains(opType(int(t) + toOmitEmptyOffset).String(), "OmitEmpty") {
return opType(int(t) + toOmitEmptyOffset)
2020-08-15 11:41:38 +03:00
}
2021-01-10 18:48:20 +03:00
2020-08-15 11:41:38 +03:00
return t
}
2020-08-19 13:55:06 +03:00
func (t opType) headToStringTagHead() opType {
const toStringTagOffset = 2
2021-01-10 18:48:20 +03:00
if strings.Contains(opType(int(t) + toStringTagOffset).String(), "StringTag") {
return opType(int(t) + toStringTagOffset)
2020-08-19 13:55:06 +03:00
}
return t
}
2020-08-15 11:41:38 +03:00
func (t opType) ptrHeadToHead() opType {
2021-01-10 18:48:20 +03:00
idx := strings.Index(t.String(), "Ptr")
if idx == -1 {
return t
}
suffix := t.String()[idx+len("Ptr"):]
2020-12-30 10:13:33 +03:00
2021-03-09 19:11:48 +03:00
const toPtrOffset = 3
2021-01-10 18:48:20 +03:00
if strings.Contains(opType(int(t) - toPtrOffset).String(), suffix) {
return opType(int(t) - toPtrOffset)
2020-08-15 11:41:38 +03:00
}
return t
}
2020-12-29 18:13:45 +03:00
func (t opType) fieldToEnd() opType {
switch t {
2021-01-11 13:05:06 +03:00
{{- range $type := .OpTypes }}
2020-12-29 21:50:19 +03:00
{{- if $type.IsFieldToEnd }}
2020-12-29 18:13:45 +03:00
case op{{ $type.Op }}:
return op{{ call $type.FieldToEnd }}
2020-12-29 21:50:19 +03:00
{{- end }}
2020-12-29 18:13:45 +03:00
{{- end }}
}
return t
}
2020-08-15 11:41:38 +03:00
func (t opType) fieldToOmitEmptyField() opType {
2021-01-10 18:48:20 +03:00
const toOmitEmptyOffset = 1
if strings.Contains(opType(int(t) + toOmitEmptyOffset).String(), "OmitEmpty") {
return opType(int(t) + toOmitEmptyOffset)
2020-08-15 11:41:38 +03:00
}
return t
}
2020-08-19 13:55:06 +03:00
func (t opType) fieldToStringTagField() opType {
2021-01-10 18:48:20 +03:00
const toStringTagOffset = 2
if strings.Contains(opType(int(t) + toStringTagOffset).String(), "StringTag") {
return opType(int(t) + toStringTagOffset)
2020-08-19 13:55:06 +03:00
}
return t
}
2020-08-15 11:41:38 +03:00
`)
if err != nil {
return err
}
codeTypes := []string{
"Op",
"ArrayHead",
"ArrayElem",
"SliceHead",
"SliceElem",
"MapHead",
"MapKey",
"MapValue",
2020-09-16 08:51:37 +03:00
"MapEnd",
2020-08-15 11:41:38 +03:00
"StructFieldRecursive",
"StructField",
2020-12-29 18:13:45 +03:00
"StructEnd",
2020-08-15 11:41:38 +03:00
}
primitiveTypes := []string{
2021-03-11 08:58:33 +03:00
"int", "uint", "float32", "float64", "bool", "string", "bytes", "number",
2021-03-09 20:12:53 +03:00
"array", "map", "slice", "struct", "MarshalJSON", "MarshalText", "recursive",
2021-02-22 09:16:53 +03:00
"intString", "uintString",
2021-03-11 08:58:33 +03:00
"intPtr", "uintPtr", "float32Ptr", "float64Ptr", "boolPtr", "stringPtr", "bytesPtr", "numberPtr",
2021-03-11 11:59:22 +03:00
"arrayPtr", "mapPtr", "slicePtr", "marshalJSONPtr", "marshalTextPtr", "interfacePtr", "recursivePtr",
2020-08-15 11:41:38 +03:00
}
primitiveTypesUpper := []string{}
for _, typ := range primitiveTypes {
primitiveTypesUpper = append(primitiveTypesUpper, strings.ToUpper(string(typ[0]))+typ[1:])
}
opTypes := []opType{
2020-12-25 10:06:25 +03:00
createOpType("End", "Op"),
createOpType("Interface", "Op"),
createOpType("Ptr", "Op"),
createOpType("RootSliceHead", "SliceHead"),
createOpType("SliceElem", "SliceElem"),
createOpType("RootSliceElem", "SliceElem"),
createOpType("SliceEnd", "Op"),
createOpType("ArrayElem", "ArrayElem"),
createOpType("ArrayEnd", "Op"),
createOpType("MapKey", "MapKey"),
createOpType("MapValue", "MapValue"),
createOpType("MapEnd", "Op"),
createOpType("StructFieldRecursiveEnd", "Op"),
2020-12-29 18:13:45 +03:00
createOpType("StructAnonymousEnd", "StructEnd"),
2020-08-15 11:41:38 +03:00
}
for _, typ := range primitiveTypesUpper {
2020-12-25 10:06:25 +03:00
typ := typ
2021-01-11 13:21:30 +03:00
opTypes = append(opTypes, createOpType(typ, "Op"))
2020-08-15 11:41:38 +03:00
}
2021-01-10 14:21:58 +03:00
for _, typ := range append(primitiveTypesUpper, "") {
2021-03-09 19:11:48 +03:00
for _, ptrOrNot := range []string{"", "Ptr"} {
for _, opt := range []string{"", "OmitEmpty", "StringTag"} {
ptrOrNot := ptrOrNot
opt := opt
typ := typ
op := fmt.Sprintf(
"StructField%sHead%s%s",
ptrOrNot,
opt,
typ,
)
opTypes = append(opTypes, opType{
Op: op,
Code: "StructField",
HeadToPtrHead: func() string {
return fmt.Sprintf(
"StructFieldPtrHead%s%s",
opt,
typ,
)
},
HeadToOmitEmptyHead: func() string {
return fmt.Sprintf(
"StructField%sHeadOmitEmpty%s",
ptrOrNot,
typ,
)
},
HeadToStringTagHead: func() string {
return fmt.Sprintf(
"StructField%sHeadStringTag%s",
ptrOrNot,
typ,
)
},
PtrHeadToHead: func() string {
return fmt.Sprintf(
"StructFieldHead%s%s",
opt,
typ,
)
},
FieldToEnd: func() string { return op },
FieldToOmitEmptyField: func() string { return op },
FieldToStringTagField: func() string { return op },
})
2021-01-08 20:28:33 +03:00
}
}
}
2021-01-10 14:21:58 +03:00
for _, typ := range append(primitiveTypesUpper, "") {
2021-01-11 13:21:30 +03:00
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 {
2021-03-09 20:12:53 +03:00
case "", "Array", "Map", "Slice", "Struct", "Recursive":
2021-01-11 13:21:30 +03:00
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,
)
},
})
2020-12-25 10:06:25 +03:00
}
2020-08-15 11:41:38 +03:00
}
2021-01-10 14:21:58 +03:00
for _, typ := range append(primitiveTypesUpper, "") {
2021-01-11 13:21:30 +03:00
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 },
})
2020-12-29 17:17:15 +03:00
}
}
2020-08-15 11:41:38 +03:00
var b bytes.Buffer
if err := tmpl.Execute(&b, struct {
2021-01-11 13:05:06 +03:00
CodeTypes []string
OpTypes []opType
OpLen int
2020-08-15 11:41:38 +03:00
}{
2021-01-11 13:05:06 +03:00
CodeTypes: codeTypes,
OpTypes: opTypes,
OpLen: len(opTypes),
2020-08-15 11:41:38 +03:00
}); err != nil {
return err
}
path := filepath.Join(repoRoot(), "encode_optype.go")
2020-11-12 18:25:57 +03:00
buf, err := format.Source(b.Bytes())
if err != nil {
return err
}
return ioutil.WriteFile(path, buf, 0644)
2020-08-15 11:41:38 +03:00
}
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)
}
}