src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/eval/builtin_fn_container.go (about) 1 package eval 2 3 import ( 4 "errors" 5 "fmt" 6 7 "src.elv.sh/pkg/eval/errs" 8 "src.elv.sh/pkg/eval/vals" 9 "src.elv.sh/pkg/eval/vars" 10 ) 11 12 // Lists and maps. 13 14 func init() { 15 addBuiltinFns(map[string]any{ 16 "ns": nsFn, 17 18 "make-map": makeMap, 19 20 "conj": conj, 21 "assoc": assoc, 22 "dissoc": dissoc, 23 24 "has-key": hasKey, 25 "has-value": hasValue, 26 27 "keys": keys, 28 }) 29 } 30 31 func nsFn(m vals.Map) (*Ns, error) { 32 nb := BuildNs() 33 for it := m.Iterator(); it.HasElem(); it.Next() { 34 k, v := it.Elem() 35 kstring, ok := k.(string) 36 if !ok { 37 return nil, errs.BadValue{ 38 What: `key of argument of "ns"`, 39 Valid: "string", Actual: vals.Kind(k)} 40 } 41 nb.AddVar(kstring, vars.FromInit(v)) 42 } 43 return nb.Ns(), nil 44 } 45 46 func makeMap(input Inputs) (vals.Map, error) { 47 m := vals.EmptyMap 48 var errMakeMap error 49 input(func(v any) { 50 if errMakeMap != nil { 51 return 52 } 53 if !vals.CanIterate(v) { 54 errMakeMap = errs.BadValue{ 55 What: "input to make-map", Valid: "iterable", Actual: vals.Kind(v)} 56 return 57 } 58 if l := vals.Len(v); l != 2 { 59 errMakeMap = errs.BadValue{ 60 What: "input to make-map", Valid: "iterable with 2 elements", 61 Actual: fmt.Sprintf("%v with %v elements", vals.Kind(v), l)} 62 return 63 } 64 elems, err := vals.Collect(v) 65 if err != nil { 66 errMakeMap = err 67 return 68 } 69 if len(elems) != 2 { 70 errMakeMap = fmt.Errorf("internal bug: collected %v values", len(elems)) 71 return 72 } 73 m = m.Assoc(elems[0], elems[1]) 74 }) 75 return m, errMakeMap 76 } 77 78 func conj(li vals.List, more ...any) vals.List { 79 for _, val := range more { 80 li = li.Conj(val) 81 } 82 return li 83 } 84 85 func assoc(a, k, v any) (any, error) { 86 return vals.Assoc(a, k, v) 87 } 88 89 var errCannotDissoc = errors.New("cannot dissoc") 90 91 func dissoc(a, k any) (any, error) { 92 a2 := vals.Dissoc(a, k) 93 if a2 == nil { 94 return nil, errCannotDissoc 95 } 96 return a2, nil 97 } 98 99 func hasValue(container, value any) (bool, error) { 100 switch container := container.(type) { 101 case vals.Map: 102 for it := container.Iterator(); it.HasElem(); it.Next() { 103 _, v := it.Elem() 104 if vals.Equal(v, value) { 105 return true, nil 106 } 107 } 108 return false, nil 109 default: 110 var found bool 111 err := vals.Iterate(container, func(v any) bool { 112 if vals.Equal(v, value) { 113 found = true 114 return false 115 } 116 return true 117 }) 118 return found, err 119 } 120 } 121 122 func hasKey(container, key any) bool { 123 return vals.HasKey(container, key) 124 } 125 126 func keys(fm *Frame, v any) error { 127 out := fm.ValueOutput() 128 var errPut error 129 errIterate := vals.IterateKeys(v, func(k any) bool { 130 errPut = out.Put(k) 131 return errPut == nil 132 }) 133 if errIterate != nil { 134 return errIterate 135 } 136 return errPut 137 }