123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- package env
- import (
- "bytes"
- "errors"
- "fmt"
- "reflect"
- "sync"
- )
- type (
- // ExternalLookup for Env external lookup of values and types.
- ExternalLookup interface {
- Get(string) (reflect.Value, error)
- Type(string) (reflect.Type, error)
- }
- // Env is the environment needed for a VM to run in.
- Env struct {
- rwMutex *sync.RWMutex
- parent *Env
- values map[string]reflect.Value
- types map[string]reflect.Type
- externalLookup ExternalLookup
- }
- )
- var (
- // Packages is a where packages can be stored so VM import command can be used to import them.
- // reflect.Value must be valid or VM may crash.
- // For nil must use NilValue.
- Packages = make(map[string]map[string]reflect.Value)
- // PackageTypes is a where package types can be stored so VM import command can be used to import them
- // reflect.Type must be valid or VM may crash.
- // For nil type must use NilType.
- PackageTypes = make(map[string]map[string]reflect.Type)
- // NilType is the reflect.type of nil
- NilType = reflect.TypeOf(nil)
- // NilValue is the reflect.value of nil
- NilValue = reflect.New(reflect.TypeOf((*interface{})(nil)).Elem()).Elem()
- basicTypes = map[string]reflect.Type{
- "interface": reflect.ValueOf([]interface{}{int64(1)}).Index(0).Type(),
- "bool": reflect.TypeOf(true),
- "string": reflect.TypeOf("a"),
- "int": reflect.TypeOf(int(1)),
- "int32": reflect.TypeOf(int32(1)),
- "int64": reflect.TypeOf(int64(1)),
- "uint": reflect.TypeOf(uint(1)),
- "uint32": reflect.TypeOf(uint32(1)),
- "uint64": reflect.TypeOf(uint64(1)),
- "byte": reflect.TypeOf(byte(1)),
- "rune": reflect.TypeOf('a'),
- "float32": reflect.TypeOf(float32(1)),
- "float64": reflect.TypeOf(float64(1)),
- }
- // ErrSymbolContainsDot symbol contains .
- ErrSymbolContainsDot = errors.New("symbol contains '.'")
- )
- // NewEnv creates new global scope.
- func NewEnv() *Env {
- return &Env{
- rwMutex: &sync.RWMutex{},
- values: make(map[string]reflect.Value),
- }
- }
- // NewEnv creates new child scope.
- func (e *Env) NewEnv() *Env {
- return &Env{
- rwMutex: &sync.RWMutex{},
- parent: e,
- values: make(map[string]reflect.Value),
- }
- }
- // NewModule creates new child scope and define it as a symbol.
- // This is a shortcut for calling e.NewEnv then Define that new Env.
- func (e *Env) NewModule(symbol string) (*Env, error) {
- module := &Env{
- rwMutex: &sync.RWMutex{},
- parent: e,
- values: make(map[string]reflect.Value),
- }
- return module, e.Define(symbol, module)
- }
- // SetExternalLookup sets an external lookup
- func (e *Env) SetExternalLookup(externalLookup ExternalLookup) {
- e.externalLookup = externalLookup
- }
- // String returns string of values and types in current scope.
- func (e *Env) String() string {
- var buffer bytes.Buffer
- e.rwMutex.RLock()
- if e.parent == nil {
- buffer.WriteString("No parent\n")
- } else {
- buffer.WriteString("Has parent\n")
- }
- for symbol, value := range e.values {
- buffer.WriteString(fmt.Sprintf("%v = %#v\n", symbol, value))
- }
- for symbol, aType := range e.types {
- buffer.WriteString(fmt.Sprintf("%v = %v\n", symbol, aType))
- }
- e.rwMutex.RUnlock()
- return buffer.String()
- }
- // GetEnvFromPath returns Env from path
- func (e *Env) GetEnvFromPath(path []string) (*Env, error) {
- if len(path) < 1 {
- return e, nil
- }
- var value reflect.Value
- var ok bool
- for {
- // find starting env
- value, ok = e.values[path[0]]
- if ok {
- e, ok = value.Interface().(*Env)
- if ok {
- break
- }
- }
- if e.parent == nil {
- return nil, fmt.Errorf("no namespace called: %v", path[0])
- }
- e = e.parent
- }
- for i := 1; i < len(path); i++ {
- // find child env
- value, ok = e.values[path[i]]
- if ok {
- e, ok = value.Interface().(*Env)
- if ok {
- continue
- }
- }
- return nil, fmt.Errorf("no namespace called: %v", path[i])
- }
- return e, nil
- }
- // Copy the Env for current scope
- func (e *Env) Copy() *Env {
- e.rwMutex.RLock()
- copy := Env{
- rwMutex: &sync.RWMutex{},
- parent: e.parent,
- values: make(map[string]reflect.Value, len(e.values)),
- externalLookup: e.externalLookup,
- }
- for name, value := range e.values {
- copy.values[name] = value
- }
- if e.types != nil {
- copy.types = make(map[string]reflect.Type, len(e.types))
- for name, t := range e.types {
- copy.types[name] = t
- }
- }
- e.rwMutex.RUnlock()
- return ©
- }
- // DeepCopy the Env for current scope and parent scopes.
- // Note that each scope is a consistent snapshot but not the whole.
- func (e *Env) DeepCopy() *Env {
- e = e.Copy()
- if e.parent != nil {
- e.parent = e.parent.DeepCopy()
- }
- return e
- }
|