elvish/eval/builtin_fn_container.go

214 lines
3.9 KiB
Go
Raw Normal View History

2017-12-17 13:20:03 +08:00
package eval
import (
"errors"
"fmt"
"io"
2018-02-15 17:14:05 +08:00
"github.com/elves/elvish/eval/vals"
2018-02-15 16:59:49 +08:00
"github.com/elves/elvish/eval/vars"
"github.com/xiaq/persistent/hashmap"
2017-12-17 13:20:03 +08:00
)
// Sequence, list and maps.
func init() {
2018-02-07 03:39:40 +08:00
addBuiltinFns(map[string]interface{}{
"ns": nsFn,
2017-12-17 13:20:03 +08:00
"range": rangeFn,
"repeat": repeat,
"explode": explode,
2017-12-17 13:20:03 +08:00
"assoc": assoc,
"dissoc": dissoc,
2017-12-17 13:20:03 +08:00
"all": all,
2017-12-17 13:20:03 +08:00
"has-key": hasKey,
"has-value": hasValue,
2017-12-17 13:20:03 +08:00
2018-02-05 15:35:49 +08:00
"take": take,
"drop": drop,
"count": count,
"keys": keys,
2017-12-17 13:20:03 +08:00
})
}
var errKeyMustBeString = errors.New("key must be string")
func nsFn(m hashmap.Map) (Ns, error) {
ns := make(Ns)
for it := m.Iterator(); it.HasElem(); it.Next() {
k, v := it.Elem()
kstring, ok := k.(string)
if !ok {
return nil, errKeyMustBeString
}
2018-02-15 16:59:49 +08:00
ns[kstring] = vars.NewAnyWithInit(v)
}
return ns, nil
}
func rangeFn(fm *Frame, rawOpts RawOptions, args ...float64) error {
opts := struct{ Step float64 }{1}
rawOpts.Scan(&opts)
2017-12-17 13:20:03 +08:00
var lower, upper float64
switch len(args) {
case 1:
upper = args[0]
2017-12-17 13:20:03 +08:00
case 2:
lower, upper = args[0], args[1]
2017-12-17 13:20:03 +08:00
default:
return ErrArgs
2017-12-17 13:20:03 +08:00
}
out := fm.ports[1].Chan
for f := lower; f < upper; f += opts.Step {
2018-02-15 17:14:05 +08:00
out <- vals.FromGo(f)
2017-12-17 13:20:03 +08:00
}
return nil
2017-12-17 13:20:03 +08:00
}
func repeat(fm *Frame, n int, v interface{}) {
out := fm.OutputChan()
2017-12-17 13:20:03 +08:00
for i := 0; i < n; i++ {
out <- v
}
}
// explode puts each element of the argument.
func explode(fm *Frame, v interface{}) error {
out := fm.ports[1].Chan
return vals.Iterate(v, func(e interface{}) bool {
2017-12-17 13:20:03 +08:00
out <- e
return true
})
}
func assoc(a, k, v interface{}) (interface{}, error) {
2018-02-15 17:14:05 +08:00
return vals.Assoc(a, k, v)
2017-12-17 13:20:03 +08:00
}
var errCannotDissoc = errors.New("cannot dissoc")
func dissoc(a, k interface{}) (interface{}, error) {
2018-02-15 17:14:05 +08:00
a2 := vals.Dissoc(a, k)
if a2 == nil {
return nil, errCannotDissoc
}
return a2, nil
2017-12-17 13:20:03 +08:00
}
func all(fm *Frame) error {
2017-12-17 13:20:03 +08:00
valuesDone := make(chan struct{})
go func() {
for input := range fm.ports[0].Chan {
fm.ports[1].Chan <- input
2017-12-17 13:20:03 +08:00
}
close(valuesDone)
}()
_, err := io.Copy(fm.ports[1].File, fm.ports[0].File)
2017-12-17 13:20:03 +08:00
<-valuesDone
if err != nil {
return fmt.Errorf("cannot copy byte input: %s", err)
2017-12-17 13:20:03 +08:00
}
return nil
2017-12-17 13:20:03 +08:00
}
2018-02-05 15:35:49 +08:00
func take(fm *Frame, n int, inputs Inputs) {
out := fm.ports[1].Chan
2017-12-17 13:20:03 +08:00
i := 0
2018-02-05 15:35:49 +08:00
inputs(func(v interface{}) {
2017-12-17 13:20:03 +08:00
if i < n {
out <- v
}
i++
})
}
2018-02-05 15:35:49 +08:00
func drop(fm *Frame, n int, inputs Inputs) {
out := fm.ports[1].Chan
2017-12-17 13:20:03 +08:00
i := 0
2018-02-05 15:35:49 +08:00
inputs(func(v interface{}) {
2017-12-17 13:20:03 +08:00
if i >= n {
out <- v
}
i++
})
}
func hasValue(container, value interface{}) (bool, error) {
2017-12-17 13:20:03 +08:00
switch container := container.(type) {
case hashmap.Map:
for it := container.Iterator(); it.HasElem(); it.Next() {
_, v := it.Elem()
2018-02-15 17:14:05 +08:00
if vals.Equal(v, value) {
return true, nil
}
}
return false, nil
2017-12-17 13:20:03 +08:00
default:
var found bool
2018-02-15 17:14:05 +08:00
err := vals.Iterate(container, func(v interface{}) bool {
found = (v == value)
return !found
})
return found, err
2017-12-17 13:20:03 +08:00
}
}
func hasKey(container, key interface{}) (bool, error) {
2017-12-17 13:20:03 +08:00
switch container := container.(type) {
case hashmap.Map:
return hashmap.HasKey(container, key), nil
2017-12-17 13:20:03 +08:00
default:
2018-02-15 17:14:05 +08:00
if len := vals.Len(container); len >= 0 {
// XXX(xiaq): Not all types that implement Lener have numerical indices
2018-02-15 17:14:05 +08:00
_, err := vals.ConvertListIndex(key, len)
return err == nil, nil
}
2018-02-15 17:14:05 +08:00
return false, fmt.Errorf("couldn't get key or index of type '%s'", vals.Kind(container))
2017-12-17 13:20:03 +08:00
}
}
func count(fm *Frame, args ...interface{}) (int, error) {
2017-12-17 13:20:03 +08:00
var n int
switch len(args) {
case 0:
// Count inputs.
2018-02-05 15:35:49 +08:00
fm.IterateInputs(func(interface{}) {
2017-12-17 13:20:03 +08:00
n++
})
case 1:
// Get length of argument.
v := args[0]
2018-02-15 17:14:05 +08:00
if len := vals.Len(v); len >= 0 {
n = len
} else {
2018-02-15 17:14:05 +08:00
err := vals.Iterate(v, func(interface{}) bool {
2017-12-17 13:20:03 +08:00
n++
return true
})
if err != nil {
return 0, fmt.Errorf("cannot get length of a %s", vals.Kind(v))
}
2017-12-17 13:20:03 +08:00
}
default:
return 0, errors.New("want 0 or 1 argument")
2017-12-17 13:20:03 +08:00
}
return n, nil
2017-12-17 13:20:03 +08:00
}
func keys(fm *Frame, m hashmap.Map) {
out := fm.ports[1].Chan
2017-12-17 13:20:03 +08:00
for it := m.Iterator(); it.HasElem(); it.Next() {
k, _ := it.Elem()
out <- k
}
2017-12-17 13:20:03 +08:00
}