github.com/kolbycrouch/elvish@v0.14.1-0.20210614162631-215b9ac1c423/pkg/eval/builtin_fn_container.go (about)

     1  package eval
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"math"
     7  	"math/big"
     8  	"sort"
     9  	"strconv"
    10  
    11  	"src.elv.sh/pkg/eval/errs"
    12  	"src.elv.sh/pkg/eval/vals"
    13  	"src.elv.sh/pkg/eval/vars"
    14  	"src.elv.sh/pkg/persistent/hashmap"
    15  )
    16  
    17  // Sequence, list and maps.
    18  
    19  func init() {
    20  	addBuiltinFns(map[string]interface{}{
    21  		"ns": nsFn,
    22  
    23  		"make-map": makeMap,
    24  
    25  		"range":  rangeFn,
    26  		"repeat": repeat,
    27  
    28  		"assoc":  assoc,
    29  		"dissoc": dissoc,
    30  
    31  		"all": all,
    32  		"one": one,
    33  
    34  		"has-key":   hasKey,
    35  		"has-value": hasValue,
    36  
    37  		"take":  take,
    38  		"drop":  drop,
    39  		"count": count,
    40  
    41  		"keys": keys,
    42  
    43  		"order": order,
    44  	})
    45  }
    46  
    47  //elvdoc:fn ns
    48  //
    49  // ```elvish
    50  // ns $map
    51  // ```
    52  //
    53  // Constructs a namespace from `$map`, using the keys as variable names and the
    54  // values as their values. Examples:
    55  //
    56  // ```elvish-transcript
    57  // ~> n = (ns [&name=value])
    58  // ~> put $n[name]
    59  // ▶ value
    60  // ~> n: = (ns [&name=value])
    61  // ~> put $n:name
    62  // ▶ value
    63  // ```
    64  
    65  func nsFn(m hashmap.Map) (*Ns, error) {
    66  	nb := make(NsBuilder)
    67  	for it := m.Iterator(); it.HasElem(); it.Next() {
    68  		k, v := it.Elem()
    69  		kstring, ok := k.(string)
    70  		if !ok {
    71  			return nil, errs.BadValue{
    72  				What:  `key of argument of "ns"`,
    73  				Valid: "string", Actual: vals.Kind(k)}
    74  		}
    75  		nb[kstring] = vars.FromInit(v)
    76  	}
    77  	return nb.Ns(), nil
    78  }
    79  
    80  //elvdoc:fn make-map
    81  //
    82  // ```elvish
    83  // make-map $input?
    84  // ```
    85  //
    86  // Outputs a map from an input consisting of containers with two elements. The
    87  // first element of each container is used as the key, and the second element is
    88  // used as the value.
    89  //
    90  // If the same key appears multiple times, the last value is used.
    91  //
    92  // Examples:
    93  //
    94  // ```elvish-transcript
    95  // ~> make-map [[k v]]
    96  // ▶ [&k=v]
    97  // ~> make-map [[k v1] [k v2]]
    98  // ▶ [&k=v2]
    99  // ~> put [k1 v1] [k2 v2] | make-map
   100  // ▶ [&k1=v1 &k2=v2]
   101  // ~> put aA bB | make-map
   102  // ▶ [&a=A &b=B]
   103  // ```
   104  
   105  func makeMap(input Inputs) (vals.Map, error) {
   106  	m := vals.EmptyMap
   107  	var errMakeMap error
   108  	input(func(v interface{}) {
   109  		if errMakeMap != nil {
   110  			return
   111  		}
   112  		if !vals.CanIterate(v) {
   113  			errMakeMap = errs.BadValue{
   114  				What: "input to make-map", Valid: "iterable", Actual: vals.Kind(v)}
   115  			return
   116  		}
   117  		if l := vals.Len(v); l != 2 {
   118  			errMakeMap = errs.BadValue{
   119  				What: "input to make-map", Valid: "iterable with 2 elements",
   120  				Actual: fmt.Sprintf("%v with %v elements", vals.Kind(v), l)}
   121  			return
   122  		}
   123  		elems, err := vals.Collect(v)
   124  		if err != nil {
   125  			errMakeMap = err
   126  			return
   127  		}
   128  		if len(elems) != 2 {
   129  			errMakeMap = fmt.Errorf("internal bug: collected %v values", len(elems))
   130  			return
   131  		}
   132  		m = m.Assoc(elems[0], elems[1])
   133  	})
   134  	return m, errMakeMap
   135  }
   136  
   137  //elvdoc:fn range
   138  //
   139  // ```elvish
   140  // range &step=1 $low? $high
   141  // ```
   142  //
   143  // Output `$low`, `$low` + `$step`, ..., proceeding as long as smaller than
   144  // `$high` or until overflow. If not given, `$low` defaults to 0. The `$step`
   145  // must be positive.
   146  //
   147  // This command is [exactness-preserving](#exactness-preserving).
   148  //
   149  // Examples:
   150  //
   151  // ```elvish-transcript
   152  // ~> range 4
   153  // ▶ 0
   154  // ▶ 1
   155  // ▶ 2
   156  // ▶ 3
   157  // ~> range 1 6 &step=2
   158  // ▶ 1
   159  // ▶ 3
   160  // ▶ 5
   161  // ```
   162  //
   163  // When using floating-point numbers, beware that numerical errors can result in
   164  // an incorrect number of outputs:
   165  //
   166  // ```elvish-transcript
   167  // ~> range 0.9 &step=0.3
   168  // ▶ (num 0.0)
   169  // ▶ (num 0.3)
   170  // ▶ (num 0.6)
   171  // ▶ (num 0.8999999999999999)
   172  // ```
   173  //
   174  // Avoid this problem by using exact rationals:
   175  //
   176  // ```elvish-transcript
   177  // ~> range 9/10 &step=3/10
   178  // ▶ (num 0)
   179  // ▶ (num 3/10)
   180  // ▶ (num 3/5)
   181  // ```
   182  //
   183  // Etymology:
   184  // [Python](https://docs.python.org/3/library/functions.html#func-range).
   185  
   186  type rangeOpts struct{ Step vals.Num }
   187  
   188  func (o *rangeOpts) SetDefaultOptions() { o.Step = 1 }
   189  
   190  func rangeFn(fm *Frame, opts rangeOpts, args ...vals.Num) error {
   191  	var rawNums []vals.Num
   192  	switch len(args) {
   193  	case 1:
   194  		rawNums = []vals.Num{0, args[0], opts.Step}
   195  	case 2:
   196  		rawNums = []vals.Num{args[0], args[1], opts.Step}
   197  	default:
   198  		return ErrArgs
   199  	}
   200  	switch step := opts.Step.(type) {
   201  	case int:
   202  		if step <= 0 {
   203  			return errs.BadValue{
   204  				What: "step", Valid: "positive", Actual: strconv.Itoa(step)}
   205  		}
   206  	case *big.Int:
   207  		if step.Sign() <= 0 {
   208  			return errs.BadValue{
   209  				What: "step", Valid: "positive", Actual: step.String()}
   210  		}
   211  	case *big.Rat:
   212  		if step.Sign() <= 0 {
   213  			return errs.BadValue{
   214  				What: "step", Valid: "positive", Actual: step.String()}
   215  		}
   216  	case float64:
   217  		if step <= 0 {
   218  			return errs.BadValue{
   219  				What: "step", Valid: "positive", Actual: vals.ToString(step)}
   220  		}
   221  	}
   222  	nums := vals.UnifyNums(rawNums, vals.Int)
   223  
   224  	out := fm.OutputChan()
   225  	switch nums := nums.(type) {
   226  	case []int:
   227  		lower, upper, step := nums[0], nums[1], nums[2]
   228  		for cur := lower; cur < upper; cur += step {
   229  			out <- vals.FromGo(cur)
   230  			if cur+step <= cur {
   231  				// Overflow
   232  				break
   233  			}
   234  		}
   235  	case []*big.Int:
   236  		lower, upper, step := nums[0], nums[1], nums[2]
   237  		cur := &big.Int{}
   238  		for cur.Set(lower); cur.Cmp(upper) < 0; {
   239  			out <- vals.FromGo(cur)
   240  			next := &big.Int{}
   241  			next.Add(cur, step)
   242  			cur = next
   243  		}
   244  	case []*big.Rat:
   245  		lower, upper, step := nums[0], nums[1], nums[2]
   246  		cur := &big.Rat{}
   247  		for cur.Set(lower); cur.Cmp(upper) < 0; {
   248  			out <- vals.FromGo(cur)
   249  			next := &big.Rat{}
   250  			next.Add(cur, step)
   251  			cur = next
   252  		}
   253  	case []float64:
   254  		lower, upper, step := nums[0], nums[1], nums[2]
   255  		for cur := lower; cur < upper; cur += step {
   256  			out <- vals.FromGo(cur)
   257  			if cur+step <= cur {
   258  				// Overflow
   259  				break
   260  			}
   261  		}
   262  	default:
   263  		panic("unreachable")
   264  	}
   265  
   266  	return nil
   267  }
   268  
   269  //elvdoc:fn repeat
   270  //
   271  // ```elvish
   272  // repeat $n $value
   273  // ```
   274  //
   275  // Output `$value` for `$n` times. Example:
   276  //
   277  // ```elvish-transcript
   278  // ~> repeat 0 lorem
   279  // ~> repeat 4 NAN
   280  // ▶ NAN
   281  // ▶ NAN
   282  // ▶ NAN
   283  // ▶ NAN
   284  // ```
   285  //
   286  // Etymology: [Clojure](https://clojuredocs.org/clojure.core/repeat).
   287  
   288  func repeat(fm *Frame, n int, v interface{}) {
   289  	out := fm.OutputChan()
   290  	for i := 0; i < n; i++ {
   291  		out <- v
   292  	}
   293  }
   294  
   295  //elvdoc:fn assoc
   296  //
   297  // ```elvish
   298  // assoc $container $k $v
   299  // ```
   300  //
   301  // Output a slightly modified version of `$container`, such that its value at `$k`
   302  // is `$v`. Applies to both lists and to maps.
   303  //
   304  // When `$container` is a list, `$k` may be a negative index. However, slice is not
   305  // yet supported.
   306  //
   307  // ```elvish-transcript
   308  // ~> assoc [foo bar quux] 0 lorem
   309  // ▶ [lorem bar quux]
   310  // ~> assoc [foo bar quux] -1 ipsum
   311  // ▶ [foo bar ipsum]
   312  // ~> assoc [&k=v] k v2
   313  // ▶ [&k=v2]
   314  // ~> assoc [&k=v] k2 v2
   315  // ▶ [&k2=v2 &k=v]
   316  // ```
   317  //
   318  // Etymology: [Clojure](https://clojuredocs.org/clojure.core/assoc).
   319  //
   320  // @cf dissoc
   321  
   322  func assoc(a, k, v interface{}) (interface{}, error) {
   323  	return vals.Assoc(a, k, v)
   324  }
   325  
   326  var errCannotDissoc = errors.New("cannot dissoc")
   327  
   328  //elvdoc:fn dissoc
   329  //
   330  // ```elvish
   331  // dissoc $map $k
   332  // ```
   333  //
   334  // Output a slightly modified version of `$map`, with the key `$k` removed. If
   335  // `$map` does not contain `$k` as a key, the same map is returned.
   336  //
   337  // ```elvish-transcript
   338  // ~> dissoc [&foo=bar &lorem=ipsum] foo
   339  // ▶ [&lorem=ipsum]
   340  // ~> dissoc [&foo=bar &lorem=ipsum] k
   341  // ▶ [&lorem=ipsum &foo=bar]
   342  // ```
   343  //
   344  // @cf assoc
   345  
   346  func dissoc(a, k interface{}) (interface{}, error) {
   347  	a2 := vals.Dissoc(a, k)
   348  	if a2 == nil {
   349  		return nil, errCannotDissoc
   350  	}
   351  	return a2, nil
   352  }
   353  
   354  //elvdoc:fn all
   355  //
   356  // ```elvish
   357  // all $input-list?
   358  // ```
   359  //
   360  // Passes inputs to the output as is. Byte inputs into values, one per line.
   361  //
   362  // This is an identity function for commands with value outputs: `a | all` is
   363  // equivalent to `a` if it only outputs values.
   364  //
   365  // This function is useful for turning inputs into arguments, like:
   366  //
   367  // ```elvish-transcript
   368  // ~> use str
   369  // ~> put 'lorem,ipsum' | str:split , (all)
   370  // ▶ lorem
   371  // ▶ ipsum
   372  // ```
   373  //
   374  // Or capturing all inputs in a variable:
   375  //
   376  // ```elvish-transcript
   377  // ~> x = [(all)]
   378  // foo
   379  // bar
   380  // (Press ^D)
   381  // ~> put $x
   382  // ▶ [foo bar]
   383  // ```
   384  //
   385  // When given a list, it outputs all elements of the list:
   386  //
   387  // ```elvish-transcript
   388  // ~> all [foo bar]
   389  // ▶ foo
   390  // ▶ bar
   391  // ```
   392  //
   393  // @cf one
   394  
   395  func all(fm *Frame, inputs Inputs) {
   396  	out := fm.OutputChan()
   397  	inputs(func(v interface{}) { out <- v })
   398  }
   399  
   400  //elvdoc:fn one
   401  //
   402  // ```elvish
   403  // one $input-list?
   404  // ```
   405  //
   406  // Passes inputs to outputs, if there is only a single one. Otherwise raises an
   407  // exception.
   408  //
   409  // This function can be used in a similar way to [`all`](#all), but is a better
   410  // choice when you expect that there is exactly one output:
   411  //
   412  // @cf all
   413  
   414  func one(fm *Frame, inputs Inputs) error {
   415  	var val interface{}
   416  	n := 0
   417  	inputs(func(v interface{}) {
   418  		if n == 0 {
   419  			val = v
   420  		}
   421  		n++
   422  	})
   423  	if n == 1 {
   424  		fm.OutputChan() <- val
   425  		return nil
   426  	}
   427  	return fmt.Errorf("expect a single value, got %d", n)
   428  }
   429  
   430  //elvdoc:fn take
   431  //
   432  // ```elvish
   433  // take $n $input-list?
   434  // ```
   435  //
   436  // Retain the first `$n` input elements. If `$n` is larger than the number of input
   437  // elements, the entire input is retained. Examples:
   438  //
   439  // ```elvish-transcript
   440  // ~> take 3 [a b c d e]
   441  // ▶ a
   442  // ▶ b
   443  // ▶ c
   444  // ~> use str
   445  // ~> str:split ' ' 'how are you?' | take 1
   446  // ▶ how
   447  // ~> range 2 | take 10
   448  // ▶ 0
   449  // ▶ 1
   450  // ```
   451  //
   452  // Etymology: Haskell.
   453  
   454  func take(fm *Frame, n int, inputs Inputs) {
   455  	out := fm.OutputChan()
   456  	i := 0
   457  	inputs(func(v interface{}) {
   458  		if i < n {
   459  			out <- v
   460  		}
   461  		i++
   462  	})
   463  }
   464  
   465  //elvdoc:fn drop
   466  //
   467  // ```elvish
   468  // drop $n $input-list?
   469  // ```
   470  //
   471  // Drop the first `$n` elements of the input. If `$n` is larger than the number of
   472  // input elements, the entire input is dropped.
   473  //
   474  // Example:
   475  //
   476  // ```elvish-transcript
   477  // ~> drop 2 [a b c d e]
   478  // ▶ c
   479  // ▶ d
   480  // ▶ e
   481  // ~> use str
   482  // ~> str:split ' ' 'how are you?' | drop 1
   483  // ▶ are
   484  // ▶ 'you?'
   485  // ~> range 2 | drop 10
   486  // ```
   487  //
   488  // Etymology: Haskell.
   489  //
   490  // @cf take
   491  
   492  func drop(fm *Frame, n int, inputs Inputs) {
   493  	out := fm.OutputChan()
   494  	i := 0
   495  	inputs(func(v interface{}) {
   496  		if i >= n {
   497  			out <- v
   498  		}
   499  		i++
   500  	})
   501  }
   502  
   503  //elvdoc:fn has-value
   504  //
   505  // ```elvish
   506  // has-value $container $value
   507  // ```
   508  //
   509  // Determine whether `$value` is a value in `$container`.
   510  //
   511  // Examples, maps:
   512  //
   513  // ```elvish-transcript
   514  // ~> has-value [&k1=v1 &k2=v2] v1
   515  // ▶ $true
   516  // ~> has-value [&k1=v1 &k2=v2] k1
   517  // ▶ $false
   518  // ```
   519  //
   520  // Examples, lists:
   521  //
   522  // ```elvish-transcript
   523  // ~> has-value [v1 v2] v1
   524  // ▶ $true
   525  // ~> has-value [v1 v2] k1
   526  // ▶ $false
   527  // ```
   528  //
   529  // Examples, strings:
   530  //
   531  // ```elvish-transcript
   532  // ~> has-value ab b
   533  // ▶ $true
   534  // ~> has-value ab c
   535  // ▶ $false
   536  // ```
   537  
   538  func hasValue(container, value interface{}) (bool, error) {
   539  	switch container := container.(type) {
   540  	case hashmap.Map:
   541  		for it := container.Iterator(); it.HasElem(); it.Next() {
   542  			_, v := it.Elem()
   543  			if vals.Equal(v, value) {
   544  				return true, nil
   545  			}
   546  		}
   547  		return false, nil
   548  	default:
   549  		var found bool
   550  		err := vals.Iterate(container, func(v interface{}) bool {
   551  			found = (v == value)
   552  			return !found
   553  		})
   554  		return found, err
   555  	}
   556  }
   557  
   558  //elvdoc:fn has-key
   559  //
   560  // ```elvish
   561  // has-key $container $key
   562  // ```
   563  //
   564  // Determine whether `$key` is a key in `$container`. A key could be a map key or
   565  // an index on a list or string. This includes a range of indexes.
   566  //
   567  // Examples, maps:
   568  //
   569  // ```elvish-transcript
   570  // ~> has-key [&k1=v1 &k2=v2] k1
   571  // ▶ $true
   572  // ~> has-key [&k1=v1 &k2=v2] v1
   573  // ▶ $false
   574  // ```
   575  //
   576  // Examples, lists:
   577  //
   578  // ```elvish-transcript
   579  // ~> has-key [v1 v2] 0
   580  // ▶ $true
   581  // ~> has-key [v1 v2] 1
   582  // ▶ $true
   583  // ~> has-key [v1 v2] 2
   584  // ▶ $false
   585  // ~> has-key [v1 v2] 0:2
   586  // ▶ $true
   587  // ~> has-key [v1 v2] 0:3
   588  // ▶ $false
   589  // ```
   590  //
   591  // Examples, strings:
   592  //
   593  // ```elvish-transcript
   594  // ~> has-key ab 0
   595  // ▶ $true
   596  // ~> has-key ab 1
   597  // ▶ $true
   598  // ~> has-key ab 2
   599  // ▶ $false
   600  // ~> has-key ab 0:2
   601  // ▶ $true
   602  // ~> has-key ab 0:3
   603  // ▶ $false
   604  // ```
   605  
   606  func hasKey(container, key interface{}) bool {
   607  	return vals.HasKey(container, key)
   608  }
   609  
   610  //elvdoc:fn count
   611  //
   612  // ```elvish
   613  // count $input-list?
   614  // ```
   615  //
   616  // Count the number of inputs.
   617  //
   618  // Examples:
   619  //
   620  // ```elvish-transcript
   621  // ~> count lorem # count bytes in a string
   622  // ▶ 5
   623  // ~> count [lorem ipsum]
   624  // ▶ 2
   625  // ~> range 100 | count
   626  // ▶ 100
   627  // ~> seq 100 | count
   628  // ▶ 100
   629  // ```
   630  
   631  // The count implementation uses a custom varargs based implementation rather
   632  // than the more common `Inputs` API (see pkg/eval/go_fn.go) because this
   633  // allows the implementation to be O(1) for the common cases rather than O(n).
   634  func count(fm *Frame, args ...interface{}) (int, error) {
   635  	var n int
   636  	switch nargs := len(args); nargs {
   637  	case 0:
   638  		// Count inputs.
   639  		fm.IterateInputs(func(interface{}) {
   640  			n++
   641  		})
   642  	case 1:
   643  		// Get length of argument.
   644  		v := args[0]
   645  		if len := vals.Len(v); len >= 0 {
   646  			n = len
   647  		} else {
   648  			err := vals.Iterate(v, func(interface{}) bool {
   649  				n++
   650  				return true
   651  			})
   652  			if err != nil {
   653  				return 0, fmt.Errorf("cannot get length of a %s", vals.Kind(v))
   654  			}
   655  		}
   656  	default:
   657  		// The error matches what would be returned if the `Inputs` API was
   658  		// used. See GoFn.Call().
   659  		return 0, errs.ArityMismatch{
   660  			What: "arguments here", ValidLow: 0, ValidHigh: 1, Actual: nargs}
   661  	}
   662  	return n, nil
   663  }
   664  
   665  //elvdoc:fn keys
   666  //
   667  // ```elvish
   668  // keys $map
   669  // ```
   670  //
   671  // Put all keys of `$map` on the structured stdout.
   672  //
   673  // Example:
   674  //
   675  // ```elvish-transcript
   676  // ~> keys [&a=foo &b=bar &c=baz]
   677  // ▶ a
   678  // ▶ c
   679  // ▶ b
   680  // ```
   681  //
   682  // Note that there is no guaranteed order for the keys of a map.
   683  
   684  func keys(fm *Frame, v interface{}) error {
   685  	out := fm.OutputChan()
   686  	return vals.IterateKeys(v, func(k interface{}) bool {
   687  		out <- k
   688  		return true
   689  	})
   690  }
   691  
   692  //elvdoc:fn order
   693  //
   694  // ```elvish
   695  // order &reverse=$false $less-than=$nil $inputs?
   696  // ```
   697  //
   698  // Outputs the input values sorted in ascending order. The sort is guaranteed to
   699  // be [stable](https://en.wikipedia.org/wiki/Sorting_algorithm#Stability).
   700  //
   701  // The `&reverse` option, if true, reverses the order of output.
   702  //
   703  // The `&less-than` option, if given, establishes the ordering of the elements.
   704  // Its value should be a function that takes two arguments and outputs a single
   705  // boolean indicating whether the first argument is less than the second
   706  // argument. If the function throws an exception, `order` rethrows the exception
   707  // without outputting any value.
   708  //
   709  // If `&less-than` has value `$nil` (the default if not set), the following
   710  // comparison algorithm is used:
   711  //
   712  // - Numbers are compared numerically. For the sake of sorting, `NaN` is treated
   713  //   as smaller than all other numbers.
   714  //
   715  // - Strings are compared lexicographically by bytes, which is equivalent to
   716  //   comparing by codepoints under UTF-8.
   717  //
   718  // - Lists are compared lexicographically by elements, if the elements at the
   719  //   same positions are comparable.
   720  //
   721  // If the ordering between two elements are not defined by the conditions above,
   722  // no value is outputted and an exception is thrown.
   723  //
   724  // Examples:
   725  //
   726  // ```elvish-transcript
   727  // ~> put foo bar ipsum | order
   728  // ▶ bar
   729  // ▶ foo
   730  // ▶ ipsum
   731  // ~> order [(float64 10) (float64 1) (float64 5)]
   732  // ▶ (float64 1)
   733  // ▶ (float64 5)
   734  // ▶ (float64 10)
   735  // ~> order [[a b] [a] [b b] [a c]]
   736  // ▶ [a]
   737  // ▶ [a b]
   738  // ▶ [a c]
   739  // ▶ [b b]
   740  // ~> order &reverse [a c b]
   741  // ▶ c
   742  // ▶ b
   743  // ▶ a
   744  // ~> order &less-than=[a b]{ eq $a x } [l x o r x e x m]
   745  // ▶ x
   746  // ▶ x
   747  // ▶ x
   748  // ▶ l
   749  // ▶ o
   750  // ▶ r
   751  // ▶ e
   752  // ▶ m
   753  // ```
   754  //
   755  // Beware that strings that look like numbers are treated as strings, not
   756  // numbers. To sort strings as numbers, use an explicit `&less-than` option:
   757  //
   758  // ```elvish-transcript
   759  // ~> order [5 1 10]
   760  // ▶ 1
   761  // ▶ 10
   762  // ▶ 5
   763  // ~> order &less-than=[a b]{ < $a $b } [5 1 10]
   764  // ▶ 1
   765  // ▶ 5
   766  // ▶ 10
   767  // ```
   768  
   769  type orderOptions struct {
   770  	Reverse  bool
   771  	LessThan Callable
   772  }
   773  
   774  func (opt *orderOptions) SetDefaultOptions() {}
   775  
   776  // ErrUncomparable is raised by the order command when inputs contain
   777  // uncomparable values.
   778  var ErrUncomparable = errs.BadValue{
   779  	What:  `inputs to "order"`,
   780  	Valid: "comparable values", Actual: "uncomparable values"}
   781  
   782  func order(fm *Frame, opts orderOptions, inputs Inputs) error {
   783  	var values []interface{}
   784  	inputs(func(v interface{}) { values = append(values, v) })
   785  
   786  	var errSort error
   787  	var lessFn func(i, j int) bool
   788  	if opts.LessThan != nil {
   789  		lessFn = func(i, j int) bool {
   790  			if errSort != nil {
   791  				return true
   792  			}
   793  			var args []interface{}
   794  			if opts.Reverse {
   795  				args = []interface{}{values[j], values[i]}
   796  			} else {
   797  				args = []interface{}{values[i], values[j]}
   798  			}
   799  			outputs, err := fm.CaptureOutput(func(fm *Frame) error {
   800  				return opts.LessThan.Call(fm, args, NoOpts)
   801  			})
   802  			if err != nil {
   803  				errSort = err
   804  				return true
   805  			}
   806  			if len(outputs) != 1 {
   807  				errSort = errs.BadValue{
   808  					What:   "output of the &less-than callback",
   809  					Valid:  "a single boolean",
   810  					Actual: fmt.Sprintf("%d values", len(outputs))}
   811  				return true
   812  			}
   813  			if b, ok := outputs[0].(bool); ok {
   814  				return b
   815  			}
   816  			errSort = errs.BadValue{
   817  				What:  "output of the &less-than callback",
   818  				Valid: "boolean", Actual: vals.Kind(outputs[0])}
   819  			return true
   820  		}
   821  	} else {
   822  		// Use default comparison implemented by compare.
   823  		lessFn = func(i, j int) bool {
   824  			if errSort != nil {
   825  				return true
   826  			}
   827  			o := compare(values[i], values[j])
   828  			if o == uncomparable {
   829  				errSort = ErrUncomparable
   830  				return true
   831  			}
   832  			if opts.Reverse {
   833  				return o == more
   834  			}
   835  			return o == less
   836  		}
   837  	}
   838  
   839  	sort.SliceStable(values, lessFn)
   840  
   841  	if errSort != nil {
   842  		return errSort
   843  	}
   844  	for _, v := range values {
   845  		fm.OutputChan() <- v
   846  	}
   847  	return nil
   848  }
   849  
   850  type ordering uint8
   851  
   852  const (
   853  	less ordering = iota
   854  	equal
   855  	more
   856  	uncomparable
   857  )
   858  
   859  func compare(a, b interface{}) ordering {
   860  	switch a := a.(type) {
   861  	case int, *big.Int, *big.Rat, float64:
   862  		switch b.(type) {
   863  		case int, *big.Int, *big.Rat, float64:
   864  			a, b := vals.UnifyNums2(a, b, 0)
   865  			switch a := a.(type) {
   866  			case int:
   867  				return compareInt(a, b.(int))
   868  			case *big.Int:
   869  				return compareInt(a.Cmp(b.(*big.Int)), 0)
   870  			case *big.Rat:
   871  				return compareInt(a.Cmp(b.(*big.Rat)), 0)
   872  			case float64:
   873  				return compareFloat(a, b.(float64))
   874  			default:
   875  				panic("unreachable")
   876  			}
   877  		}
   878  	case string:
   879  		if b, ok := b.(string); ok {
   880  			switch {
   881  			case a == b:
   882  				return equal
   883  			case a < b:
   884  				return less
   885  			default:
   886  				// a > b
   887  				return more
   888  			}
   889  		}
   890  	case vals.List:
   891  		if b, ok := b.(vals.List); ok {
   892  			aIt := a.Iterator()
   893  			bIt := b.Iterator()
   894  			for aIt.HasElem() && bIt.HasElem() {
   895  				o := compare(aIt.Elem(), bIt.Elem())
   896  				if o != equal {
   897  					return o
   898  				}
   899  				aIt.Next()
   900  				bIt.Next()
   901  			}
   902  			switch {
   903  			case a.Len() == b.Len():
   904  				return equal
   905  			case a.Len() < b.Len():
   906  				return less
   907  			default:
   908  				// a.Len() > b.Len()
   909  				return more
   910  			}
   911  		}
   912  	}
   913  	return uncomparable
   914  }
   915  
   916  func compareInt(a, b int) ordering {
   917  	if a < b {
   918  		return less
   919  	} else if a > b {
   920  		return more
   921  	}
   922  	return equal
   923  }
   924  
   925  func compareFloat(a, b float64) ordering {
   926  	// For the sake of ordering, NaN's are considered equal to each
   927  	// other and smaller than all numbers
   928  	switch {
   929  	case math.IsNaN(a):
   930  		if math.IsNaN(b) {
   931  			return equal
   932  		}
   933  		return less
   934  	case math.IsNaN(b):
   935  		return more
   936  	case a < b:
   937  		return less
   938  	case a > b:
   939  		return more
   940  	default: // a == b
   941  		return equal
   942  	}
   943  }