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