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"
|
2018-01-29 22:36:43 +08:00
|
|
|
"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{}{
|
2018-02-04 13:51:20 +08:00
|
|
|
"ns": nsFn,
|
2017-12-17 13:20:03 +08:00
|
|
|
|
2018-02-04 13:51:20 +08:00
|
|
|
"range": rangeFn,
|
|
|
|
"repeat": repeat,
|
|
|
|
"explode": explode,
|
2017-12-17 13:20:03 +08:00
|
|
|
|
2018-02-04 13:51:20 +08:00
|
|
|
"assoc": assoc,
|
|
|
|
"dissoc": dissoc,
|
2017-12-17 13:20:03 +08:00
|
|
|
|
2018-02-04 13:51:20 +08:00
|
|
|
"all": all,
|
2017-12-17 13:20:03 +08:00
|
|
|
|
2018-02-04 13:51:20 +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,
|
|
|
|
|
2018-02-04 13:51:20 +08:00
|
|
|
"keys": keys,
|
2017-12-17 13:20:03 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-02-03 14:10:10 +08:00
|
|
|
var errKeyMustBeString = errors.New("key must be string")
|
|
|
|
|
2018-03-01 23:13:00 +08:00
|
|
|
func nsFn(m hashmap.Map) (Ns, error) {
|
2018-02-03 14:10:10 +08:00
|
|
|
ns := make(Ns)
|
|
|
|
for it := m.Iterator(); it.HasElem(); it.Next() {
|
|
|
|
k, v := it.Elem()
|
|
|
|
kstring, ok := k.(string)
|
|
|
|
if !ok {
|
2018-03-01 23:13:00 +08:00
|
|
|
return nil, errKeyMustBeString
|
2018-02-03 14:10:10 +08:00
|
|
|
}
|
2018-02-15 16:59:49 +08:00
|
|
|
ns[kstring] = vars.NewAnyWithInit(v)
|
2018-02-03 14:10:10 +08:00
|
|
|
}
|
2018-03-01 23:13:00 +08:00
|
|
|
return ns, nil
|
2017-12-24 07:51:32 +08:00
|
|
|
}
|
|
|
|
|
2018-02-15 21:25:17 +08:00
|
|
|
func rangeFn(fm *Frame, rawOpts RawOptions, args ...float64) error {
|
2018-02-15 20:57:22 +08:00
|
|
|
opts := struct{ Step float64 }{1}
|
2018-02-15 21:25:17 +08:00
|
|
|
rawOpts.Scan(&opts)
|
2017-12-17 13:20:03 +08:00
|
|
|
|
|
|
|
var lower, upper float64
|
|
|
|
|
|
|
|
switch len(args) {
|
|
|
|
case 1:
|
2018-02-04 13:51:20 +08:00
|
|
|
upper = args[0]
|
2017-12-17 13:20:03 +08:00
|
|
|
case 2:
|
2018-02-04 13:51:20 +08:00
|
|
|
lower, upper = args[0], args[1]
|
2017-12-17 13:20:03 +08:00
|
|
|
default:
|
2018-02-04 13:51:20 +08:00
|
|
|
return ErrArgs
|
2017-12-17 13:20:03 +08:00
|
|
|
}
|
|
|
|
|
2018-02-04 13:51:20 +08:00
|
|
|
out := fm.ports[1].Chan
|
2018-02-15 20:57:22 +08:00
|
|
|
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
|
|
|
}
|
2018-02-04 13:51:20 +08:00
|
|
|
return nil
|
2017-12-17 13:20:03 +08:00
|
|
|
}
|
|
|
|
|
2018-03-01 10:17:56 +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.
|
2018-03-01 23:13:00 +08:00
|
|
|
func explode(fm *Frame, v interface{}) error {
|
2018-03-01 10:17:56 +08:00
|
|
|
out := fm.ports[1].Chan
|
2018-03-01 23:13:00 +08:00
|
|
|
return vals.Iterate(v, func(e interface{}) bool {
|
2017-12-17 13:20:03 +08:00
|
|
|
out <- e
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-02-04 13:51:20 +08:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2018-01-29 22:36:43 +08:00
|
|
|
var errCannotDissoc = errors.New("cannot dissoc")
|
|
|
|
|
2018-02-04 13:51:20 +08:00
|
|
|
func dissoc(a, k interface{}) (interface{}, error) {
|
2018-02-15 17:14:05 +08:00
|
|
|
a2 := vals.Dissoc(a, k)
|
2018-01-29 22:36:43 +08:00
|
|
|
if a2 == nil {
|
2018-02-04 13:51:20 +08:00
|
|
|
return nil, errCannotDissoc
|
2018-01-29 22:36:43 +08:00
|
|
|
}
|
2018-02-04 13:51:20 +08:00
|
|
|
return a2, nil
|
2017-12-17 13:20:03 +08:00
|
|
|
}
|
|
|
|
|
2018-03-01 10:17:56 +08:00
|
|
|
func all(fm *Frame) error {
|
2017-12-17 13:20:03 +08:00
|
|
|
valuesDone := make(chan struct{})
|
|
|
|
go func() {
|
2018-03-01 10:17:56 +08:00
|
|
|
for input := range fm.ports[0].Chan {
|
|
|
|
fm.ports[1].Chan <- input
|
2017-12-17 13:20:03 +08:00
|
|
|
}
|
|
|
|
close(valuesDone)
|
|
|
|
}()
|
2018-03-01 10:17:56 +08:00
|
|
|
_, err := io.Copy(fm.ports[1].File, fm.ports[0].File)
|
2017-12-17 13:20:03 +08:00
|
|
|
<-valuesDone
|
|
|
|
if err != nil {
|
2018-02-04 13:51:20 +08:00
|
|
|
return fmt.Errorf("cannot copy byte input: %s", err)
|
2017-12-17 13:20:03 +08:00
|
|
|
}
|
2018-02-04 13:51:20 +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++
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-02-04 13:51:20 +08:00
|
|
|
func hasValue(container, value interface{}) (bool, error) {
|
2017-12-17 13:20:03 +08:00
|
|
|
switch container := container.(type) {
|
2018-01-29 22:36:43 +08:00
|
|
|
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) {
|
2018-02-04 13:51:20 +08:00
|
|
|
return true, nil
|
2018-01-29 22:36:43 +08:00
|
|
|
}
|
|
|
|
}
|
2018-02-04 13:51:20 +08:00
|
|
|
return false, nil
|
2017-12-17 13:20:03 +08:00
|
|
|
default:
|
2018-02-04 13:51:20 +08:00
|
|
|
var found bool
|
2018-02-15 17:14:05 +08:00
|
|
|
err := vals.Iterate(container, func(v interface{}) bool {
|
2018-01-25 08:48:31 +08:00
|
|
|
found = (v == value)
|
|
|
|
return !found
|
|
|
|
})
|
2018-02-04 13:51:20 +08:00
|
|
|
return found, err
|
2017-12-17 13:20:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-04 13:51:20 +08:00
|
|
|
func hasKey(container, key interface{}) (bool, error) {
|
2017-12-17 13:20:03 +08:00
|
|
|
switch container := container.(type) {
|
2018-01-29 22:36:43 +08:00
|
|
|
case hashmap.Map:
|
2018-02-04 13:51:20 +08:00
|
|
|
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 {
|
2018-01-25 08:26:46 +08:00
|
|
|
// XXX(xiaq): Not all types that implement Lener have numerical indices
|
2018-02-15 17:14:05 +08:00
|
|
|
_, err := vals.ConvertListIndex(key, len)
|
2018-02-04 13:51:20 +08:00
|
|
|
return err == nil, nil
|
2018-01-25 08:26:46 +08:00
|
|
|
}
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-01 23:13:00 +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 {
|
2018-01-25 08:26:46 +08:00
|
|
|
n = len
|
2018-01-25 08:48:31 +08:00
|
|
|
} 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
|
|
|
|
})
|
2018-01-25 08:48:31 +08:00
|
|
|
if err != nil {
|
2018-03-01 23:13:00 +08:00
|
|
|
return 0, fmt.Errorf("cannot get length of a %s", vals.Kind(v))
|
2018-01-25 08:48:31 +08:00
|
|
|
}
|
2017-12-17 13:20:03 +08:00
|
|
|
}
|
|
|
|
default:
|
2018-03-01 23:13:00 +08:00
|
|
|
return 0, errors.New("want 0 or 1 argument")
|
2017-12-17 13:20:03 +08:00
|
|
|
}
|
2018-03-01 23:13:00 +08:00
|
|
|
return n, nil
|
2017-12-17 13:20:03 +08:00
|
|
|
}
|
|
|
|
|
2018-03-01 10:17:56 +08:00
|
|
|
func keys(fm *Frame, m hashmap.Map) {
|
|
|
|
out := fm.ports[1].Chan
|
2017-12-17 13:20:03 +08:00
|
|
|
|
2018-01-29 22:36:43 +08:00
|
|
|
for it := m.Iterator(); it.HasElem(); it.Next() {
|
|
|
|
k, _ := it.Elem()
|
|
|
|
out <- k
|
|
|
|
}
|
2017-12-17 13:20:03 +08:00
|
|
|
}
|