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