... This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
... If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.

(.require
 [library
  [lux (.except)
   ["$" documentation]
   [data
    [collection
     ["[0]" list]]]
   [math
    [number
     ["n" natural]
     ["i" integer]
     ["r" revolution]
     ["d" decimal]]]
   [meta
    [macro
     ["[0]" template]
     ["[0]" expansion]]]]]
 [\\library
  ["[0]" /]])

(`` (the arithmetic
      (.List $.Documentation)
      (list (,, (template.with [<input> <word> <func>]
                  [(`` ($.definition (,, (template.symbol [/._] [<word>]))
                         (,, (template.text [<func> " for " <input> " arithmetic."]))))]

                  [Natural  n/+  n.+]
                  [Natural  n/-  n.-]
                  [Natural  n/*  n.*]
                  [Natural  n//  n./]
                  [Natural  n/%  n.%]
                  [Natural  n/=  n.=]
                  [Natural  n/<  n.<]
                  [Natural  n/<= n.<=]
                  [Natural  n/>  n.>]
                  [Natural  n/>= n.>=]

                  [Integer  i/+  i.+]
                  [Integer  i/-  i.-]
                  [Integer  i/*  i.*]
                  [Integer  i//  i./]
                  [Integer  i/%  i.%]
                  [Integer  i/=  i.=]
                  [Integer  i/<  i.<]
                  [Integer  i/<= i.<=]
                  [Integer  i/>  i.>]
                  [Integer  i/>= i.>=]

                  [Revolution  r/+  r.+]
                  [Revolution  r/-  r.-]
                  [Revolution  r/*  r.*]
                  [Revolution  r//  r./]
                  [Revolution  r/%  r.%]
                  [Revolution  r/=  r.=]
                  [Revolution  r/<  r.<]
                  [Revolution  r/<= r.<=]
                  [Revolution  r/>  r.>]
                  [Revolution  r/>= r.>=]

                  [Decimal f/+  d.+]
                  [Decimal f/-  d.-]
                  [Decimal f/*  d.*]
                  [Decimal f//  d./]
                  [Decimal f/%  d.%]
                  [Decimal f/=  d.=]
                  [Decimal f/<  d.<]
                  [Decimal f/<= d.<=]
                  [Decimal f/>  d.>]
                  [Decimal f/>= d.>=]
                  ))
            )))

(`` (the .public documentation
      (.List $.Documentation)
      (list.partial ($.module /._
                              "")

                    ($.definition /.value)

                    ($.definition /.=>
                      "Concatenative function types."
                      ($.example (' (=> [Natural] [Natural])))
                      ($.example (' (for_any (_ a)
                                      (-> a (=> [] [a])))))
                      ($.example (' (for_any (_ t)
                                      (=> [t] []))))
                      ($.example (' (for_any (_ a b c)
                                      (=> [a b c] [b c a]))))
                      ($.example (' (for_any (_ ,,,0 ,,,1)
                                      (=> [then (=> ,,,0 ,,,1)
                                           else (=> ,,,0 ,,,1)]
                                          ,,,0 [Bit then else] ,,,1)))))

                    ($.definition /.apply
                      "A generator for functions that turn arity N functions into arity N concatenative functions."
                      ($.example (' (is (=> [Natural] [Natural])
                                        ((apply 1) ++)))))

                    (,, (template.with [<arity>]
                          [(expansion.let [<name> (template.symbol [/._] ["apply_" <arity>])
                                           <doc> (template.text ["Lift a function of arity " <arity>
                                                                 " into a concatenative function of arity " <arity> "."])]
                             ($.definition <name>
                               <doc>))]

                          [1] [2] [3] [4]
                          [5] [6] [7] [8]
                          ))

                    ($.definition /.push
                      "Push a value onto the stack.")

                    ($.definition /.drop
                      "Drop/pop a value from the top of the stack.")

                    ($.definition /.nip
                      "Drop the second-to-last value from the top of the stack.")

                    ($.definition /.dup
                      "Duplicate the top of the stack.")

                    ($.definition /.swap
                      "Swaps the 2 topmost stack values.")

                    ($.definition /.left_rotation
                      "Rotes the 3 topmost stack values to the left.")

                    ($.definition /.right_rotation
                      "Rotes the 3 topmost stack values to the right.")

                    ($.definition /.&&
                      "Groups the 2 topmost stack values as a 2-tuple.")

                    ($.definition /.left
                      "Left-injects the top into sum.")

                    ($.definition /.right
                      "Right-injects the top into sum.")

                    ($.definition /.if
                      "If expression."
                      ($.example (' (same? "then"
                                           (/.value (|>> (push true)
                                                         (push "then")
                                                         (push "else")
                                                         if))))))

                    ($.definition /.call
                      "Executes an anonymous block on the stack.")

                    ($.definition /.loop
                      "Executes a block as a loop until it yields #0 to stop.")

                    ($.definition /.dip
                      "Executes a block on the stack, save for the topmost value.")

                    ($.definition /.dip_2
                      "Executes a block on the stack, save for the 2 topmost values.")

                    ($.definition /.do
                      "Do-while loop expression."
                      ($.example (' (n.= (++ sample)
                                         (/.value (|>> (push sample)
                                                       (push (push false))
                                                       (push (|>> (push 1) n/+))
                                                       do while))))))

                    ($.definition /.while
                      "While loop expression."
                      ($.example (' (n.= (n.+ distance start)
                                         (/.value (|>> (push start)
                                                       (push (|>> dup
                                                                  (push start) n/-
                                                                  (push distance) n/<))
                                                       (push (|>> (push 1) n/+))
                                                       while))))))

                    ($.definition /.compose
                      "Function composition."
                      ($.example (' (n.= (n.+ 2 sample)
                                         (/.value (|>> (push sample)
                                                       (push (|>> (push 1) n/+))
                                                       (push (|>> (push 1) n/+))
                                                       compose
                                                       call))))))

                    ($.definition /.partial
                      "Partial application."
                      ($.example (' (n.= (n.+ sample sample)
                                         (/.value (|>> (push sample)
                                                       (push sample)
                                                       (push n/+)
                                                       partial
                                                       call))))))

                    ($.definition /.?
                      "Choose the top value when #0 and the second-to-top when #1.")

                    ..arithmetic
                    )))
