1package interp 2 3import ( 4 "log" 5 "reflect" 6 "strconv" 7) 8 9// A sKind represents the kind of symbol. 10type sKind uint 11 12// Symbol kinds for the Go interpreter. 13const ( 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 25var 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 37func (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. 46type 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 nodes jumping to node if kind is label, 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// 74type 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 types []reflect.Type // frame layout, may be shared by same level scopes 82 level int // frame level: number of frame indirections to access var during execution 83 sym map[string]*symbol // map of symbols defined in this current scope 84 global bool // true if scope refers to global space (single frame for universe and package level scopes) 85 iota int // iota value in this scope 86} 87 88// push creates a new child scope and chain it to the current one. 89func (s *scope) push(indirect bool) *scope { 90 sc := &scope{anc: s, level: s.level, sym: map[string]*symbol{}} 91 s.child = append(s.child, sc) 92 if indirect { 93 sc.types = []reflect.Type{} 94 sc.level = s.level + 1 95 } else { 96 // Propagate size, types, def and global as scopes at same level share the same frame. 97 sc.types = s.types 98 sc.def = s.def 99 sc.global = s.global 100 sc.level = s.level 101 } 102 // inherit loop state and pkgID from ancestor 103 sc.loop, sc.loopRestart, sc.pkgID = s.loop, s.loopRestart, s.pkgID 104 return sc 105} 106 107func (s *scope) pushBloc() *scope { return s.push(false) } 108func (s *scope) pushFunc() *scope { return s.push(true) } 109 110func (s *scope) pop() *scope { 111 if s.level == s.anc.level { 112 // Propagate size and types, as scopes at same level share the same frame. 113 s.anc.types = s.types 114 } 115 return s.anc 116} 117 118func (s *scope) upperLevel() *scope { 119 level := s.level 120 for s != nil && s.level == level { 121 s = s.anc 122 } 123 return s 124} 125 126// lookup searches for a symbol in the current scope, and upper ones if not found 127// it returns the symbol, the number of indirections level from the current scope 128// and status (false if no result). 129func (s *scope) lookup(ident string) (*symbol, int, bool) { 130 level := s.level 131 for { 132 if sym, ok := s.sym[ident]; ok { 133 if sym.global { 134 return sym, globalFrame, true 135 } 136 return sym, level - s.level, true 137 } 138 if s.anc == nil { 139 break 140 } 141 s = s.anc 142 } 143 return nil, 0, false 144} 145 146// lookdown searches for a symbol in the current scope and included ones, recursively. 147// It returns the first found symbol and true, or nil and false. 148func (s *scope) lookdown(ident string) (*symbol, bool) { 149 if sym, ok := s.sym[ident]; ok { 150 return sym, true 151 } 152 for _, c := range s.child { 153 if sym, ok := c.lookdown(ident); ok { 154 return sym, true 155 } 156 } 157 return nil, false 158} 159 160func (s *scope) rangeChanType(n *node) *itype { 161 if sym, _, found := s.lookup(n.child[1].ident); found { 162 if t := sym.typ; len(n.child) == 3 && t != nil && (t.cat == chanT || t.cat == chanRecvT) { 163 return t 164 } 165 } 166 167 c := n.child[1] 168 if c.typ == nil { 169 return nil 170 } 171 switch { 172 case c.typ.cat == chanT, c.typ.cat == chanRecvT: 173 return c.typ 174 case c.typ.cat == valueT && c.typ.rtype.Kind() == reflect.Chan: 175 return &itype{cat: chanT, val: &itype{cat: valueT, rtype: c.typ.rtype.Elem()}} 176 } 177 178 return nil 179} 180 181// fixType returns the input type, or a valid default type for untyped constant. 182func (s *scope) fixType(t *itype) *itype { 183 if !t.untyped || t.cat != valueT { 184 return t 185 } 186 switch typ := t.TypeOf(); typ.Kind() { 187 case reflect.Int64: 188 return s.getType("int") 189 case reflect.Uint64: 190 return s.getType("uint") 191 case reflect.Float64: 192 return s.getType("float64") 193 case reflect.Complex128: 194 return s.getType("complex128") 195 } 196 return t 197} 198 199func (s *scope) getType(ident string) *itype { 200 var t *itype 201 if sym, _, found := s.lookup(ident); found { 202 if sym.kind == typeSym { 203 t = sym.typ 204 } 205 } 206 return t 207} 208 209// add adds a type to the scope types array, and returns its index. 210func (s *scope) add(typ *itype) (index int) { 211 if typ == nil { 212 log.Panic("nil type") 213 } 214 index = len(s.types) 215 t := typ.frameType() 216 if t == nil { 217 log.Panic("nil reflect type") 218 } 219 s.types = append(s.types, t) 220 return 221} 222 223func (interp *Interpreter) initScopePkg(pkgID string) *scope { 224 sc := interp.universe 225 226 interp.mutex.Lock() 227 if _, ok := interp.scopes[pkgID]; !ok { 228 interp.scopes[pkgID] = sc.pushBloc() 229 } 230 sc = interp.scopes[pkgID] 231 sc.pkgID = pkgID 232 interp.mutex.Unlock() 233 return sc 234} 235