1package gen
2
3import (
4	"fmt"
5	"math/rand"
6	"strings"
7)
8
9const (
10	idxChars = "abcdefghijlkmnopqrstuvwxyz"
11	idxLen   = 3
12)
13
14// generate a random identifier name
15func randIdent() string {
16	bts := make([]byte, idxLen)
17	for i := range bts {
18		bts[i] = idxChars[rand.Intn(len(idxChars))]
19	}
20
21	// Use a `z` prefix so the randomly generated bytes can't conflict with
22	// Go keywords (such as `int` and `var`).
23	return "z" + string(bts)
24}
25
26// This code defines the type declaration tree.
27//
28// Consider the following:
29//
30// type Marshaler struct {
31// 	  Thing1 *float64 `msg:"thing1"`
32// 	  Body   []byte   `msg:"body"`
33// }
34//
35// A parser using this generator as a backend
36// should parse the above into:
37//
38// var val Elem = &Ptr{
39// 	name: "z",
40// 	Value: &Struct{
41// 		Name: "Marshaler",
42// 		Fields: []StructField{
43// 			{
44// 				FieldTag: "thing1",
45// 				FieldElem: &Ptr{
46// 					name: "z.Thing1",
47// 					Value: &BaseElem{
48// 						name:    "*z.Thing1",
49// 						Value:   Float64,
50//						Convert: false,
51// 					},
52// 				},
53// 			},
54// 			{
55// 				FieldTag: "body",
56// 				FieldElem: &BaseElem{
57// 					name:    "z.Body",
58// 					Value:   Bytes,
59// 					Convert: false,
60// 				},
61// 			},
62// 		},
63// 	},
64// }
65
66// Base is one of the
67// base types
68type Primitive uint8
69
70// this is effectively the
71// list of currently available
72// ReadXxxx / WriteXxxx methods.
73const (
74	Invalid Primitive = iota
75	Bytes
76	String
77	Float32
78	Float64
79	Complex64
80	Complex128
81	Uint
82	Uint8
83	Uint16
84	Uint32
85	Uint64
86	Byte
87	Int
88	Int8
89	Int16
90	Int32
91	Int64
92	Bool
93	Intf // interface{}
94	Time // time.Time
95	Ext  // extension
96
97	IDENT // IDENT means an unrecognized identifier
98)
99
100// all of the recognized identities
101// that map to primitive types
102var primitives = map[string]Primitive{
103	"[]byte":         Bytes,
104	"string":         String,
105	"float32":        Float32,
106	"float64":        Float64,
107	"complex64":      Complex64,
108	"complex128":     Complex128,
109	"uint":           Uint,
110	"uint8":          Uint8,
111	"uint16":         Uint16,
112	"uint32":         Uint32,
113	"uint64":         Uint64,
114	"byte":           Byte,
115	"int":            Int,
116	"int8":           Int8,
117	"int16":          Int16,
118	"int32":          Int32,
119	"int64":          Int64,
120	"bool":           Bool,
121	"interface{}":    Intf,
122	"time.Time":      Time,
123	"msgp.Extension": Ext,
124}
125
126// types built into the library
127// that satisfy all of the
128// interfaces.
129var builtins = map[string]struct{}{
130	"msgp.Raw":    struct{}{},
131	"msgp.Number": struct{}{},
132}
133
134// common data/methods for every Elem
135type common struct{ vname, alias string }
136
137func (c *common) SetVarname(s string) { c.vname = s }
138func (c *common) Varname() string     { return c.vname }
139func (c *common) Alias(typ string)    { c.alias = typ }
140func (c *common) hidden()             {}
141
142func IsPrintable(e Elem) bool {
143	if be, ok := e.(*BaseElem); ok && !be.Printable() {
144		return false
145	}
146	return true
147}
148
149// Elem is a go type capable of being
150// serialized into MessagePack. It is
151// implemented by *Ptr, *Struct, *Array,
152// *Slice, *Map, and *BaseElem.
153type Elem interface {
154	// SetVarname sets this nodes
155	// variable name and recursively
156	// sets the names of all its children.
157	// In general, this should only be
158	// called on the parent of the tree.
159	SetVarname(s string)
160
161	// Varname returns the variable
162	// name of the element.
163	Varname() string
164
165	// TypeName is the canonical
166	// go type name of the node
167	// e.g. "string", "int", "map[string]float64"
168	// OR the alias name, if it has been set.
169	TypeName() string
170
171	// Alias sets a type (alias) name
172	Alias(typ string)
173
174	// Copy should perform a deep copy of the object
175	Copy() Elem
176
177	// Complexity returns a measure of the
178	// complexity of element (greater than
179	// or equal to 1.)
180	Complexity() int
181
182	hidden()
183}
184
185// Ident returns the *BaseElem that corresponds
186// to the provided identity.
187func Ident(id string) *BaseElem {
188	p, ok := primitives[id]
189	if ok {
190		return &BaseElem{Value: p}
191	}
192	be := &BaseElem{Value: IDENT}
193	be.Alias(id)
194	return be
195}
196
197type Array struct {
198	common
199	Index string // index variable name
200	Size  string // array size
201	Els   Elem   // child
202}
203
204func (a *Array) SetVarname(s string) {
205	a.common.SetVarname(s)
206ridx:
207	a.Index = randIdent()
208
209	// try to avoid using the same
210	// index as a parent slice
211	if strings.Contains(a.Varname(), a.Index) {
212		goto ridx
213	}
214
215	a.Els.SetVarname(fmt.Sprintf("%s[%s]", a.Varname(), a.Index))
216}
217
218func (a *Array) TypeName() string {
219	if a.common.alias != "" {
220		return a.common.alias
221	}
222	a.common.Alias(fmt.Sprintf("[%s]%s", a.Size, a.Els.TypeName()))
223	return a.common.alias
224}
225
226func (a *Array) Copy() Elem {
227	b := *a
228	b.Els = a.Els.Copy()
229	return &b
230}
231
232func (a *Array) Complexity() int { return 1 + a.Els.Complexity() }
233
234// Map is a map[string]Elem
235type Map struct {
236	common
237	Keyidx string // key variable name
238	Validx string // value variable name
239	Value  Elem   // value element
240}
241
242func (m *Map) SetVarname(s string) {
243	m.common.SetVarname(s)
244ridx:
245	m.Keyidx = randIdent()
246	m.Validx = randIdent()
247
248	// just in case
249	if m.Keyidx == m.Validx {
250		goto ridx
251	}
252
253	m.Value.SetVarname(m.Validx)
254}
255
256func (m *Map) TypeName() string {
257	if m.common.alias != "" {
258		return m.common.alias
259	}
260	m.common.Alias("map[string]" + m.Value.TypeName())
261	return m.common.alias
262}
263
264func (m *Map) Copy() Elem {
265	g := *m
266	g.Value = m.Value.Copy()
267	return &g
268}
269
270func (m *Map) Complexity() int { return 2 + m.Value.Complexity() }
271
272type Slice struct {
273	common
274	Index string
275	Els   Elem // The type of each element
276}
277
278func (s *Slice) SetVarname(a string) {
279	s.common.SetVarname(a)
280	s.Index = randIdent()
281	varName := s.Varname()
282	if varName[0] == '*' {
283		// Pointer-to-slice requires parenthesis for slicing.
284		varName = "(" + varName + ")"
285	}
286	s.Els.SetVarname(fmt.Sprintf("%s[%s]", varName, s.Index))
287}
288
289func (s *Slice) TypeName() string {
290	if s.common.alias != "" {
291		return s.common.alias
292	}
293	s.common.Alias("[]" + s.Els.TypeName())
294	return s.common.alias
295}
296
297func (s *Slice) Copy() Elem {
298	z := *s
299	z.Els = s.Els.Copy()
300	return &z
301}
302
303func (s *Slice) Complexity() int {
304	return 1 + s.Els.Complexity()
305}
306
307type Ptr struct {
308	common
309	Value Elem
310}
311
312func (s *Ptr) SetVarname(a string) {
313	s.common.SetVarname(a)
314
315	// struct fields are dereferenced
316	// automatically...
317	switch x := s.Value.(type) {
318	case *Struct:
319		// struct fields are automatically dereferenced
320		x.SetVarname(a)
321		return
322
323	case *BaseElem:
324		// identities have pointer receivers
325		if x.Value == IDENT {
326			x.SetVarname(a)
327		} else {
328			x.SetVarname("*" + a)
329		}
330		return
331
332	default:
333		s.Value.SetVarname("*" + a)
334		return
335	}
336}
337
338func (s *Ptr) TypeName() string {
339	if s.common.alias != "" {
340		return s.common.alias
341	}
342	s.common.Alias("*" + s.Value.TypeName())
343	return s.common.alias
344}
345
346func (s *Ptr) Copy() Elem {
347	v := *s
348	v.Value = s.Value.Copy()
349	return &v
350}
351
352func (s *Ptr) Complexity() int { return 1 + s.Value.Complexity() }
353
354func (s *Ptr) Needsinit() bool {
355	if be, ok := s.Value.(*BaseElem); ok && be.needsref {
356		return false
357	}
358	return true
359}
360
361type Struct struct {
362	common
363	Fields  []StructField // field list
364	AsTuple bool          // write as an array instead of a map
365}
366
367func (s *Struct) TypeName() string {
368	if s.common.alias != "" {
369		return s.common.alias
370	}
371	str := "struct{\n"
372	for i := range s.Fields {
373		str += s.Fields[i].FieldName + " " + s.Fields[i].FieldElem.TypeName() + ";\n"
374	}
375	str += "}"
376	s.common.Alias(str)
377	return s.common.alias
378}
379
380func (s *Struct) SetVarname(a string) {
381	s.common.SetVarname(a)
382	writeStructFields(s.Fields, a)
383}
384
385func (s *Struct) Copy() Elem {
386	g := *s
387	g.Fields = make([]StructField, len(s.Fields))
388	copy(g.Fields, s.Fields)
389	for i := range s.Fields {
390		g.Fields[i].FieldElem = s.Fields[i].FieldElem.Copy()
391	}
392	return &g
393}
394
395func (s *Struct) Complexity() int {
396	c := 1
397	for i := range s.Fields {
398		c += s.Fields[i].FieldElem.Complexity()
399	}
400	return c
401}
402
403type StructField struct {
404	FieldTag  string // the string inside the `msg:""` tag
405	FieldName string // the name of the struct field
406	FieldElem Elem   // the field type
407}
408
409// BaseElem is an element that
410// can be represented by a primitive
411// MessagePack type.
412type BaseElem struct {
413	common
414	ShimToBase   string    // shim to base type, or empty
415	ShimFromBase string    // shim from base type, or empty
416	Value        Primitive // Type of element
417	Convert      bool      // should we do an explicit conversion?
418	mustinline   bool      // must inline; not printable
419	needsref     bool      // needs reference for shim
420}
421
422func (s *BaseElem) Printable() bool { return !s.mustinline }
423
424func (s *BaseElem) Alias(typ string) {
425	s.common.Alias(typ)
426	if s.Value != IDENT {
427		s.Convert = true
428	}
429	if strings.Contains(typ, ".") {
430		s.mustinline = true
431	}
432}
433
434func (s *BaseElem) SetVarname(a string) {
435	// extensions whose parents
436	// are not pointers need to
437	// be explicitly referenced
438	if s.Value == Ext || s.needsref {
439		if strings.HasPrefix(a, "*") {
440			s.common.SetVarname(a[1:])
441			return
442		}
443		s.common.SetVarname("&" + a)
444		return
445	}
446
447	s.common.SetVarname(a)
448}
449
450// TypeName returns the syntactically correct Go
451// type name for the base element.
452func (s *BaseElem) TypeName() string {
453	if s.common.alias != "" {
454		return s.common.alias
455	}
456	s.common.Alias(s.BaseType())
457	return s.common.alias
458}
459
460// ToBase, used if Convert==true, is used as tmp = {{ToBase}}({{Varname}})
461func (s *BaseElem) ToBase() string {
462	if s.ShimToBase != "" {
463		return s.ShimToBase
464	}
465	return s.BaseType()
466}
467
468// FromBase, used if Convert==true, is used as {{Varname}} = {{FromBase}}(tmp)
469func (s *BaseElem) FromBase() string {
470	if s.ShimFromBase != "" {
471		return s.ShimFromBase
472	}
473	return s.TypeName()
474}
475
476// BaseName returns the string form of the
477// base type (e.g. Float64, Ident, etc)
478func (s *BaseElem) BaseName() string {
479	// time is a special case;
480	// we strip the package prefix
481	if s.Value == Time {
482		return "Time"
483	}
484	return s.Value.String()
485}
486
487func (s *BaseElem) BaseType() string {
488	switch s.Value {
489	case IDENT:
490		return s.TypeName()
491
492	// exceptions to the naming/capitalization
493	// rule:
494	case Intf:
495		return "interface{}"
496	case Bytes:
497		return "[]byte"
498	case Time:
499		return "time.Time"
500	case Ext:
501		return "msgp.Extension"
502
503	// everything else is base.String() with
504	// the first letter as lowercase
505	default:
506		return strings.ToLower(s.BaseName())
507	}
508}
509
510func (s *BaseElem) Needsref(b bool) {
511	s.needsref = b
512}
513
514func (s *BaseElem) Copy() Elem {
515	g := *s
516	return &g
517}
518
519func (s *BaseElem) Complexity() int {
520	if s.Convert && !s.mustinline {
521		return 2
522	}
523	// we need to return 1 if !printable(),
524	// in order to make sure that stuff gets
525	// inlined appropriately
526	return 1
527}
528
529// Resolved returns whether or not
530// the type of the element is
531// a primitive or a builtin provided
532// by the package.
533func (s *BaseElem) Resolved() bool {
534	if s.Value == IDENT {
535		_, ok := builtins[s.TypeName()]
536		return ok
537	}
538	return true
539}
540
541func (k Primitive) String() string {
542	switch k {
543	case String:
544		return "String"
545	case Bytes:
546		return "Bytes"
547	case Float32:
548		return "Float32"
549	case Float64:
550		return "Float64"
551	case Complex64:
552		return "Complex64"
553	case Complex128:
554		return "Complex128"
555	case Uint:
556		return "Uint"
557	case Uint8:
558		return "Uint8"
559	case Uint16:
560		return "Uint16"
561	case Uint32:
562		return "Uint32"
563	case Uint64:
564		return "Uint64"
565	case Byte:
566		return "Byte"
567	case Int:
568		return "Int"
569	case Int8:
570		return "Int8"
571	case Int16:
572		return "Int16"
573	case Int32:
574		return "Int32"
575	case Int64:
576		return "Int64"
577	case Bool:
578		return "Bool"
579	case Intf:
580		return "Intf"
581	case Time:
582		return "time.Time"
583	case Ext:
584		return "Extension"
585	case IDENT:
586		return "Ident"
587	default:
588		return "INVALID"
589	}
590}
591
592// writeStructFields is a trampoline for writeBase for
593// all of the fields in a struct
594func writeStructFields(s []StructField, name string) {
595	for i := range s {
596		s[i].FieldElem.SetVarname(fmt.Sprintf("%s.%s", name, s[i].FieldName))
597	}
598}
599