github.com/kolbycrouch/elvish@v0.14.1-0.20210614162631-215b9ac1c423/pkg/edit/binding_map.go (about) 1 package edit 2 3 import ( 4 "errors" 5 "sort" 6 7 "src.elv.sh/pkg/eval" 8 "src.elv.sh/pkg/eval/vals" 9 "src.elv.sh/pkg/parse" 10 "src.elv.sh/pkg/persistent/hashmap" 11 "src.elv.sh/pkg/ui" 12 ) 13 14 var errValueShouldBeFn = errors.New("value should be function") 15 16 // A special Map that converts its key to ui.Key and ensures that its values 17 // satisfy eval.CallableValue. 18 type bindingsMap struct { 19 hashmap.Map 20 } 21 22 var emptyBindingsMap = bindingsMap{vals.EmptyMap} 23 24 // Repr returns the representation of the binding table as if it were an 25 // ordinary map keyed by strings. 26 func (bt bindingsMap) Repr(indent int) string { 27 var keys ui.Keys 28 for it := bt.Map.Iterator(); it.HasElem(); it.Next() { 29 k, _ := it.Elem() 30 keys = append(keys, k.(ui.Key)) 31 } 32 sort.Sort(keys) 33 34 builder := vals.NewMapReprBuilder(indent) 35 36 for _, k := range keys { 37 v, _ := bt.Map.Index(k) 38 builder.WritePair(parse.Quote(k.String()), indent+2, vals.Repr(v, indent+2)) 39 } 40 41 return builder.String() 42 } 43 44 // Index converts the index to ui.Key and uses the Index of the inner Map. 45 func (bt bindingsMap) Index(index interface{}) (interface{}, error) { 46 key, err := toKey(index) 47 if err != nil { 48 return nil, err 49 } 50 return vals.Index(bt.Map, key) 51 } 52 53 func (bt bindingsMap) HasKey(k interface{}) bool { 54 _, ok := bt.Map.Index(k) 55 return ok 56 } 57 58 func (bt bindingsMap) GetKey(k ui.Key) eval.Callable { 59 v, ok := bt.Map.Index(k) 60 if !ok { 61 panic("get called when key not present") 62 } 63 return v.(eval.Callable) 64 } 65 66 // Assoc converts the index to ui.Key, ensures that the value is CallableValue, 67 // uses the Assoc of the inner Map and converts the result to a BindingTable. 68 func (bt bindingsMap) Assoc(k, v interface{}) (interface{}, error) { 69 key, err := toKey(k) 70 if err != nil { 71 return nil, err 72 } 73 f, ok := v.(eval.Callable) 74 if !ok { 75 return nil, errValueShouldBeFn 76 } 77 map2 := bt.Map.Assoc(key, f) 78 return bindingsMap{map2}, nil 79 } 80 81 // Dissoc converts the key to ui.Key and calls the Dissoc method of the inner 82 // map. 83 func (bt bindingsMap) Dissoc(k interface{}) interface{} { 84 key, err := toKey(k) 85 if err != nil { 86 // Key is invalid; dissoc is no-op. 87 return bt 88 } 89 return bindingsMap{bt.Map.Dissoc(key)} 90 } 91 92 func makeBindingMap(raw hashmap.Map) (bindingsMap, error) { 93 converted := vals.EmptyMap 94 for it := raw.Iterator(); it.HasElem(); it.Next() { 95 k, v := it.Elem() 96 f, ok := v.(eval.Callable) 97 if !ok { 98 return emptyBindingsMap, errValueShouldBeFn 99 } 100 key, err := toKey(k) 101 if err != nil { 102 return bindingsMap{}, err 103 } 104 converted = converted.Assoc(key, f) 105 } 106 107 return bindingsMap{converted}, nil 108 }