go-json/internal/cmd/generator/main.go

320 lines
6.9 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"
2021-05-19 06:34:40 +03:00
"go/parser"
"go/printer"
"go/token"
"os"
2020-08-15 11:41:38 +03:00
"path/filepath"
"runtime"
"strings"
"text/template"
)
type opType struct {
2021-03-19 09:46:53 +03:00
Op string
Code string
2020-12-29 21:50:19 +03:00
}
2020-12-25 10:06:25 +03:00
func createOpType(op, code string) opType {
return opType{
2021-03-19 09:46:53 +03:00
Op: op,
Code: code,
2020-12-25 10:06:25 +03:00
}
2020-08-15 11:41:38 +03:00
}
func _main() error {
2021-03-15 20:50:19 +03:00
tmpl, err := template.New("").Parse(`// Code generated by internal/cmd/generator. DO NOT EDIT!
package encoder
2020-08-15 11:41:38 +03:00
2021-01-10 14:21:58 +03:00
import (
"strings"
)
2021-03-15 20:50:19 +03:00
type CodeType int
2020-08-15 11:41:38 +03:00
const (
{{- range $index, $type := .CodeTypes }}
2021-03-15 20:50:19 +03:00
Code{{ $type }} CodeType = {{ $index }}
2020-08-15 11:41:38 +03:00
{{- end }}
)
2021-01-17 16:23:28 +03:00
var opTypeStrings = [{{ .OpLen }}]string{
{{- range $type := .OpTypes }}
"{{ $type.Op }}",
{{- end }}
}
type OpType uint16
2020-08-15 11:41:38 +03:00
const (
{{- range $index, $type := .OpTypes }}
2021-03-15 20:50:19 +03:00
Op{{ $type.Op }} OpType = {{ $index }}
2020-08-15 11:41:38 +03:00
{{- end }}
)
2021-03-15 20:50:19 +03:00
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
}
2021-03-15 20:50:19 +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") {
2021-03-15 20:50:19 +03:00
return CodeStructEnd
2021-01-10 18:48:20 +03:00
}
2021-03-15 20:50:19 +03:00
return CodeStructField
2021-01-10 18:48:20 +03:00
}
2021-03-15 20:50:19 +03:00
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
2020-08-15 11:41:38 +03:00
}
2021-01-10 18:48:20 +03:00
2021-03-15 20:50:19 +03:00
return CodeOp
2020-08-15 11:41:38 +03:00
}
2021-03-15 20:50:19 +03:00
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-03-15 20:50:19 +03:00
idx := strings.Index(t.String(), "Head")
2021-01-10 18:48:20 +03:00
if idx == -1 {
return t
}
2021-03-16 18:22:19 +03:00
suffix := "PtrHead"+t.String()[idx+len("Head"):]
2021-01-10 18:48:20 +03:00
2021-05-06 14:54:22 +03:00
const toPtrOffset = 2
2021-03-15 20:50:19 +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
}
2021-03-15 20:50:19 +03:00
func (t OpType) HeadToOmitEmptyHead() OpType {
const toOmitEmptyOffset = 1
2021-03-15 20:50:19 +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
}
2021-03-15 20:50:19 +03:00
func (t OpType) PtrHeadToHead() OpType {
idx := strings.Index(t.String(), "PtrHead")
2021-01-10 18:48:20 +03:00
if idx == -1 {
return t
}
suffix := t.String()[idx+len("Ptr"):]
2020-12-30 10:13:33 +03:00
2021-05-06 14:54:22 +03:00
const toPtrOffset = 2
2021-03-15 20:50:19 +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
}
2021-03-15 20:50:19 +03:00
func (t OpType) FieldToEnd() OpType {
idx := strings.Index(t.String(), "Field")
if idx == -1 {
return t
}
suffix := t.String()[idx+len("Field"):]
2021-05-06 14:54:22 +03:00
if suffix == "" || suffix == "OmitEmpty" {
2021-03-16 18:22:19 +03:00
return t
}
2021-05-06 14:54:22 +03:00
const toEndOffset = 2
2021-03-15 20:50:19 +03:00
if strings.Contains(OpType(int(t) + toEndOffset).String(), "End"+suffix) {
return OpType(int(t) + toEndOffset)
2020-12-29 18:13:45 +03:00
}
return t
}
2021-03-15 20:50:19 +03:00
func (t OpType) FieldToOmitEmptyField() OpType {
2021-01-10 18:48:20 +03:00
const toOmitEmptyOffset = 1
2021-03-15 20:50:19 +03:00
if strings.Contains(OpType(int(t) + toOmitEmptyOffset).String(), "OmitEmpty") {
return OpType(int(t) + toOmitEmptyOffset)
2020-08-15 11:41:38 +03:00
}
return t
}
`)
if err != nil {
return err
}
codeTypes := []string{
"Op",
"ArrayHead",
"ArrayElem",
"SliceHead",
"SliceElem",
"MapHead",
"MapKey",
"MapValue",
2020-09-16 08:51:37 +03:00
"MapEnd",
2021-03-19 09:46:53 +03:00
"Recursive",
2020-08-15 11:41:38 +03:00
"StructField",
2020-12-29 18:13:45 +03:00
"StructEnd",
2020-08-15 11:41:38 +03:00
}
primitiveTypes := []string{
"int", "uint", "float32", "float64", "bool", "string", "bytes", "number",
2021-03-19 09:46:53 +03:00
"array", "map", "slice", "struct", "MarshalJSON", "MarshalText",
2021-05-06 14:54:22 +03:00
"intString", "uintString", "float32String", "float64String", "boolString", "stringString", "numberString",
"intPtr", "uintPtr", "float32Ptr", "float64Ptr", "boolPtr", "stringPtr", "bytesPtr", "numberPtr",
2021-03-19 09:46:53 +03:00
"arrayPtr", "mapPtr", "slicePtr", "marshalJSONPtr", "marshalTextPtr", "interfacePtr",
2021-05-06 14:54:22 +03:00
"intPtrString", "uintPtrString", "float32PtrString", "float64PtrString", "boolPtrString", "stringPtrString", "numberPtrString",
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("SliceElem", "SliceElem"),
createOpType("SliceEnd", "Op"),
createOpType("ArrayElem", "ArrayElem"),
createOpType("ArrayEnd", "Op"),
createOpType("MapKey", "MapKey"),
createOpType("MapValue", "MapValue"),
createOpType("MapEnd", "Op"),
2021-03-19 09:46:53 +03:00
createOpType("Recursive", "Op"),
createOpType("RecursivePtr", "Op"),
createOpType("RecursiveEnd", "Op"),
2021-06-25 14:17:12 +03:00
createOpType("InterfaceEnd", "Op"),
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, "") {
for _, ptrOrNot := range []string{"", "Ptr"} {
2021-05-06 14:54:22 +03:00
for _, opt := range []string{"", "OmitEmpty"} {
ptrOrNot := ptrOrNot
opt := opt
typ := typ
op := fmt.Sprintf(
2021-03-15 20:50:19 +03:00
"Struct%sHead%s%s",
ptrOrNot,
opt,
typ,
)
opTypes = append(opTypes, opType{
Op: op,
Code: "StructField",
})
2021-01-08 20:28:33 +03:00
}
}
}
2021-01-10 14:21:58 +03:00
for _, typ := range append(primitiveTypesUpper, "") {
2021-05-06 14:54:22 +03:00
for _, opt := range []string{"", "OmitEmpty"} {
2021-01-11 13:21:30 +03:00
opt := opt
typ := typ
op := fmt.Sprintf(
"StructField%s%s",
opt,
typ,
)
opTypes = append(opTypes, opType{
2021-03-19 09:46:53 +03:00
Op: op,
Code: "StructField",
2021-01-11 13:21:30 +03:00
})
2020-12-25 10:06:25 +03:00
}
2021-05-06 14:54:22 +03:00
for _, opt := range []string{"", "OmitEmpty"} {
2021-01-11 13:21:30 +03:00
opt := opt
typ := typ
op := fmt.Sprintf(
"StructEnd%s%s",
opt,
typ,
)
opTypes = append(opTypes, opType{
2021-03-19 09:46:53 +03:00
Op: op,
Code: "StructEnd",
2021-01-11 13:21:30 +03:00
})
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
}
2021-03-15 20:50:19 +03:00
path := filepath.Join(repoRoot(), "internal", "encoder", "optype.go")
2020-11-12 18:25:57 +03:00
buf, err := format.Source(b.Bytes())
if err != nil {
return err
}
return os.WriteFile(path, buf, 0644)
2020-08-15 11:41:38 +03:00
}
2021-05-19 06:34:40 +03:00
func generateVM() error {
file, err := os.ReadFile("vm.go.tmpl")
2021-05-19 06:34:40 +03:00
if err != nil {
return err
}
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "", string(file), parser.ParseComments)
if err != nil {
return err
}
2021-05-31 21:09:47 +03:00
for _, pkg := range []string{"vm", "vm_indent", "vm_color", "vm_color_indent"} {
2021-05-19 06:34:40 +03:00
f.Name.Name = pkg
var buf bytes.Buffer
printer.Fprint(&buf, fset, f)
path := filepath.Join(repoRoot(), "internal", "encoder", pkg, "vm.go")
source, err := format.Source(buf.Bytes())
if err != nil {
return err
}
if err := os.WriteFile(path, source, 0644); err != nil {
2021-05-19 06:34:40 +03:00
return err
}
}
return nil
}
2020-08-15 11:41:38 +03:00
func repoRoot() string {
_, file, _, _ := runtime.Caller(0)
2021-03-15 20:50:19 +03:00
relativePathFromRepoRoot := filepath.Join("internal", "cmd", "generator")
2020-08-15 11:41:38 +03:00
return strings.TrimSuffix(filepath.Dir(file), relativePathFromRepoRoot)
}
2021-03-15 20:50:19 +03:00
//go:generate go run main.go
2020-08-15 11:41:38 +03:00
func main() {
2021-05-19 06:34:40 +03:00
if err := generateVM(); err != nil {
panic(err)
}
2020-08-15 11:41:38 +03:00
if err := _main(); err != nil {
panic(err)
}
}