1 package main
2
3 import (
4 "bytes"
5 "fmt"
6 "go/format"
7 "go/parser"
8 "go/printer"
9 "go/token"
10 "io/ioutil"
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 ioutil.WriteFile(path, buf, 0644)
277 }
278
279 func generateVM() error {
280 file, err := ioutil.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 := ioutil.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
312 func main() {
313 if err := generateVM(); err != nil {
314 panic(err)
315 }
316 if err := _main(); err != nil {
317 panic(err)
318 }
319 }
320
View as plain text