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
409type ShimMode int
410
411const (
412	Cast ShimMode = iota
413	Convert
414)
415
416// BaseElem is an element that
417// can be represented by a primitive
418// MessagePack type.
419type BaseElem struct {
420	common
421	ShimMode     ShimMode  // Method used to shim
422	ShimToBase   string    // shim to base type, or empty
423	ShimFromBase string    // shim from base type, or empty
424	Value        Primitive // Type of element
425	Convert      bool      // should we do an explicit conversion?
426	mustinline   bool      // must inline; not printable
427	needsref     bool      // needs reference for shim
428}
429
430func (s *BaseElem) Printable() bool { return !s.mustinline }
431
432func (s *BaseElem) Alias(typ string) {
433	s.common.Alias(typ)
434	if s.Value != IDENT {
435		s.Convert = true
436	}
437	if strings.Contains(typ, ".") {
438		s.mustinline = true
439	}
440}
441
442func (s *BaseElem) SetVarname(a string) {
443	// extensions whose parents
444	// are not pointers need to
445	// be explicitly referenced
446	if s.Value == Ext || s.needsref {
447		if strings.HasPrefix(a, "*") {
448			s.common.SetVarname(a[1:])
449			return
450		}
451		s.common.SetVarname("&" + a)
452		return
453	}
454
455	s.common.SetVarname(a)
456}
457
458// TypeName returns the syntactically correct Go
459// type name for the base element.
460func (s *BaseElem) TypeName() string {
461	if s.common.alias != "" {
462		return s.common.alias
463	}
464	s.common.Alias(s.BaseType())
465	return s.common.alias
466}
467
468// ToBase, used if Convert==true, is used as tmp = {{ToBase}}({{Varname}})
469func (s *BaseElem) ToBase() string {
470	if s.ShimToBase != "" {
471		return s.ShimToBase
472	}
473	return s.BaseType()
474}
475
476// FromBase, used if Convert==true, is used as {{Varname}} = {{FromBase}}(tmp)
477func (s *BaseElem) FromBase() string {
478	if s.ShimFromBase != "" {
479		return s.ShimFromBase
480	}
481	return s.TypeName()
482}
483
484// BaseName returns the string form of the
485// base type (e.g. Float64, Ident, etc)
486func (s *BaseElem) BaseName() string {
487	// time is a special case;
488	// we strip the package prefix
489	if s.Value == Time {
490		return "Time"
491	}
492	return s.Value.String()
493}
494
495func (s *BaseElem) BaseType() string {
496	switch s.Value {
497	case IDENT:
498		return s.TypeName()
499
500	// exceptions to the naming/capitalization
501	// rule:
502	case Intf:
503		return "interface{}"
504	case Bytes:
505		return "[]byte"
506	case Time:
507		return "time.Time"
508	case Ext:
509		return "msgp.Extension"
510
511	// everything else is base.String() with
512	// the first letter as lowercase
513	default:
514		return strings.ToLower(s.BaseName())
515	}
516}
517
518func (s *BaseElem) Needsref(b bool) {
519	s.needsref = b
520}
521
522func (s *BaseElem) Copy() Elem {
523	g := *s
524	return &g
525}
526
527func (s *BaseElem) Complexity() int {
528	if s.Convert && !s.mustinline {
529		return 2
530	}
531	// we need to return 1 if !printable(),
532	// in order to make sure that stuff gets
533	// inlined appropriately
534	return 1
535}
536
537// Resolved returns whether or not
538// the type of the element is
539// a primitive or a builtin provided
540// by the package.
541func (s *BaseElem) Resolved() bool {
542	if s.Value == IDENT {
543		_, ok := builtins[s.TypeName()]
544		return ok
545	}
546	return true
547}
548
549func (k Primitive) String() string {
550	switch k {
551	case String:
552		return "String"
553	case Bytes:
554		return "Bytes"
555	case Float32:
556		return "Float32"
557	case Float64:
558		return "Float64"
559	case Complex64:
560		return "Complex64"
561	case Complex128:
562		return "Complex128"
563	case Uint:
564		return "Uint"
565	case Uint8:
566		return "Uint8"
567	case Uint16:
568		return "Uint16"
569	case Uint32:
570		return "Uint32"
571	case Uint64:
572		return "Uint64"
573	case Byte:
574		return "Byte"
575	case Int:
576		return "Int"
577	case Int8:
578		return "Int8"
579	case Int16:
580		return "Int16"
581	case Int32:
582		return "Int32"
583	case Int64:
584		return "Int64"
585	case Bool:
586		return "Bool"
587	case Intf:
588		return "Intf"
589	case Time:
590		return "time.Time"
591	case Ext:
592		return "Extension"
593	case IDENT:
594		return "Ident"
595	default:
596		return "INVALID"
597	}
598}
599
600// writeStructFields is a trampoline for writeBase for
601// all of the fields in a struct
602func writeStructFields(s []StructField, name string) {
603	for i := range s {
604		s[i].FieldElem.SetVarname(fmt.Sprintf("%s.%s", name, s[i].FieldName))
605	}
606}
607