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  }