github.com/traefik/yaegi@v0.15.1/interp/scope.go (about) 1 package interp 2 3 import ( 4 "log" 5 "reflect" 6 "strconv" 7 ) 8 9 // A sKind represents the kind of symbol. 10 type sKind uint 11 12 // Symbol kinds for the Go interpreter. 13 const ( 14 undefSym sKind = iota 15 binSym // Binary from runtime 16 bltnSym // Builtin 17 constSym // Constant 18 funcSym // Function 19 labelSym // Label 20 pkgSym // Package 21 typeSym // Type 22 varTypeSym // Variable type (generic) 23 varSym // Variable 24 ) 25 26 var symKinds = [...]string{ 27 undefSym: "undefSym", 28 binSym: "binSym", 29 bltnSym: "bltnSym", 30 constSym: "constSym", 31 funcSym: "funcSym", 32 labelSym: "labelSym", 33 pkgSym: "pkgSym", 34 typeSym: "typeSym", 35 varTypeSym: "varTypeSym", 36 varSym: "varSym", 37 } 38 39 func (k sKind) String() string { 40 if k < sKind(len(symKinds)) { 41 return symKinds[k] 42 } 43 return "SymKind(" + strconv.Itoa(int(k)) + ")" 44 } 45 46 // A symbol represents an interpreter object such as type, constant, var, func, 47 // label, builtin or binary object. Symbols are defined within a scope. 48 type symbol struct { 49 kind sKind 50 typ *itype // Type of value 51 node *node // Node value if index is negative 52 from []*node // list of goto nodes jumping to this label node, or nil 53 recv *receiver // receiver node value, if sym refers to a method 54 index int // index of value in frame or -1 55 rval reflect.Value // default value (used for constants) 56 builtin bltnGenerator // Builtin function or nil 57 global bool // true if symbol is defined in global space 58 } 59 60 // scope type stores symbols in maps, and frame layout as array of types 61 // The purposes of scopes are to manage the visibility of each symbol 62 // and to store the memory frame layout information (type and index in frame) 63 // at each level (global, package, functions) 64 // 65 // scopes are organized in a stack fashion: a first scope (universe) is created 66 // once at global level, and for each block (package, func, for, etc...), a new 67 // scope is pushed at entry, and poped at exit. 68 // 69 // Nested scopes with the same level value use the same frame: it allows to have 70 // exactly one frame per function, with a fixed position for each variable (named 71 // or not), no matter the inner complexity (number of nested blocks in the function) 72 // 73 // In symbols, the index value corresponds to the index in scope.types, and at 74 // execution to the index in frame, created exactly from the types layout. 75 type scope struct { 76 anc *scope // ancestor upper scope 77 child []*scope // included scopes 78 def *node // function definition node this scope belongs to, or nil 79 loop *node // loop exit node for break statement 80 loopRestart *node // loop restart node for continue statement 81 pkgID string // unique id of package in which scope is defined 82 pkgName string // package name for the package 83 types []reflect.Type // frame layout, may be shared by same level scopes 84 level int // frame level: number of frame indirections to access var during execution 85 sym map[string]*symbol // map of symbols defined in this current scope 86 global bool // true if scope refers to global space (single frame for universe and package level scopes) 87 iota int // iota value in this scope 88 } 89 90 // push creates a new child scope and chain it to the current one. 91 func (s *scope) push(indirect bool) *scope { 92 sc := &scope{anc: s, level: s.level, sym: map[string]*symbol{}} 93 s.child = append(s.child, sc) 94 if indirect { 95 sc.types = []reflect.Type{} 96 sc.level = s.level + 1 97 } else { 98 // Propagate size, types, def and global as scopes at same level share the same frame. 99 sc.types = s.types 100 sc.def = s.def 101 sc.global = s.global 102 sc.level = s.level 103 } 104 // inherit loop state and pkgID from ancestor 105 sc.loop, sc.loopRestart, sc.pkgID = s.loop, s.loopRestart, s.pkgID 106 return sc 107 } 108 109 func (s *scope) pushBloc() *scope { return s.push(false) } 110 func (s *scope) pushFunc() *scope { return s.push(true) } 111 112 func (s *scope) pop() *scope { 113 if s.level == s.anc.level { 114 // Propagate size and types, as scopes at same level share the same frame. 115 s.anc.types = s.types 116 } 117 return s.anc 118 } 119 120 func (s *scope) upperLevel() *scope { 121 level := s.level 122 for s != nil && s.level == level { 123 s = s.anc 124 } 125 return s 126 } 127 128 // lookup searches for a symbol in the current scope, and upper ones if not found 129 // it returns the symbol, the number of indirections level from the current scope 130 // and status (false if no result). 131 func (s *scope) lookup(ident string) (*symbol, int, bool) { 132 level := s.level 133 for { 134 if sym, ok := s.sym[ident]; ok { 135 if sym.global { 136 return sym, globalFrame, true 137 } 138 return sym, level - s.level, true 139 } 140 if s.anc == nil { 141 break 142 } 143 s = s.anc 144 } 145 return nil, 0, false 146 } 147 148 func (s *scope) rangeChanType(n *node) *itype { 149 if sym, _, found := s.lookup(n.child[1].ident); found { 150 if t := sym.typ; len(n.child) == 3 && t != nil && (t.cat == chanT || t.cat == chanRecvT) { 151 return t 152 } 153 } 154 155 c := n.child[1] 156 if c.typ == nil { 157 return nil 158 } 159 switch { 160 case c.typ.cat == chanT, c.typ.cat == chanRecvT: 161 return c.typ 162 case c.typ.cat == valueT && c.typ.rtype.Kind() == reflect.Chan: 163 dir := chanSendRecv 164 switch c.typ.rtype.ChanDir() { 165 case reflect.RecvDir: 166 dir = chanRecv 167 case reflect.SendDir: 168 dir = chanSend 169 } 170 return chanOf(valueTOf(c.typ.rtype.Elem()), dir) 171 } 172 173 return nil 174 } 175 176 // fixType returns the input type, or a valid default type for untyped constant. 177 func (s *scope) fixType(t *itype) *itype { 178 if !t.untyped || t.cat != valueT { 179 return t 180 } 181 switch typ := t.TypeOf(); typ.Kind() { 182 case reflect.Int64: 183 return s.getType("int") 184 case reflect.Uint64: 185 return s.getType("uint") 186 case reflect.Float64: 187 return s.getType("float64") 188 case reflect.Complex128: 189 return s.getType("complex128") 190 } 191 return t 192 } 193 194 func (s *scope) getType(ident string) *itype { 195 var t *itype 196 if sym, _, found := s.lookup(ident); found { 197 if sym.kind == typeSym { 198 t = sym.typ 199 } 200 } 201 return t 202 } 203 204 // add adds a type to the scope types array, and returns its index. 205 func (s *scope) add(typ *itype) (index int) { 206 if typ == nil { 207 log.Panic("nil type") 208 } 209 index = len(s.types) 210 t := typ.frameType() 211 if t == nil { 212 log.Panic("nil reflect type") 213 } 214 s.types = append(s.types, t) 215 return 216 } 217 218 func (interp *Interpreter) initScopePkg(pkgID, pkgName string) *scope { 219 sc := interp.universe 220 221 interp.mutex.Lock() 222 if _, ok := interp.scopes[pkgID]; !ok { 223 interp.scopes[pkgID] = sc.pushBloc() 224 } 225 sc = interp.scopes[pkgID] 226 sc.pkgID = pkgID 227 sc.pkgName = pkgName 228 interp.mutex.Unlock() 229 return sc 230 } 231 232 // Globals returns a map of global variables and constants in the main package. 233 func (interp *Interpreter) Globals() map[string]reflect.Value { 234 syms := map[string]reflect.Value{} 235 interp.mutex.RLock() 236 defer interp.mutex.RUnlock() 237 238 v, ok := interp.srcPkg["main"] 239 if !ok { 240 return syms 241 } 242 243 for n, s := range v { 244 switch s.kind { 245 case constSym: 246 syms[n] = s.rval 247 case varSym: 248 syms[n] = interp.frame.data[s.index] 249 } 250 } 251 252 return syms 253 }