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 }