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 }