comparison.lisp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. "Provides macros for various comparison operators."
  2. (import core/base b)
  3. (import core/base (defun defmacro gensym and n with let* if get-idx list .. else get-idx car))
  4. (defun mk-quote (a) :hidden (list `unquote a))
  5. (defun mk-splice-quote (a) :hidden (list `unquote-splice a))
  6. (defmacro def-comparison (name names func-name &additional)
  7. "Def a comparison macro with the given NAME, which calls FUNC-NAME with two operands.
  8. ### Example:
  9. ```
  10. > (< 1 2 3)
  11. true
  12. > (< 1 4 3)
  13. false
  14. ```"
  15. :hidden
  16. (let* [(a (car names))
  17. (b (get-idx names 2))
  18. (sym (gensym))
  19. (len (gensym))
  20. (rest (get-idx names 3))]
  21. ;; Sit back and enjoy the quote/unquote awfulness.
  22. `(defmacro ,name (,a ,b ,{ :tag "symbol" :contents (.. "&" (get-idx rest :contents)) })
  23. ,@additional
  24. (with (,len (n ,rest))
  25. (cond
  26. [(b/= ,len 0) `(,,func-name ,,(mk-quote a) ,,(mk-quote b))]
  27. [else
  28. (with (,sym (gensym))
  29. ;; If we've got multiple values then cache b, as that will be reused in the next operator
  30. `(with (,,(mk-quote sym) ,,(mk-quote b))
  31. (if (,,func-name ,,(mk-quote a) ,,(mk-quote sym)) (,,name ,,(mk-quote sym) ,,(mk-splice-quote rest)) false)))])))))
  32. (def-comparison = (a b rest) b/=
  33. "Check whether A, B and all items in REST are equal.
  34. This will lazily evaluate each value: if A is not equal to B, then no
  35. subsequent arguments will be evaluated.
  36. ### Example:
  37. ```cl
  38. > (let [(a 1)
  39. . (b 2)]
  40. . (= 1 a b))
  41. out = false
  42. > (with (a 1)
  43. . (= a 1))
  44. out = true
  45. ```")
  46. (def-comparison /= (a b rest) b//=
  47. "Check whether A is not equal to B, B is not equal to the first element
  48. in REST, etc...
  49. This will lazily evaluate each value: if A is equal to B, then no
  50. subsequent arguments will be evaluated.
  51. ### Example:
  52. ```cl
  53. > (let [(a 1)
  54. . (b 2)]
  55. . (/= a b 1))
  56. out = true
  57. > (with (a 1)
  58. . (/= a 1))
  59. out = false
  60. ```")
  61. (def-comparison < (a b rest) b/<
  62. "Check whether A is smaller than B, B is smaller than the first element
  63. in REST, and so on for all subsequent arguments.
  64. This will lazily evaluate each value: if A is greater or equal to B,
  65. then no subsequent arguments will be evaluated.
  66. ### Example:
  67. ```cl
  68. > (with (a 3)
  69. . (< 1 a 5))
  70. out = true
  71. ```")
  72. (def-comparison > (a b rest) b/>
  73. "Check whether A is larger than B, B is larger than the first element
  74. in REST, and so on for all subsequent arguments.
  75. This will lazily evaluate each value: if A is smaller or equal to B,
  76. then no subsequent arguments will be evaluated.
  77. ### Example:
  78. ```cl
  79. > (with (a 3)
  80. . (> 5 a 1))
  81. out = true
  82. ```")
  83. (def-comparison <= (a b rest) b/<=
  84. "Check whether A is smaller or equal to B, B is smaller or equal to the
  85. first element in REST, and so on for all subsequent arguments.
  86. This will lazily evaluate each value: if A is larger than B,
  87. then no subsequent arguments will be evaluated.
  88. ### Example:
  89. ```cl
  90. > (with (a 3)
  91. . (<= 1 a 5))
  92. out = true
  93. ```")
  94. (def-comparison >= (a b rest) b/>=
  95. "Check whether A is larger or equal to B, B is larger or equal to the
  96. first element in REST, and so on for all subsequent arguments.
  97. This will lazily evaluate each value: if A is smaller than B,
  98. then no subsequent arguments will be evaluated.
  99. ### Example:
  100. ```cl
  101. > (with (a 3)
  102. . (>= 5 a 1))
  103. out = true
  104. ```")