github.com/switchupcb/yaegi@v0.10.2/interp/gta.go (about) 1 package interp 2 3 import ( 4 "path" 5 "path/filepath" 6 ) 7 8 // gta performs a global types analysis on the AST, registering types, 9 // variables and functions symbols at package level, prior to CFG. 10 // All function bodies are skipped. GTA is necessary to handle out of 11 // order declarations and multiple source files packages. 12 // rpath is the relative path to the directory containing the source for the package. 13 func (interp *Interpreter) gta(root *node, rpath, importPath, pkgName string) ([]*node, error) { 14 sc := interp.initScopePkg(importPath, pkgName) 15 var err error 16 var revisit []*node 17 18 baseName := filepath.Base(interp.fset.Position(root.pos).Filename) 19 20 root.Walk(func(n *node) bool { 21 if err != nil { 22 return false 23 } 24 switch n.kind { 25 case constDecl: 26 // Early parse of constDecl subtree, to compute all constant 27 // values which may be used in further declarations. 28 if _, err = interp.cfg(n, sc, importPath, pkgName); err != nil { 29 // No error processing here, to allow recovery in subtree nodes. 30 // TODO(marc): check for a non recoverable error and return it for better diagnostic. 31 err = nil 32 } 33 34 case blockStmt: 35 if n != root { 36 return false // skip statement block if not the entry point 37 } 38 39 case defineStmt: 40 var ( 41 atyp *itype 42 err2 error 43 ) 44 if n.nleft+n.nright < len(n.child) { 45 // Type is declared explicitly in the assign expression. 46 if atyp, err2 = nodeType(interp, sc, n.child[n.nleft]); err2 != nil { 47 // The type does not exist yet, stash the error and come back 48 // when the type is known. 49 n.meta = err2 50 revisit = append(revisit, n) 51 return false 52 } 53 } 54 55 var sbase int 56 if n.nright > 0 { 57 sbase = len(n.child) - n.nright 58 } 59 60 for i := 0; i < n.nleft; i++ { 61 dest, src := n.child[i], n.child[sbase+i] 62 val := src.rval 63 if n.anc.kind == constDecl { 64 if _, err2 := interp.cfg(n, sc, importPath, pkgName); err2 != nil { 65 // Constant value can not be computed yet. 66 // Come back when child dependencies are known. 67 revisit = append(revisit, n) 68 return false 69 } 70 } 71 typ := atyp 72 if typ == nil { 73 if typ, err2 = nodeType(interp, sc, src); err2 != nil || typ == nil { 74 // The type does is not known yet, stash the error and come back 75 // when the type is known. 76 n.meta = err2 77 revisit = append(revisit, n) 78 return false 79 } 80 val = src.rval 81 } 82 if !typ.isComplete() { 83 // Come back when type is known. 84 revisit = append(revisit, n) 85 return false 86 } 87 if typ.cat == nilT { 88 err = n.cfgErrorf("use of untyped nil") 89 return false 90 } 91 if typ.isBinMethod { 92 typ = valueTOf(typ.methodCallType(), isBinMethod(), withScope(sc)) 93 } 94 sc.sym[dest.ident] = &symbol{kind: varSym, global: true, index: sc.add(typ), typ: typ, rval: val, node: n} 95 if n.anc.kind == constDecl { 96 sc.sym[dest.ident].kind = constSym 97 if childPos(n) == len(n.anc.child)-1 { 98 sc.iota = 0 99 } else { 100 sc.iota++ 101 } 102 } 103 } 104 return false 105 106 case defineXStmt: 107 err = compDefineX(sc, n) 108 109 case valueSpec: 110 l := len(n.child) - 1 111 if n.typ = n.child[l].typ; n.typ == nil { 112 if n.typ, err = nodeType(interp, sc, n.child[l]); err != nil { 113 return false 114 } 115 if !n.typ.isComplete() { 116 // Come back when type is known. 117 revisit = append(revisit, n) 118 return false 119 } 120 } 121 for _, c := range n.child[:l] { 122 asImportName := filepath.Join(c.ident, baseName) 123 sym, exists := sc.sym[asImportName] 124 if !exists { 125 sc.sym[c.ident] = &symbol{index: sc.add(n.typ), kind: varSym, global: true, typ: n.typ, node: n} 126 continue 127 } 128 c.level = globalFrame 129 130 // redeclaration error 131 if sym.typ.node != nil && sym.typ.node.anc != nil { 132 prevDecl := n.interp.fset.Position(sym.typ.node.anc.pos) 133 err = n.cfgErrorf("%s redeclared in this block\n\tprevious declaration at %v", c.ident, prevDecl) 134 return false 135 } 136 err = n.cfgErrorf("%s redeclared in this block", c.ident) 137 return false 138 } 139 140 case funcDecl: 141 if n.typ, err = nodeType(interp, sc, n.child[2]); err != nil { 142 return false 143 } 144 ident := n.child[1].ident 145 switch { 146 case isMethod(n): 147 // Add a method symbol in the receiver type name space 148 var rcvrtype *itype 149 n.ident = ident 150 rcvr := n.child[0].child[0] 151 rtn := rcvr.lastChild() 152 typName, typPtr := rtn.ident, false 153 if typName == "" { 154 typName, typPtr = rtn.child[0].ident, true 155 } 156 sym, _, found := sc.lookup(typName) 157 if !found { 158 n.meta = n.cfgErrorf("undefined: %s", typName) 159 revisit = append(revisit, n) 160 return false 161 } 162 if sym.kind != typeSym || (sym.node != nil && sym.node.kind == typeSpecAssign) { 163 err = n.cfgErrorf("cannot define new methods on non-local type %s", baseType(sym.typ).id()) 164 return false 165 } 166 rcvrtype = sym.typ 167 if typPtr { 168 elementType := sym.typ 169 rcvrtype = ptrOf(elementType, withNode(rtn), withScope(sc)) 170 rcvrtype.incomplete = elementType.incomplete 171 elementType.addMethod(n) 172 } 173 rcvrtype.addMethod(n) 174 n.child[0].child[0].lastChild().typ = rcvrtype 175 case ident == "init": 176 // init functions do not get declared as per the Go spec. 177 default: 178 asImportName := filepath.Join(ident, baseName) 179 if _, exists := sc.sym[asImportName]; exists { 180 // redeclaration error 181 err = n.cfgErrorf("%s redeclared in this block", ident) 182 return false 183 } 184 // Add a function symbol in the package name space except for init 185 sc.sym[n.child[1].ident] = &symbol{kind: funcSym, typ: n.typ, node: n, index: -1} 186 } 187 if !n.typ.isComplete() { 188 revisit = append(revisit, n) 189 } 190 return false 191 192 case importSpec: 193 var name, ipath string 194 if len(n.child) == 2 { 195 ipath = constToString(n.child[1].rval) 196 name = n.child[0].ident 197 } else { 198 ipath = constToString(n.child[0].rval) 199 } 200 // Try to import a binary package first, or a source package 201 var pkgName string 202 if packageName := path.Base(ipath); path.Dir(ipath) == packageName { 203 ipath = packageName 204 } 205 if pkg := interp.binPkg[ipath]; pkg != nil { 206 switch name { 207 case "_": // no import of symbols 208 case ".": // import symbols in current scope 209 for n, v := range pkg { 210 typ := v.Type() 211 if isBinType(v) { 212 typ = typ.Elem() 213 } 214 sc.sym[n] = &symbol{kind: binSym, typ: valueTOf(typ, withScope(sc)), rval: v} 215 } 216 default: // import symbols in package namespace 217 if name == "" { 218 name = interp.pkgNames[ipath] 219 } 220 // Imports of a same package are all mapped in the same scope, so we cannot just 221 // map them by their names, otherwise we could have collisions from same-name 222 // imports in different source files of the same package. Therefore, we suffix 223 // the key with the basename of the source file. 224 name = filepath.Join(name, baseName) 225 if sym, exists := sc.sym[name]; !exists { 226 sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: binPkgT, path: ipath, scope: sc}} 227 break 228 } else if sym.kind == pkgSym && sym.typ.cat == srcPkgT && sym.typ.path == ipath { 229 // ignore re-import of identical package 230 break 231 } 232 233 // redeclaration error. Not caught by the parser. 234 err = n.cfgErrorf("%s redeclared in this block", name) 235 return false 236 } 237 } else if pkgName, err = interp.importSrc(rpath, ipath, NoTest); err == nil { 238 sc.types = interp.universe.types 239 switch name { 240 case "_": // no import of symbols 241 case ".": // import symbols in current namespace 242 for k, v := range interp.srcPkg[ipath] { 243 if canExport(k) { 244 sc.sym[k] = v 245 } 246 } 247 default: // import symbols in package namespace 248 if name == "" { 249 name = pkgName 250 } 251 name = filepath.Join(name, baseName) 252 if sym, exists := sc.sym[name]; !exists { 253 sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: srcPkgT, path: ipath, scope: sc}} 254 break 255 } else if sym.kind == pkgSym && sym.typ.cat == srcPkgT && sym.typ.path == ipath { 256 // ignore re-import of identical package 257 break 258 } 259 260 // redeclaration error 261 err = n.cfgErrorf("%s redeclared as imported package name", name) 262 return false 263 } 264 } else { 265 err = n.cfgErrorf("import %q error: %v", ipath, err) 266 } 267 268 case typeSpec, typeSpecAssign: 269 typeName := n.child[0].ident 270 var typ *itype 271 if typ, err = nodeType(interp, sc, n.child[1]); err != nil { 272 err = nil 273 revisit = append(revisit, n) 274 return false 275 } 276 277 switch n.child[1].kind { 278 case identExpr, selectorExpr: 279 n.typ = namedOf(typ, pkgName, typeName, withNode(n.child[0]), withScope(sc)) 280 n.typ.incomplete = typ.incomplete 281 n.typ.field = typ.field 282 copy(n.typ.method, typ.method) 283 default: 284 n.typ = typ 285 n.typ.name = typeName 286 n.typ.path = pkgName 287 } 288 n.typ.str = n.typ.path + "." + n.typ.name 289 290 asImportName := filepath.Join(typeName, baseName) 291 if _, exists := sc.sym[asImportName]; exists { 292 // redeclaration error 293 err = n.cfgErrorf("%s redeclared in this block", typeName) 294 return false 295 } 296 sym, exists := sc.sym[typeName] 297 if !exists { 298 sc.sym[typeName] = &symbol{kind: typeSym, node: n} 299 } else { 300 if sym.typ != nil && (len(sym.typ.method) > 0) { 301 if n.kind == typeSpecAssign { 302 err = n.cfgErrorf("cannot define new methods on non-local type %s", baseType(typ).id()) 303 return false 304 } 305 // Type has already been seen as a receiver in a method function 306 for _, m := range sym.typ.method { 307 n.typ.addMethod(m) 308 } 309 } else { 310 // TODO(mpl): figure out how to detect redeclarations without breaking type aliases. 311 // Allow redeclarations for now. 312 sc.sym[typeName] = &symbol{kind: typeSym, node: n} 313 } 314 } 315 sc.sym[typeName].typ = n.typ 316 if !n.typ.isComplete() { 317 revisit = append(revisit, n) 318 } 319 return false 320 } 321 return true 322 }, nil) 323 324 if sc != interp.universe { 325 sc.pop() 326 } 327 return revisit, err 328 } 329 330 func baseType(t *itype) *itype { 331 for { 332 switch t.cat { 333 case ptrT, aliasT: 334 t = t.val 335 default: 336 return t 337 } 338 } 339 } 340 341 // gtaRetry (re)applies gta until all global constants and types are defined. 342 func (interp *Interpreter) gtaRetry(nodes []*node, importPath, pkgName string) error { 343 revisit := []*node{} 344 for { 345 for _, n := range nodes { 346 list, err := interp.gta(n, importPath, importPath, pkgName) 347 if err != nil { 348 return err 349 } 350 revisit = append(revisit, list...) 351 } 352 353 if len(revisit) == 0 || equalNodes(nodes, revisit) { 354 break 355 } 356 357 nodes = revisit 358 revisit = []*node{} 359 } 360 361 if len(revisit) > 0 { 362 n := revisit[0] 363 switch n.kind { 364 case typeSpec, typeSpecAssign: 365 if err := definedType(n.typ); err != nil { 366 return err 367 } 368 case defineStmt, funcDecl: 369 if err, ok := n.meta.(error); ok { 370 return err 371 } 372 } 373 return n.cfgErrorf("constant definition loop") 374 } 375 return nil 376 } 377 378 func definedType(typ *itype) error { 379 if !typ.incomplete { 380 return nil 381 } 382 switch typ.cat { 383 case interfaceT, structT: 384 for _, f := range typ.field { 385 if err := definedType(f.typ); err != nil { 386 return err 387 } 388 } 389 case funcT: 390 for _, t := range typ.arg { 391 if err := definedType(t); err != nil { 392 return err 393 } 394 } 395 for _, t := range typ.ret { 396 if err := definedType(t); err != nil { 397 return err 398 } 399 } 400 case mapT: 401 if err := definedType(typ.key); err != nil { 402 return err 403 } 404 fallthrough 405 case aliasT, arrayT, chanT, chanSendT, chanRecvT, ptrT, variadicT: 406 if err := definedType(typ.val); err != nil { 407 return err 408 } 409 case nilT: 410 return typ.node.cfgErrorf("undefined: %s", typ.node.ident) 411 } 412 return nil 413 } 414 415 // equalNodes returns true if two slices of nodes are identical. 416 func equalNodes(a, b []*node) bool { 417 if len(a) != len(b) { 418 return false 419 } 420 for i, n := range a { 421 if n != b[i] { 422 return false 423 } 424 } 425 return true 426 }