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