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