github.com/mattn/anko@v0.1.10/env/envValues.go (about)

     1  package env
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"strings"
     7  )
     8  
     9  // define
    10  
    11  // Define defines/sets interface value to symbol in current scope.
    12  func (e *Env) Define(symbol string, value interface{}) error {
    13  	if value == nil {
    14  		return e.DefineValue(symbol, NilValue)
    15  	}
    16  	return e.DefineValue(symbol, reflect.ValueOf(value))
    17  }
    18  
    19  // DefineValue defines/sets reflect value to symbol in current scope.
    20  func (e *Env) DefineValue(symbol string, value reflect.Value) error {
    21  	if strings.Contains(symbol, ".") {
    22  		return ErrSymbolContainsDot
    23  	}
    24  	e.rwMutex.Lock()
    25  	e.values[symbol] = value
    26  	e.rwMutex.Unlock()
    27  
    28  	return nil
    29  }
    30  
    31  // DefineGlobal defines/sets interface value to symbol in global scope.
    32  func (e *Env) DefineGlobal(symbol string, value interface{}) error {
    33  	for e.parent != nil {
    34  		e = e.parent
    35  	}
    36  	return e.Define(symbol, value)
    37  }
    38  
    39  // DefineGlobalValue defines/sets reflect value to symbol in global scope.
    40  func (e *Env) DefineGlobalValue(symbol string, value reflect.Value) error {
    41  	for e.parent != nil {
    42  		e = e.parent
    43  	}
    44  	return e.DefineValue(symbol, value)
    45  }
    46  
    47  // set
    48  
    49  // Set interface value to the scope where symbol is frist found.
    50  func (e *Env) Set(symbol string, value interface{}) error {
    51  	if value == nil {
    52  		return e.SetValue(symbol, NilValue)
    53  	}
    54  	return e.SetValue(symbol, reflect.ValueOf(value))
    55  }
    56  
    57  // SetValue reflect value to the scope where symbol is frist found.
    58  func (e *Env) SetValue(symbol string, value reflect.Value) error {
    59  	e.rwMutex.RLock()
    60  	_, ok := e.values[symbol]
    61  	e.rwMutex.RUnlock()
    62  	if ok {
    63  		e.rwMutex.Lock()
    64  		e.values[symbol] = value
    65  		e.rwMutex.Unlock()
    66  		return nil
    67  	}
    68  
    69  	if e.parent == nil {
    70  		return fmt.Errorf("undefined symbol '%s'", symbol)
    71  	}
    72  	return e.parent.SetValue(symbol, value)
    73  }
    74  
    75  // get
    76  
    77  // Get returns interface value from the scope where symbol is frist found.
    78  func (e *Env) Get(symbol string) (interface{}, error) {
    79  	rv, err := e.GetValue(symbol)
    80  	return rv.Interface(), err
    81  }
    82  
    83  // GetValue returns reflect value from the scope where symbol is frist found.
    84  func (e *Env) GetValue(symbol string) (reflect.Value, error) {
    85  	e.rwMutex.RLock()
    86  	value, ok := e.values[symbol]
    87  	e.rwMutex.RUnlock()
    88  	if ok {
    89  		return value, nil
    90  	}
    91  
    92  	if e.externalLookup != nil {
    93  		var err error
    94  		value, err = e.externalLookup.Get(symbol)
    95  		if err == nil {
    96  			return value, nil
    97  		}
    98  	}
    99  
   100  	if e.parent == nil {
   101  		return NilValue, fmt.Errorf("undefined symbol '%s'", symbol)
   102  	}
   103  
   104  	return e.parent.GetValue(symbol)
   105  }
   106  
   107  // GetValueSymbols returns all value symbol in the current scope.
   108  func (e *Env) GetValueSymbols() []string {
   109  	symbols := make([]string, 0, len(e.values))
   110  	e.rwMutex.RLock()
   111  	for symbol := range e.values {
   112  		symbols = append(symbols, symbol)
   113  	}
   114  	e.rwMutex.RUnlock()
   115  	return symbols
   116  }
   117  
   118  // delete
   119  
   120  // Delete deletes symbol in current scope.
   121  func (e *Env) Delete(symbol string) {
   122  	e.rwMutex.Lock()
   123  	delete(e.values, symbol)
   124  	e.rwMutex.Unlock()
   125  }
   126  
   127  // DeleteGlobal deletes the first matching symbol found in current or parent scope.
   128  func (e *Env) DeleteGlobal(symbol string) {
   129  	if e.parent == nil {
   130  		e.Delete(symbol)
   131  		return
   132  	}
   133  
   134  	e.rwMutex.RLock()
   135  	_, ok := e.values[symbol]
   136  	e.rwMutex.RUnlock()
   137  
   138  	if ok {
   139  		e.Delete(symbol)
   140  		return
   141  	}
   142  
   143  	e.parent.DeleteGlobal(symbol)
   144  }
   145  
   146  // Addr
   147  
   148  // Addr returns reflect.Addr of value for first matching symbol found in current or parent scope.
   149  func (e *Env) Addr(symbol string) (reflect.Value, error) {
   150  	e.rwMutex.RLock()
   151  	defer e.rwMutex.RUnlock()
   152  
   153  	if v, ok := e.values[symbol]; ok {
   154  		if v.CanAddr() {
   155  			return v.Addr(), nil
   156  		}
   157  		return NilValue, fmt.Errorf("unaddressable")
   158  	}
   159  	if e.externalLookup != nil {
   160  		v, err := e.externalLookup.Get(symbol)
   161  		if err == nil {
   162  			if v.CanAddr() {
   163  				return v.Addr(), nil
   164  			}
   165  			return NilValue, fmt.Errorf("unaddressable")
   166  		}
   167  	}
   168  	if e.parent == nil {
   169  		return NilValue, fmt.Errorf("undefined symbol '%s'", symbol)
   170  	}
   171  	return e.parent.Addr(symbol)
   172  }