package interpimport ()// A sKind represents the kind of symbol.type sKind uint// Symbol kinds for the Go interpreter.const ( undefSym sKind = iota binSym // Binary from runtime bltnSym // Builtin constSym // Constant funcSym // Function labelSym // Label pkgSym // Package typeSym // Type varTypeSym // Variable type (generic) varSym // Variable)var symKinds = [...]string{undefSym: "undefSym",binSym: "binSym",bltnSym: "bltnSym",constSym: "constSym",funcSym: "funcSym",labelSym: "labelSym",pkgSym: "pkgSym",typeSym: "typeSym",varTypeSym: "varTypeSym",varSym: "varSym",}func ( sKind) () string {if < sKind(len(symKinds)) {returnsymKinds[] }return"SymKind(" + strconv.Itoa(int()) + ")"}// A symbol represents an interpreter object such as type, constant, var, func,// label, builtin or binary object. Symbols are defined within a scope.type symbol struct { kind sKind typ *itype// Type of value node *node// Node value if index is negative from []*node// list of goto nodes jumping to this label node, or nil recv *receiver// receiver node value, if sym refers to a method index int// index of value in frame or -1 rval reflect.Value// default value (used for constants) builtin bltnGenerator// Builtin function or nil global bool// true if symbol is defined in global space}// scope type stores symbols in maps, and frame layout as array of types// The purposes of scopes are to manage the visibility of each symbol// and to store the memory frame layout information (type and index in frame)// at each level (global, package, functions)//// scopes are organized in a stack fashion: a first scope (universe) is created// once at global level, and for each block (package, func, for, etc...), a new// scope is pushed at entry, and poped at exit.//// Nested scopes with the same level value use the same frame: it allows to have// exactly one frame per function, with a fixed position for each variable (named// or not), no matter the inner complexity (number of nested blocks in the function)//// In symbols, the index value corresponds to the index in scope.types, and at// execution to the index in frame, created exactly from the types layout.type scope struct { anc *scope// ancestor upper scope child []*scope// included scopes def *node// function definition node this scope belongs to, or nil loop *node// loop exit node for break statement loopRestart *node// loop restart node for continue statement pkgID string// unique id of package in which scope is defined pkgName string// package name for the package types []reflect.Type// frame layout, may be shared by same level scopes level int// frame level: number of frame indirections to access var during execution sym map[string]*symbol// map of symbols defined in this current scope global bool// true if scope refers to global space (single frame for universe and package level scopes) iota int// iota value in this scope}// push creates a new child scope and chain it to the current one.func ( *scope) ( bool) *scope { := &scope{anc: , level: .level, sym: map[string]*symbol{}} .child = append(.child, )if { .types = []reflect.Type{} .level = .level + 1 } else {// Propagate size, types, def and global as scopes at same level share the same frame. .types = .types .def = .def .global = .global .level = .level }// inherit loop state and pkgID from ancestor .loop, .loopRestart, .pkgID = .loop, .loopRestart, .pkgIDreturn}func ( *scope) () *scope { return .push(false) }func ( *scope) () *scope { return .push(true) }func ( *scope) () *scope {if .level == .anc.level {// Propagate size and types, as scopes at same level share the same frame. .anc.types = .types }return .anc}func ( *scope) () *scope { := .levelfor != nil && .level == { = .anc }return}// lookup searches for a symbol in the current scope, and upper ones if not found// it returns the symbol, the number of indirections level from the current scope// and status (false if no result).func ( *scope) ( string) (*symbol, int, bool) { := .levelfor {if , := .sym[]; {if .global {return , globalFrame, true }return , - .level, true }if .anc == nil {break } = .anc }returnnil, 0, false}func ( *scope) ( *node) *itype {if , , := .lookup(.child[1].ident); {if := .typ; len(.child) == 3 && != nil && (.cat == chanT || .cat == chanRecvT) {return } } := .child[1]if .typ == nil {returnnil }switch {case .typ.cat == chanT, .typ.cat == chanRecvT:return .typcase .typ.cat == valueT && .typ.rtype.Kind() == reflect.Chan: := chanSendRecvswitch .typ.rtype.ChanDir() {casereflect.RecvDir: = chanRecvcasereflect.SendDir: = chanSend }returnchanOf(valueTOf(.typ.rtype.Elem()), ) }returnnil}// fixType returns the input type, or a valid default type for untyped constant.func ( *scope) ( *itype) *itype {if !.untyped || .cat != valueT {return }switch := .TypeOf(); .Kind() {casereflect.Int64:return .getType("int")casereflect.Uint64:return .getType("uint")casereflect.Float64:return .getType("float64")casereflect.Complex128:return .getType("complex128") }return}func ( *scope) ( string) *itype {var *itypeif , , := .lookup(); {if .kind == typeSym { = .typ } }return}// add adds a type to the scope types array, and returns its index.func ( *scope) ( *itype) ( int) {if == nil {log.Panic("nil type") } = len(.types) := .frameType()if == nil {log.Panic("nil reflect type") } .types = append(.types, )return}func ( *Interpreter) (, string) *scope { := .universe .mutex.Lock()if , := .scopes[]; ! { .scopes[] = .pushBloc() } = .scopes[] .pkgID = .pkgName = .mutex.Unlock()return}// Globals returns a map of global variables and constants in the main package.func ( *Interpreter) () map[string]reflect.Value { := map[string]reflect.Value{} .mutex.RLock()defer .mutex.RUnlock() , := .srcPkg["main"]if ! {return }for , := range {switch .kind {caseconstSym: [] = .rvalcasevarSym: [] = .frame.data[.index] } }return}
The pages are generated with Goldsv0.8.4. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.