github.com/mattn/anko@v0.1.10/env/env.go (about) 1 package env 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "reflect" 8 "sync" 9 ) 10 11 type ( 12 // ExternalLookup for Env external lookup of values and types. 13 ExternalLookup interface { 14 Get(string) (reflect.Value, error) 15 Type(string) (reflect.Type, error) 16 } 17 18 // Env is the environment needed for a VM to run in. 19 Env struct { 20 rwMutex *sync.RWMutex 21 parent *Env 22 values map[string]reflect.Value 23 types map[string]reflect.Type 24 externalLookup ExternalLookup 25 } 26 ) 27 28 var ( 29 // Packages is a where packages can be stored so VM import command can be used to import them. 30 // reflect.Value must be valid or VM may crash. 31 // For nil must use NilValue. 32 Packages = make(map[string]map[string]reflect.Value) 33 // PackageTypes is a where package types can be stored so VM import command can be used to import them 34 // reflect.Type must be valid or VM may crash. 35 // For nil type must use NilType. 36 PackageTypes = make(map[string]map[string]reflect.Type) 37 38 // NilType is the reflect.type of nil 39 NilType = reflect.TypeOf(nil) 40 // NilValue is the reflect.value of nil 41 NilValue = reflect.New(reflect.TypeOf((*interface{})(nil)).Elem()).Elem() 42 43 basicTypes = map[string]reflect.Type{ 44 "interface": reflect.ValueOf([]interface{}{int64(1)}).Index(0).Type(), 45 "bool": reflect.TypeOf(true), 46 "string": reflect.TypeOf("a"), 47 "int": reflect.TypeOf(int(1)), 48 "int32": reflect.TypeOf(int32(1)), 49 "int64": reflect.TypeOf(int64(1)), 50 "uint": reflect.TypeOf(uint(1)), 51 "uint32": reflect.TypeOf(uint32(1)), 52 "uint64": reflect.TypeOf(uint64(1)), 53 "byte": reflect.TypeOf(byte(1)), 54 "rune": reflect.TypeOf('a'), 55 "float32": reflect.TypeOf(float32(1)), 56 "float64": reflect.TypeOf(float64(1)), 57 } 58 59 // ErrSymbolContainsDot symbol contains . 60 ErrSymbolContainsDot = errors.New("symbol contains '.'") 61 ) 62 63 // NewEnv creates new global scope. 64 func NewEnv() *Env { 65 return &Env{ 66 rwMutex: &sync.RWMutex{}, 67 values: make(map[string]reflect.Value), 68 } 69 } 70 71 // NewEnv creates new child scope. 72 func (e *Env) NewEnv() *Env { 73 return &Env{ 74 rwMutex: &sync.RWMutex{}, 75 parent: e, 76 values: make(map[string]reflect.Value), 77 } 78 } 79 80 // NewModule creates new child scope and define it as a symbol. 81 // This is a shortcut for calling e.NewEnv then Define that new Env. 82 func (e *Env) NewModule(symbol string) (*Env, error) { 83 module := &Env{ 84 rwMutex: &sync.RWMutex{}, 85 parent: e, 86 values: make(map[string]reflect.Value), 87 } 88 return module, e.Define(symbol, module) 89 } 90 91 // SetExternalLookup sets an external lookup 92 func (e *Env) SetExternalLookup(externalLookup ExternalLookup) { 93 e.externalLookup = externalLookup 94 } 95 96 // String returns string of values and types in current scope. 97 func (e *Env) String() string { 98 var buffer bytes.Buffer 99 e.rwMutex.RLock() 100 101 if e.parent == nil { 102 buffer.WriteString("No parent\n") 103 } else { 104 buffer.WriteString("Has parent\n") 105 } 106 107 for symbol, value := range e.values { 108 buffer.WriteString(fmt.Sprintf("%v = %#v\n", symbol, value)) 109 } 110 111 for symbol, aType := range e.types { 112 buffer.WriteString(fmt.Sprintf("%v = %v\n", symbol, aType)) 113 } 114 115 e.rwMutex.RUnlock() 116 return buffer.String() 117 } 118 119 // GetEnvFromPath returns Env from path 120 func (e *Env) GetEnvFromPath(path []string) (*Env, error) { 121 if len(path) < 1 { 122 return e, nil 123 } 124 125 var value reflect.Value 126 var ok bool 127 for { 128 // find starting env 129 value, ok = e.values[path[0]] 130 if ok { 131 e, ok = value.Interface().(*Env) 132 if ok { 133 break 134 } 135 } 136 if e.parent == nil { 137 return nil, fmt.Errorf("no namespace called: %v", path[0]) 138 } 139 e = e.parent 140 } 141 142 for i := 1; i < len(path); i++ { 143 // find child env 144 value, ok = e.values[path[i]] 145 if ok { 146 e, ok = value.Interface().(*Env) 147 if ok { 148 continue 149 } 150 } 151 return nil, fmt.Errorf("no namespace called: %v", path[i]) 152 } 153 154 return e, nil 155 } 156 157 // Copy the Env for current scope 158 func (e *Env) Copy() *Env { 159 e.rwMutex.RLock() 160 copy := Env{ 161 rwMutex: &sync.RWMutex{}, 162 parent: e.parent, 163 values: make(map[string]reflect.Value, len(e.values)), 164 externalLookup: e.externalLookup, 165 } 166 for name, value := range e.values { 167 copy.values[name] = value 168 } 169 if e.types != nil { 170 copy.types = make(map[string]reflect.Type, len(e.types)) 171 for name, t := range e.types { 172 copy.types[name] = t 173 } 174 } 175 e.rwMutex.RUnlock() 176 return © 177 } 178 179 // DeepCopy the Env for current scope and parent scopes. 180 // Note that each scope is a consistent snapshot but not the whole. 181 func (e *Env) DeepCopy() *Env { 182 e = e.Copy() 183 if e.parent != nil { 184 e.parent = e.parent.DeepCopy() 185 } 186 return e 187 }