github.com/mem/u-root@v2.0.1-0.20181004165302-9b18b4636a33+incompatible/cmds/elvish/eval/builtin_fn_container.go (about) 1 package eval 2 3 import ( 4 "errors" 5 "fmt" 6 "io" 7 8 "github.com/u-root/u-root/cmds/elvish/eval/vals" 9 "github.com/u-root/u-root/cmds/elvish/eval/vars" 10 "github.com/xiaq/persistent/hashmap" 11 ) 12 13 // Sequence, list and maps. 14 15 func init() { 16 addBuiltinFns(map[string]interface{}{ 17 "ns": nsFn, 18 19 "range": rangeFn, 20 "repeat": repeat, 21 "explode": explode, 22 23 "assoc": assoc, 24 "dissoc": dissoc, 25 26 "all": all, 27 28 "has-key": hasKey, 29 "has-value": hasValue, 30 31 "take": take, 32 "drop": drop, 33 "count": count, 34 35 "keys": keys, 36 }) 37 } 38 39 var errKeyMustBeString = errors.New("key must be string") 40 41 func nsFn(m hashmap.Map) (Ns, error) { 42 ns := make(Ns) 43 for it := m.Iterator(); it.HasElem(); it.Next() { 44 k, v := it.Elem() 45 kstring, ok := k.(string) 46 if !ok { 47 return nil, errKeyMustBeString 48 } 49 ns[kstring] = vars.NewAnyWithInit(v) 50 } 51 return ns, nil 52 } 53 54 func rangeFn(fm *Frame, rawOpts RawOptions, args ...float64) error { 55 opts := struct{ Step float64 }{1} 56 rawOpts.Scan(&opts) 57 58 var lower, upper float64 59 60 switch len(args) { 61 case 1: 62 upper = args[0] 63 case 2: 64 lower, upper = args[0], args[1] 65 default: 66 return ErrArgs 67 } 68 69 out := fm.ports[1].Chan 70 for f := lower; f < upper; f += opts.Step { 71 out <- vals.FromGo(f) 72 } 73 return nil 74 } 75 76 func repeat(fm *Frame, n int, v interface{}) { 77 out := fm.OutputChan() 78 for i := 0; i < n; i++ { 79 out <- v 80 } 81 } 82 83 // explode puts each element of the argument. 84 func explode(fm *Frame, v interface{}) error { 85 out := fm.ports[1].Chan 86 return vals.Iterate(v, func(e interface{}) bool { 87 out <- e 88 return true 89 }) 90 } 91 92 func assoc(a, k, v interface{}) (interface{}, error) { 93 return vals.Assoc(a, k, v) 94 } 95 96 var errCannotDissoc = errors.New("cannot dissoc") 97 98 func dissoc(a, k interface{}) (interface{}, error) { 99 a2 := vals.Dissoc(a, k) 100 if a2 == nil { 101 return nil, errCannotDissoc 102 } 103 return a2, nil 104 } 105 106 func all(fm *Frame) error { 107 valuesDone := make(chan struct{}) 108 go func() { 109 for input := range fm.ports[0].Chan { 110 fm.ports[1].Chan <- input 111 } 112 close(valuesDone) 113 }() 114 _, err := io.Copy(fm.ports[1].File, fm.ports[0].File) 115 <-valuesDone 116 if err != nil { 117 return fmt.Errorf("cannot copy byte input: %s", err) 118 } 119 return nil 120 } 121 122 func take(fm *Frame, n int, inputs Inputs) { 123 out := fm.ports[1].Chan 124 i := 0 125 inputs(func(v interface{}) { 126 if i < n { 127 out <- v 128 } 129 i++ 130 }) 131 } 132 133 func drop(fm *Frame, n int, inputs Inputs) { 134 out := fm.ports[1].Chan 135 i := 0 136 inputs(func(v interface{}) { 137 if i >= n { 138 out <- v 139 } 140 i++ 141 }) 142 } 143 144 func hasValue(container, value interface{}) (bool, error) { 145 switch container := container.(type) { 146 case hashmap.Map: 147 for it := container.Iterator(); it.HasElem(); it.Next() { 148 _, v := it.Elem() 149 if vals.Equal(v, value) { 150 return true, nil 151 } 152 } 153 return false, nil 154 default: 155 var found bool 156 err := vals.Iterate(container, func(v interface{}) bool { 157 found = (v == value) 158 return !found 159 }) 160 return found, err 161 } 162 } 163 164 func hasKey(container, key interface{}) (bool, error) { 165 switch container := container.(type) { 166 case hashmap.Map: 167 return hashmap.HasKey(container, key), nil 168 default: 169 if len := vals.Len(container); len >= 0 { 170 // XXX(xiaq): Not all types that implement Lener have numerical indices 171 _, err := vals.ConvertListIndex(key, len) 172 return err == nil, nil 173 } else { 174 var found bool 175 err := vals.IterateKeys(container, func(k interface{}) bool { 176 if key == k { 177 found = true 178 } 179 return !found 180 }) 181 if err == nil { 182 return found, nil 183 } 184 } 185 return false, fmt.Errorf("couldn't get key or index of type '%s'", vals.Kind(container)) 186 } 187 } 188 189 func count(fm *Frame, args ...interface{}) (int, error) { 190 var n int 191 switch len(args) { 192 case 0: 193 // Count inputs. 194 fm.IterateInputs(func(interface{}) { 195 n++ 196 }) 197 case 1: 198 // Get length of argument. 199 v := args[0] 200 if len := vals.Len(v); len >= 0 { 201 n = len 202 } else { 203 err := vals.Iterate(v, func(interface{}) bool { 204 n++ 205 return true 206 }) 207 if err != nil { 208 return 0, fmt.Errorf("cannot get length of a %s", vals.Kind(v)) 209 } 210 } 211 default: 212 return 0, errors.New("want 0 or 1 argument") 213 } 214 return n, nil 215 } 216 217 func keys(fm *Frame, v interface{}) error { 218 out := fm.ports[1].Chan 219 return vals.IterateKeys(v, func(k interface{}) bool { 220 out <- k 221 return true 222 }) 223 }