forked from u-root/u-root
-
Notifications
You must be signed in to change notification settings - Fork 0
/
binding_map.go
103 lines (86 loc) · 2.57 KB
/
binding_map.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package eddefs
import (
"errors"
"sort"
"github.com/u-root/u-root/cmds/elvish/edit/ui"
"github.com/u-root/u-root/cmds/elvish/eval"
"github.com/u-root/u-root/cmds/elvish/eval/vals"
"github.com/u-root/u-root/cmds/elvish/parse"
"github.com/u-root/u-root/cmds/elvish/hashmap"
)
var errValueShouldBeFn = errors.New("value should be function")
// BindingMap is a special Map that converts its key to ui.Key and ensures
// that its values satisfy eval.CallableValue.
type BindingMap struct {
hashmap.Map
}
var EmptyBindingMap = BindingMap{vals.EmptyMap}
// Repr returns the representation of the binding table as if it were an
// ordinary map keyed by strings.
func (bt BindingMap) Repr(indent int) string {
var builder vals.MapReprBuilder
builder.Indent = indent
var keys ui.Keys
for it := bt.Map.Iterator(); it.HasElem(); it.Next() {
k, _ := it.Elem()
keys = append(keys, k.(ui.Key))
}
sort.Sort(keys)
for _, k := range keys {
v, _ := bt.Map.Index(k)
builder.WritePair(parse.Quote(k.String()), indent+2, vals.Repr(v, indent+2))
}
return builder.String()
}
// Index converts the index to ui.Key and uses the Index of the inner Map.
func (bt BindingMap) Index(index interface{}) (interface{}, error) {
return vals.Index(bt.Map, ui.ToKey(index))
}
func (bt BindingMap) HasKey(k interface{}) bool {
_, ok := bt.Map.Index(k)
return ok
}
func (bt BindingMap) GetKey(k ui.Key) eval.Callable {
v, ok := bt.Map.Index(k)
if !ok {
panic("get called when key not present")
}
return v.(eval.Callable)
}
func (bt BindingMap) GetOrDefault(k ui.Key) eval.Callable {
switch {
case bt.HasKey(k):
return bt.GetKey(k)
case bt.HasKey(ui.Default):
return bt.GetKey(ui.Default)
}
return nil
}
// Assoc converts the index to ui.Key, ensures that the value is CallableValue,
// uses the Assoc of the inner Map and converts the result to a BindingTable.
func (bt BindingMap) Assoc(k, v interface{}) (interface{}, error) {
key := ui.ToKey(k)
f, ok := v.(eval.Callable)
if !ok {
return nil, errValueShouldBeFn
}
map2 := bt.Map.Assoc(key, f)
return BindingMap{map2}, nil
}
// Dissoc converts the key to ui.Key and calls the Dissoc method of the inner
// map.
func (bt BindingMap) Dissoc(k interface{}) interface{} {
return BindingMap{bt.Map.Dissoc(ui.ToKey(k))}
}
func MakeBindingMap(raw hashmap.Map) (BindingMap, error) {
converted := vals.EmptyMap
for it := raw.Iterator(); it.HasElem(); it.Next() {
k, v := it.Elem()
f, ok := v.(eval.Callable)
if !ok {
return EmptyBindingMap, errValueShouldBeFn
}
converted = converted.Assoc(ui.ToKey(k), f)
}
return BindingMap{converted}, nil
}