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 }