github.com/goccy/go-json@v0.10.3-0.20240509105655-5e2ae3f23c1d/internal/cmd/generator/main.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "fmt" 6 "go/format" 7 "go/parser" 8 "go/printer" 9 "go/token" 10 "os" 11 "path/filepath" 12 "runtime" 13 "strings" 14 "text/template" 15 ) 16 17 type opType struct { 18 Op string 19 Code string 20 } 21 22 func createOpType(op, code string) opType { 23 return opType{ 24 Op: op, 25 Code: code, 26 } 27 } 28 29 func _main() error { 30 tmpl, err := template.New("").Parse(`// Code generated by internal/cmd/generator. DO NOT EDIT! 31 package encoder 32 33 import ( 34 "strings" 35 ) 36 37 type CodeType int 38 39 const ( 40 {{- range $index, $type := .CodeTypes }} 41 Code{{ $type }} CodeType = {{ $index }} 42 {{- end }} 43 ) 44 45 var opTypeStrings = [{{ .OpLen }}]string{ 46 {{- range $type := .OpTypes }} 47 "{{ $type.Op }}", 48 {{- end }} 49 } 50 51 type OpType uint16 52 53 const ( 54 {{- range $index, $type := .OpTypes }} 55 Op{{ $type.Op }} OpType = {{ $index }} 56 {{- end }} 57 ) 58 59 func (t OpType) String() string { 60 if int(t) >= {{ .OpLen }} { 61 return "" 62 } 63 return opTypeStrings[int(t)] 64 } 65 66 func (t OpType) CodeType() CodeType { 67 if strings.Contains(t.String(), "Struct") { 68 if strings.Contains(t.String(), "End") { 69 return CodeStructEnd 70 } 71 return CodeStructField 72 } 73 switch t { 74 case OpArray, OpArrayPtr: 75 return CodeArrayHead 76 case OpArrayElem: 77 return CodeArrayElem 78 case OpSlice, OpSlicePtr: 79 return CodeSliceHead 80 case OpSliceElem: 81 return CodeSliceElem 82 case OpMap, OpMapPtr: 83 return CodeMapHead 84 case OpMapKey: 85 return CodeMapKey 86 case OpMapValue: 87 return CodeMapValue 88 case OpMapEnd: 89 return CodeMapEnd 90 } 91 92 return CodeOp 93 } 94 95 func (t OpType) HeadToPtrHead() OpType { 96 if strings.Index(t.String(), "PtrHead") > 0 { 97 return t 98 } 99 100 idx := strings.Index(t.String(), "Head") 101 if idx == -1 { 102 return t 103 } 104 suffix := "PtrHead"+t.String()[idx+len("Head"):] 105 106 const toPtrOffset = 2 107 if strings.Contains(OpType(int(t) + toPtrOffset).String(), suffix) { 108 return OpType(int(t) + toPtrOffset) 109 } 110 return t 111 } 112 113 func (t OpType) HeadToOmitEmptyHead() OpType { 114 const toOmitEmptyOffset = 1 115 if strings.Contains(OpType(int(t) + toOmitEmptyOffset).String(), "OmitEmpty") { 116 return OpType(int(t) + toOmitEmptyOffset) 117 } 118 119 return t 120 } 121 122 func (t OpType) PtrHeadToHead() OpType { 123 idx := strings.Index(t.String(), "PtrHead") 124 if idx == -1 { 125 return t 126 } 127 suffix := t.String()[idx+len("Ptr"):] 128 129 const toPtrOffset = 2 130 if strings.Contains(OpType(int(t) - toPtrOffset).String(), suffix) { 131 return OpType(int(t) - toPtrOffset) 132 } 133 return t 134 } 135 136 func (t OpType) FieldToEnd() OpType { 137 idx := strings.Index(t.String(), "Field") 138 if idx == -1 { 139 return t 140 } 141 suffix := t.String()[idx+len("Field"):] 142 if suffix == "" || suffix == "OmitEmpty" { 143 return t 144 } 145 const toEndOffset = 2 146 if strings.Contains(OpType(int(t) + toEndOffset).String(), "End"+suffix) { 147 return OpType(int(t) + toEndOffset) 148 } 149 return t 150 } 151 152 func (t OpType) FieldToOmitEmptyField() OpType { 153 const toOmitEmptyOffset = 1 154 if strings.Contains(OpType(int(t) + toOmitEmptyOffset).String(), "OmitEmpty") { 155 return OpType(int(t) + toOmitEmptyOffset) 156 } 157 return t 158 } 159 `) 160 if err != nil { 161 return err 162 } 163 codeTypes := []string{ 164 "Op", 165 "ArrayHead", 166 "ArrayElem", 167 "SliceHead", 168 "SliceElem", 169 "MapHead", 170 "MapKey", 171 "MapValue", 172 "MapEnd", 173 "Recursive", 174 "StructField", 175 "StructEnd", 176 } 177 primitiveTypes := []string{ 178 "int", "uint", "float32", "float64", "bool", "string", "bytes", "number", 179 "array", "map", "slice", "struct", "MarshalJSON", "MarshalText", 180 "intString", "uintString", "float32String", "float64String", "boolString", "stringString", "numberString", 181 "intPtr", "uintPtr", "float32Ptr", "float64Ptr", "boolPtr", "stringPtr", "bytesPtr", "numberPtr", 182 "arrayPtr", "mapPtr", "slicePtr", "marshalJSONPtr", "marshalTextPtr", "interfacePtr", 183 "intPtrString", "uintPtrString", "float32PtrString", "float64PtrString", "boolPtrString", "stringPtrString", "numberPtrString", 184 } 185 primitiveTypesUpper := []string{} 186 for _, typ := range primitiveTypes { 187 primitiveTypesUpper = append(primitiveTypesUpper, strings.ToUpper(string(typ[0]))+typ[1:]) 188 } 189 opTypes := []opType{ 190 createOpType("End", "Op"), 191 createOpType("Interface", "Op"), 192 createOpType("Ptr", "Op"), 193 createOpType("SliceElem", "SliceElem"), 194 createOpType("SliceEnd", "Op"), 195 createOpType("ArrayElem", "ArrayElem"), 196 createOpType("ArrayEnd", "Op"), 197 createOpType("MapKey", "MapKey"), 198 createOpType("MapValue", "MapValue"), 199 createOpType("MapEnd", "Op"), 200 createOpType("Recursive", "Op"), 201 createOpType("RecursivePtr", "Op"), 202 createOpType("RecursiveEnd", "Op"), 203 createOpType("InterfaceEnd", "Op"), 204 } 205 for _, typ := range primitiveTypesUpper { 206 typ := typ 207 opTypes = append(opTypes, createOpType(typ, "Op")) 208 } 209 for _, typ := range append(primitiveTypesUpper, "") { 210 for _, ptrOrNot := range []string{"", "Ptr"} { 211 for _, opt := range []string{"", "OmitEmpty"} { 212 ptrOrNot := ptrOrNot 213 opt := opt 214 typ := typ 215 216 op := fmt.Sprintf( 217 "Struct%sHead%s%s", 218 ptrOrNot, 219 opt, 220 typ, 221 ) 222 opTypes = append(opTypes, opType{ 223 Op: op, 224 Code: "StructField", 225 }) 226 } 227 } 228 } 229 for _, typ := range append(primitiveTypesUpper, "") { 230 for _, opt := range []string{"", "OmitEmpty"} { 231 opt := opt 232 typ := typ 233 234 op := fmt.Sprintf( 235 "StructField%s%s", 236 opt, 237 typ, 238 ) 239 opTypes = append(opTypes, opType{ 240 Op: op, 241 Code: "StructField", 242 }) 243 } 244 for _, opt := range []string{"", "OmitEmpty"} { 245 opt := opt 246 typ := typ 247 248 op := fmt.Sprintf( 249 "StructEnd%s%s", 250 opt, 251 typ, 252 ) 253 opTypes = append(opTypes, opType{ 254 Op: op, 255 Code: "StructEnd", 256 }) 257 } 258 } 259 var b bytes.Buffer 260 if err := tmpl.Execute(&b, struct { 261 CodeTypes []string 262 OpTypes []opType 263 OpLen int 264 }{ 265 CodeTypes: codeTypes, 266 OpTypes: opTypes, 267 OpLen: len(opTypes), 268 }); err != nil { 269 return err 270 } 271 path := filepath.Join(repoRoot(), "internal", "encoder", "optype.go") 272 buf, err := format.Source(b.Bytes()) 273 if err != nil { 274 return err 275 } 276 return os.WriteFile(path, buf, 0644) 277 } 278 279 func generateVM() error { 280 file, err := os.ReadFile("vm.go.tmpl") 281 if err != nil { 282 return err 283 } 284 fset := token.NewFileSet() 285 f, err := parser.ParseFile(fset, "", string(file), parser.ParseComments) 286 if err != nil { 287 return err 288 } 289 for _, pkg := range []string{"vm", "vm_indent", "vm_color", "vm_color_indent"} { 290 f.Name.Name = pkg 291 var buf bytes.Buffer 292 printer.Fprint(&buf, fset, f) 293 path := filepath.Join(repoRoot(), "internal", "encoder", pkg, "vm.go") 294 source, err := format.Source(buf.Bytes()) 295 if err != nil { 296 return err 297 } 298 if err := os.WriteFile(path, source, 0644); err != nil { 299 return err 300 } 301 } 302 return nil 303 } 304 305 func repoRoot() string { 306 _, file, _, _ := runtime.Caller(0) 307 relativePathFromRepoRoot := filepath.Join("internal", "cmd", "generator") 308 return strings.TrimSuffix(filepath.Dir(file), relativePathFromRepoRoot) 309 } 310 311 //go:generate go run main.go 312 func main() { 313 if err := generateVM(); err != nil { 314 panic(err) 315 } 316 if err := _main(); err != nil { 317 panic(err) 318 } 319 }