github.com/goplus/gop@v1.2.6/cl/recorder.go (about) 1 /* 2 * Copyright (c) 2021 The GoPlus Authors (goplus.org). All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package cl 18 19 import ( 20 "go/types" 21 "strings" 22 23 "github.com/goplus/gogen" 24 "github.com/goplus/gop/ast" 25 "github.com/goplus/gop/ast/fromgo" 26 "github.com/goplus/gop/cl/internal/typesutil" 27 "github.com/goplus/gop/token" 28 ) 29 30 type goxRecorder struct { 31 Recorder 32 types map[ast.Expr]types.TypeAndValue 33 refers map[string][]*ast.Ident 34 } 35 36 func newRecorder(rec Recorder) *goxRecorder { 37 types := make(map[ast.Expr]types.TypeAndValue) 38 refers := make(map[string][]*ast.Ident) 39 return &goxRecorder{rec, types, refers} 40 } 41 42 // Refer maps identifiers to name for ast.OverloadFuncDecl. 43 func (p *goxRecorder) Refer(ident *ast.Ident, name string) { 44 p.refers[name] = append(p.refers[name], ident) 45 } 46 47 // Complete computes the types record. 48 func (p *goxRecorder) Complete(scope *types.Scope) { 49 for name, idents := range p.refers { 50 pos := strings.Index(name, ".") 51 if pos == -1 { 52 if obj := scope.Lookup(name); obj != nil { 53 for _, id := range idents { 54 p.Use(id, obj) 55 } 56 } 57 continue 58 } 59 if obj := scope.Lookup(name[:pos]); obj != nil { 60 if named, ok := obj.Type().(*types.Named); ok { 61 n := named.NumMethods() 62 for i := 0; i < n; i++ { 63 if m := named.Method(i); m.Name() == name[pos+1:] { 64 for _, id := range idents { 65 p.Use(id, m) 66 } 67 break 68 } 69 } 70 } 71 } 72 } 73 p.types = nil 74 p.refers = nil 75 } 76 77 // Member maps identifiers to the objects they denote. 78 func (p *goxRecorder) Member(id ast.Node, obj types.Object) { 79 switch v := id.(type) { 80 case *ast.SelectorExpr: 81 sel := v.Sel 82 // TODO: record event for a Go ident 83 if _, ok := fromgo.CheckIdent(sel); !ok { 84 var tv types.TypeAndValue 85 // check v.X call result by value 86 if f, ok := obj.(*types.Var); ok && f.IsField() && p.checkExprByValue(v.X) { 87 tv = typesutil.NewTypeAndValueForValue(obj.Type(), nil, typesutil.Value) 88 } else { 89 tv = typesutil.NewTypeAndValueForObject(obj) 90 } 91 p.Use(sel, obj) 92 p.Type(v, tv) 93 } 94 case *ast.Ident: // it's in a classfile and impossible converted from Go 95 p.Use(v, obj) 96 p.Type(v, typesutil.NewTypeAndValueForObject(obj)) 97 } 98 } 99 100 func (p *goxRecorder) Call(id ast.Node, obj types.Object) { 101 switch v := id.(type) { 102 case *ast.Ident: 103 p.Use(v, obj) 104 p.Type(v, typesutil.NewTypeAndValueForObject(obj)) 105 case *ast.SelectorExpr: 106 p.Use(v.Sel, obj) 107 p.Type(v, typesutil.NewTypeAndValueForObject(obj)) 108 case *ast.CallExpr: 109 switch id := v.Fun.(type) { 110 case *ast.Ident: 111 p.Use(id, obj) 112 case *ast.SelectorExpr: 113 p.Use(id.Sel, obj) 114 } 115 p.Type(v.Fun, typesutil.NewTypeAndValueForObject(obj)) 116 } 117 } 118 119 func (rec *goxRecorder) checkExprByValue(v ast.Expr) bool { 120 if tv, ok := rec.types[v]; ok { 121 switch v.(type) { 122 case *ast.CallExpr: 123 if _, ok := tv.Type.(*types.Pointer); !ok { 124 return true 125 } 126 default: 127 if tv, ok := rec.types[v]; ok { 128 return !tv.Addressable() 129 } 130 } 131 } 132 return false 133 } 134 135 func (rec *goxRecorder) Type(expr ast.Expr, tv types.TypeAndValue) { 136 rec.types[expr] = tv 137 rec.Recorder.Type(expr, tv) 138 } 139 140 func (rec *goxRecorder) instantiate(expr ast.Expr, _, typ types.Type) { 141 // check gox TyOverloadNamed 142 if tv, ok := rec.types[expr]; ok { 143 tv.Type = typ 144 rec.Recorder.Type(expr, tv) 145 } 146 var ident *ast.Ident 147 switch id := expr.(type) { 148 case *ast.Ident: 149 ident = id 150 case *ast.SelectorExpr: 151 ident = id.Sel 152 } 153 if ident != nil { 154 if named, ok := typ.(*types.Named); ok { 155 rec.Use(ident, named.Obj()) 156 } 157 } 158 } 159 160 func (rec *goxRecorder) recordTypeValue(ctx *blockCtx, expr ast.Expr, mode typesutil.OperandMode) { 161 e := ctx.cb.Get(-1) 162 t, _ := gogen.DerefType(e.Type) 163 rec.Type(expr, typesutil.NewTypeAndValueForValue(t, e.CVal, mode)) 164 } 165 166 func (rec *goxRecorder) indexExpr(ctx *blockCtx, expr *ast.IndexExpr) { 167 if tv, ok := rec.types[expr.X]; ok { 168 switch tv.Type.(type) { 169 case *types.Map: 170 rec.recordTypeValue(ctx, expr, typesutil.MapIndex) 171 return 172 case *types.Slice: 173 rec.recordTypeValue(ctx, expr, typesutil.Variable) 174 return 175 } 176 } 177 op := typesutil.Variable 178 switch e := expr.X.(type) { 179 case *ast.CompositeLit: 180 op = typesutil.Value 181 case *ast.SelectorExpr: 182 if rec.checkExprByValue(e.X) { 183 op = typesutil.Value 184 } 185 } 186 rec.recordTypeValue(ctx, expr, op) 187 } 188 189 func (rec *goxRecorder) unaryExpr(ctx *blockCtx, expr *ast.UnaryExpr) { 190 switch expr.Op { 191 case token.ARROW: 192 rec.recordTypeValue(ctx, expr, typesutil.CommaOK) 193 default: 194 rec.recordTypeValue(ctx, expr, typesutil.Value) 195 } 196 } 197 198 func (rec *goxRecorder) recordCallExpr(ctx *blockCtx, v *ast.CallExpr, fnt types.Type) { 199 e := ctx.cb.Get(-1) 200 if _, ok := rec.types[v.Fun]; !ok { 201 rec.Type(v.Fun, typesutil.NewTypeAndValueForValue(fnt, nil, typesutil.Value)) 202 } 203 rec.Type(v, typesutil.NewTypeAndValueForCallResult(e.Type, e.CVal)) 204 } 205 206 func (rec *goxRecorder) recordCompositeLit(v *ast.CompositeLit, typ types.Type) { 207 rec.Type(v.Type, typesutil.NewTypeAndValueForType(typ)) 208 rec.Type(v, typesutil.NewTypeAndValueForValue(typ, nil, typesutil.Value)) 209 } 210 211 func (rec *goxRecorder) recordFuncLit(v *ast.FuncLit, typ types.Type) { 212 rec.Type(v.Type, typesutil.NewTypeAndValueForType(typ)) 213 rec.Type(v, typesutil.NewTypeAndValueForValue(typ, nil, typesutil.Value)) 214 } 215 216 func (rec *goxRecorder) recordType(typ ast.Expr, t types.Type) { 217 rec.Type(typ, typesutil.NewTypeAndValueForType(t)) 218 } 219 220 func (rec *goxRecorder) recordIdent(ident *ast.Ident, obj types.Object) { 221 rec.Use(ident, obj) 222 rec.Type(ident, typesutil.NewTypeAndValueForObject(obj)) 223 } 224 225 func (rec *goxRecorder) recordExpr(ctx *blockCtx, expr ast.Expr, _ bool) { 226 switch v := expr.(type) { 227 case *ast.Ident: 228 case *ast.BasicLit: 229 rec.recordTypeValue(ctx, v, typesutil.Value) 230 case *ast.CallExpr: 231 case *ast.SelectorExpr: 232 if _, ok := rec.types[v]; !ok { 233 rec.recordTypeValue(ctx, v, typesutil.Variable) 234 } 235 case *ast.BinaryExpr: 236 rec.recordTypeValue(ctx, v, typesutil.Value) 237 case *ast.UnaryExpr: 238 rec.unaryExpr(ctx, v) 239 case *ast.FuncLit: 240 case *ast.CompositeLit: 241 case *ast.SliceLit: 242 case *ast.RangeExpr: 243 case *ast.IndexExpr: 244 rec.indexExpr(ctx, v) 245 case *ast.IndexListExpr: 246 case *ast.SliceExpr: 247 rec.recordTypeValue(ctx, v, typesutil.Value) 248 case *ast.StarExpr: 249 rec.recordTypeValue(ctx, v, typesutil.Variable) 250 case *ast.ArrayType: 251 rec.recordTypeValue(ctx, v, typesutil.TypExpr) 252 case *ast.MapType: 253 rec.recordTypeValue(ctx, v, typesutil.TypExpr) 254 case *ast.StructType: 255 rec.recordTypeValue(ctx, v, typesutil.TypExpr) 256 case *ast.ChanType: 257 rec.recordTypeValue(ctx, v, typesutil.TypExpr) 258 case *ast.InterfaceType: 259 rec.recordTypeValue(ctx, v, typesutil.TypExpr) 260 case *ast.ComprehensionExpr: 261 case *ast.TypeAssertExpr: 262 rec.recordTypeValue(ctx, v, typesutil.CommaOK) 263 case *ast.ParenExpr: 264 rec.recordTypeValue(ctx, v, typesutil.Value) 265 case *ast.ErrWrapExpr: 266 case *ast.FuncType: 267 rec.recordTypeValue(ctx, v, typesutil.TypExpr) 268 case *ast.Ellipsis: 269 case *ast.KeyValueExpr: 270 default: 271 } 272 }