You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

146 lines
3.5 KiB

  1. package parse
  2. import (
  3. "github.com/tinylib/msgp/gen"
  4. )
  5. // This file defines when and how we
  6. // propagate type information from
  7. // one type declaration to another.
  8. // After the processing pass, every
  9. // non-primitive type is marshalled/unmarshalled/etc.
  10. // through a function call. Here, we propagate
  11. // the type information into the caller's type
  12. // tree *if* the child type is simple enough.
  13. //
  14. // For example, types like
  15. //
  16. // type A [4]int
  17. //
  18. // will get pushed into parent methods,
  19. // whereas types like
  20. //
  21. // type B [3]map[string]struct{A, B [4]string}
  22. //
  23. // will not.
  24. // this is an approximate measure
  25. // of the number of children in a node
  26. const maxComplex = 5
  27. // begin recursive search for identities with the
  28. // given name and replace them with be
  29. func (f *FileSet) findShim(id string, be *gen.BaseElem) {
  30. for name, el := range f.Identities {
  31. pushstate(name)
  32. switch el := el.(type) {
  33. case *gen.Struct:
  34. for i := range el.Fields {
  35. f.nextShim(&el.Fields[i].FieldElem, id, be)
  36. }
  37. case *gen.Array:
  38. f.nextShim(&el.Els, id, be)
  39. case *gen.Slice:
  40. f.nextShim(&el.Els, id, be)
  41. case *gen.Map:
  42. f.nextShim(&el.Value, id, be)
  43. case *gen.Ptr:
  44. f.nextShim(&el.Value, id, be)
  45. }
  46. popstate()
  47. }
  48. // we'll need this at the top level as well
  49. f.Identities[id] = be
  50. }
  51. func (f *FileSet) nextShim(ref *gen.Elem, id string, be *gen.BaseElem) {
  52. if (*ref).TypeName() == id {
  53. vn := (*ref).Varname()
  54. *ref = be.Copy()
  55. (*ref).SetVarname(vn)
  56. } else {
  57. switch el := (*ref).(type) {
  58. case *gen.Struct:
  59. for i := range el.Fields {
  60. f.nextShim(&el.Fields[i].FieldElem, id, be)
  61. }
  62. case *gen.Array:
  63. f.nextShim(&el.Els, id, be)
  64. case *gen.Slice:
  65. f.nextShim(&el.Els, id, be)
  66. case *gen.Map:
  67. f.nextShim(&el.Value, id, be)
  68. case *gen.Ptr:
  69. f.nextShim(&el.Value, id, be)
  70. }
  71. }
  72. }
  73. // propInline identifies and inlines candidates
  74. func (f *FileSet) propInline() {
  75. for name, el := range f.Identities {
  76. pushstate(name)
  77. switch el := el.(type) {
  78. case *gen.Struct:
  79. for i := range el.Fields {
  80. f.nextInline(&el.Fields[i].FieldElem, name)
  81. }
  82. case *gen.Array:
  83. f.nextInline(&el.Els, name)
  84. case *gen.Slice:
  85. f.nextInline(&el.Els, name)
  86. case *gen.Map:
  87. f.nextInline(&el.Value, name)
  88. case *gen.Ptr:
  89. f.nextInline(&el.Value, name)
  90. }
  91. popstate()
  92. }
  93. }
  94. const fatalloop = `detected infinite recursion in inlining loop!
  95. Please file a bug at github.com/tinylib/msgp/issues!
  96. Thanks!
  97. `
  98. func (f *FileSet) nextInline(ref *gen.Elem, root string) {
  99. switch el := (*ref).(type) {
  100. case *gen.BaseElem:
  101. // ensure that we're not inlining
  102. // a type into itself
  103. typ := el.TypeName()
  104. if el.Value == gen.IDENT && typ != root {
  105. if node, ok := f.Identities[typ]; ok && node.Complexity() < maxComplex {
  106. infof("inlining %s\n", typ)
  107. // This should never happen; it will cause
  108. // infinite recursion.
  109. if node == *ref {
  110. panic(fatalloop)
  111. }
  112. *ref = node.Copy()
  113. f.nextInline(ref, node.TypeName())
  114. } else if !ok && !el.Resolved() {
  115. // this is the point at which we're sure that
  116. // we've got a type that isn't a primitive,
  117. // a library builtin, or a processed type
  118. warnf("unresolved identifier: %s\n", typ)
  119. }
  120. }
  121. case *gen.Struct:
  122. for i := range el.Fields {
  123. f.nextInline(&el.Fields[i].FieldElem, root)
  124. }
  125. case *gen.Array:
  126. f.nextInline(&el.Els, root)
  127. case *gen.Slice:
  128. f.nextInline(&el.Els, root)
  129. case *gen.Map:
  130. f.nextInline(&el.Value, root)
  131. case *gen.Ptr:
  132. f.nextInline(&el.Value, root)
  133. default:
  134. panic("bad elem type")
  135. }
  136. }