package main import ( "bytes" "fmt" "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", "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", } primitiveTypesUpper := []string{} for _, typ := range primitiveTypes { primitiveTypesUpper = append(primitiveTypesUpper, strings.ToUpper(string(typ[0]))+typ[1:]) } opTypes := []opType{ {"End", "EndIndent", "Op"}, {"Interface", "InterfaceIndent", "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"}, {"RootMapHead", "RootMapHeadIndent", "MapHead"}, {"MapKey", "MapKeyIndent", "MapKey"}, {"RootMapKey", "RootMapKeyIndent", "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"}, {"StructFieldRecursive", "StructFieldRecursiveIndent", "StructFieldRecursive"}, {"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", "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") return ioutil.WriteFile(path, b.Bytes(), 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) } }