(.require
 [library
  [lux (.except)
   ["$" documentation]
   [data
    [text
     ["%" \\format (.only format)]]
    [collection
     ["[0]" list]]]
   [math
    [number
     ["n" nat]
     ["i" int]
     ["r" rev]
     ["f" frac]]]
   [meta
    [macro
     ["[0]" template]]]]]
 [\\library
  ["[0]" /]])

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

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

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

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

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

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

                    ($.definition /.value)

                    ($.definition /.=>
                      "Concatenative function types."
                      [(=> [Nat] [Nat])]
                      [(All (_ a)
                         (-> a (=> [] [a])))]
                      [(All (_ t)
                         (=> [t] []))]
                      [(All (_ a b c)
                         (=> [a b c] [b c a]))]
                      [(All (_ ,,,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."
                      [(is (=> [Nat] [Nat])
                           ((apply 1) ++))])

                    (,, (with_template [<arity>]
                          [(with_expansions [<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."
                      [(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."
                      [(n.= (++ sample)
                            (/.value (|>> (push sample)
                                          (push (push false))
                                          (push (|>> (push 1) n/+))
                                          do while)))])

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

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

                    ($.definition /.partial
                      "Partial application."
                      [(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
                    )))
