github.com/tardisgo/tardisgo@v0.0.0-20161119180838-e0dd9a7e46b5/pogo/pogotypes.go (about)

     1  // Copyright 2014 Elliott Stoneham and The TARDIS Go Authors
     2  // Use of this source code is governed by an MIT-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package pogo
     6  
     7  import (
     8  	"fmt"
     9  	"go/types"
    10  	"reflect"
    11  	"sort"
    12  
    13  	"golang.org/x/tools/go/ssa"
    14  )
    15  
    16  // IsValidInPogo exists to screen out any types that the system does not handle correctly.
    17  // Currently it should say everything is valid.
    18  // TODO review if still required in this form.
    19  func (comp *Compilation) IsValidInPogo(et types.Type, posStr string) bool {
    20  	switch et.(type) {
    21  	case *types.Basic:
    22  		switch et.(*types.Basic).Kind() {
    23  		case types.Bool, types.String, types.Float64, types.Float32,
    24  			types.Int, types.Int8, types.Int16, types.Int32,
    25  			types.Uint, types.Uint8, types.Uint16, types.Uint32, types.Int64, types.Uint64,
    26  			types.Complex64, types.Complex128,
    27  			types.Uintptr, types.UnsafePointer:
    28  			return true
    29  		case types.UntypedInt, types.UntypedRune, types.UntypedBool,
    30  			types.UntypedString, types.UntypedFloat, types.UntypedComplex:
    31  			return true
    32  		default:
    33  			if et.(*types.Basic).String() == "invalid type" { // the type of unused map value itterators!
    34  				return true
    35  			}
    36  			comp.LogError(posStr, "pogo", fmt.Errorf("basic type %s is not supported", et.(*types.Basic).String()))
    37  		}
    38  	case *types.Interface, *types.Slice, *types.Struct, *types.Tuple, *types.Map, *types.Pointer, *types.Array,
    39  		*types.Named, *types.Signature, *types.Chan:
    40  		return true
    41  	default:
    42  		rTyp := reflect.TypeOf(et).String()
    43  		if rTyp == "*ssa.opaqueType" { // the type of map itterators!
    44  			return true
    45  		}
    46  		comp.LogError(posStr, "pogo", fmt.Errorf("type %s is not supported", rTyp))
    47  	}
    48  	return false
    49  }
    50  
    51  func (comp *Compilation) initTypes() {
    52  	comp.catchReferencedTypesSeen = make(map[string]bool)
    53  	comp.NextTypeID = 1 // entry zero is invalid
    54  }
    55  
    56  // LogTypeUse : As the code generator encounters new types it logs them here, returning a string of the ID for insertion into the code.
    57  func (comp *Compilation) LogTypeUse(t types.Type) string {
    58  	r := comp.TypesEncountered.At(t)
    59  	if r != nil {
    60  		return fmt.Sprintf("%d", r)
    61  	}
    62  	comp.TypesEncountered.Set(t, comp.NextTypeID)
    63  	r = comp.NextTypeID
    64  	comp.NextTypeID++
    65  	return fmt.Sprintf("%d", r)
    66  }
    67  
    68  // TypesWithMethodSets in a utility function to only return seen types
    69  func (comp *Compilation) TypesWithMethodSets() (sets []types.Type) {
    70  	typs := comp.rootProgram.RuntimeTypes()
    71  	for _, t := range typs {
    72  		if comp.TypesEncountered.At(t) != nil {
    73  			sets = append(sets, t)
    74  		}
    75  	}
    76  	return sets
    77  }
    78  
    79  // MethodSetFor is a conveniance function
    80  func (comp *Compilation) MethodSetFor(T types.Type) *types.MethodSet {
    81  	return comp.rootProgram.MethodSets.MethodSet(T)
    82  }
    83  
    84  // RootProgram is a conveniance function
    85  func (comp *Compilation) RootProgram() *ssa.Program {
    86  	return comp.rootProgram
    87  }
    88  
    89  func (comp *Compilation) catchReferencedTypes(et types.Type) {
    90  	id := comp.LogTypeUse(et)
    91  	_, seen := comp.catchReferencedTypesSeen[id]
    92  	if seen {
    93  		return
    94  	}
    95  	comp.catchReferencedTypesSeen[id] = true
    96  
    97  	// check that we have all the required methods?
    98  	/*
    99  		for t := 1; t < NextTypeID; t++ { // make sure we do this in a consistent order
   100  			for _, k := range TypesEncountered.Keys() {
   101  				if TypesEncountered.At(k).(int) == t {
   102  					switch k.(type) {
   103  					case *types.Interface:
   104  						if types.Implements(et,k.(*types.Interface)) {
   105  							// TODO call missing method?
   106  						}
   107  					}
   108  				}
   109  			}
   110  		}
   111  	*/
   112  
   113  	//LogTypeUse(types.NewPointer(et))
   114  	switch et.(type) {
   115  	case *types.Named:
   116  		comp.catchReferencedTypes(et.Underlying())
   117  		for m := 0; m < et.(*types.Named).NumMethods(); m++ {
   118  			comp.catchReferencedTypes(et.(*types.Named).Method(m).Type())
   119  		}
   120  	case *types.Array:
   121  		comp.catchReferencedTypes(et.(*types.Array).Elem())
   122  		//catchReferencedTypes(types.NewSlice(et.(*types.Array).Elem()))
   123  	case *types.Pointer:
   124  		comp.catchReferencedTypes(et.(*types.Pointer).Elem())
   125  	case *types.Slice:
   126  		comp.catchReferencedTypes(et.(*types.Slice).Elem())
   127  	case *types.Struct:
   128  		for f := 0; f < et.(*types.Struct).NumFields(); f++ {
   129  			if et.(*types.Struct).Field(f).IsField() {
   130  				comp.catchReferencedTypes(et.(*types.Struct).Field(f).Type())
   131  			}
   132  		}
   133  	case *types.Map:
   134  		comp.catchReferencedTypes(et.(*types.Map).Key())
   135  		comp.catchReferencedTypes(et.(*types.Map).Elem())
   136  	case *types.Signature:
   137  		for i := 0; i < et.(*types.Signature).Params().Len(); i++ {
   138  			comp.catchReferencedTypes(et.(*types.Signature).Params().At(i).Type())
   139  		}
   140  		for o := 0; o < et.(*types.Signature).Results().Len(); o++ {
   141  			comp.catchReferencedTypes(et.(*types.Signature).Results().At(o).Type())
   142  		}
   143  	case *types.Chan:
   144  		comp.catchReferencedTypes(et.(*types.Chan).Elem())
   145  	}
   146  }
   147  
   148  func (comp *Compilation) visitAllTypes() {
   149  	// add the supplied method, required to make sure no synthetic types or types referenced via interfaces have been missed
   150  	rt := comp.rootProgram.RuntimeTypes()
   151  	sort.Sort(TypeSorter(rt))
   152  	for _, T := range rt {
   153  		comp.LogTypeUse(T)
   154  	}
   155  	// ...so just get the full info on the types we've seen
   156  	for t := 1; t < comp.NextTypeID; t++ { // make sure we do this in a consistent order
   157  		for _, k := range comp.TypesEncountered.Keys() {
   158  			if comp.TypesEncountered.At(k).(int) == t {
   159  				comp.catchReferencedTypes(k)
   160  			}
   161  		}
   162  	}
   163  }
   164  
   165  // Wrapper for target language emitTypeInfo()
   166  func (comp *Compilation) emitTypeInfo() {
   167  	comp.visitAllTypes()
   168  	l := comp.TargetLang
   169  
   170  	if len(comp.LibListNoDCE) > 0 { // output target lang type to access named object
   171  		for t := 1; t < comp.NextTypeID; t++ { // make sure we do this in a consistent order
   172  			for _, k := range comp.TypesEncountered.Keys() {
   173  				if comp.TypesEncountered.At(k).(int) == t {
   174  					switch k.(type) {
   175  					case *types.Named:
   176  						if k.(*types.Named).Obj().Exported() {
   177  							fmt.Fprintln(&LanguageList[l].buffer,
   178  								LanguageList[l].TypeStart(k.(*types.Named), k.String()))
   179  							//fmt.Fprintln(&LanguageList[l].buffer,
   180  							//	LanguageList[l].TypeEnd(k.(*types.Named), k.String()))
   181  						}
   182  					}
   183  				}
   184  			}
   185  		}
   186  	}
   187  
   188  	fmt.Fprintln(&LanguageList[l].buffer, LanguageList[l].EmitTypeInfo())
   189  }