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