github.com/masahide/goansible@v0.0.0-20160116054156-01eac649e9f2/lisp/value.go (about)

     1  package lisp
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  )
     7  
     8  type Value struct {
     9  	typ valueType
    10  	val interface{}
    11  }
    12  
    13  type Map interface {
    14  	Get(key string) (Value, bool)
    15  }
    16  
    17  func (v Value) Interface() interface{} {
    18  	return v.val
    19  }
    20  
    21  var Nil = Value{nilValue, nil}
    22  var False = Value{symbolValue, "false"}
    23  var True = Value{symbolValue, "true"}
    24  
    25  type valueType uint8
    26  
    27  const (
    28  	nilValue valueType = iota
    29  	symbolValue
    30  	numberValue
    31  	stringValue
    32  	vectorValue
    33  	procValue
    34  	consValue
    35  	mapValue
    36  )
    37  
    38  func NumberValue(n int64) Value {
    39  	return Value{typ: numberValue, val: n}
    40  }
    41  
    42  func StringValue(s string) Value {
    43  	return Value{typ: stringValue, val: s}
    44  }
    45  
    46  func MapValue(m Map) Value {
    47  	return Value{typ: mapValue, val: m}
    48  }
    49  
    50  func (v Value) Eval(scope ScopedVars) (Value, error) {
    51  	switch v.typ {
    52  	case consValue:
    53  		return v.Cons().Execute(scope)
    54  	case symbolValue:
    55  		sym := v.String()
    56  
    57  		parts := strings.Split(sym, ".")
    58  
    59  		var (
    60  			v  Value
    61  			ok bool
    62  		)
    63  
    64  		if len(parts) == 1 {
    65  			v, ok = scope.Get(sym)
    66  		} else {
    67  			v, ok = scope.Get(parts[0])
    68  
    69  			for _, sub := range parts[1:] {
    70  				if v.typ != mapValue {
    71  					return Nil, fmt.Errorf("Variable '%s' is not a map (%v)", parts[0], v)
    72  				}
    73  
    74  				v, ok = v.Interface().(Map).Get(sub)
    75  			}
    76  		}
    77  
    78  		if ok {
    79  			return v, nil
    80  		} else if sym == "true" || sym == "false" {
    81  			return Value{symbolValue, sym}, nil
    82  		} else {
    83  			return Nil, fmt.Errorf("Unbound variable: %v", sym)
    84  		}
    85  	default:
    86  		return v, nil
    87  	}
    88  }
    89  
    90  func (v Value) String() string {
    91  	switch v.typ {
    92  	case numberValue:
    93  		return fmt.Sprintf("%d", v.val.(int64))
    94  	case nilValue:
    95  		return "()"
    96  	default:
    97  		return fmt.Sprintf("%v", v.val)
    98  	}
    99  }
   100  
   101  func (v Value) Inspect() string {
   102  	switch v.typ {
   103  	case stringValue:
   104  		return fmt.Sprintf(`"%v"`, v.val)
   105  	case vectorValue:
   106  		return v.val.(Vector).Inspect()
   107  	default:
   108  		return v.String()
   109  	}
   110  }
   111  
   112  func (v Value) Cons() Cons {
   113  	if v.typ == consValue {
   114  		return *v.val.(*Cons)
   115  	} else {
   116  		return Cons{&v, &Nil}
   117  	}
   118  }
   119  
   120  func (v Value) Number() int64 {
   121  	return v.val.(int64)
   122  }