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  }