(.using
  [library
   [lux {"-" if loop}
    ["$" documentation {"+" documentation:}]
    [data
     [text
      ["%" format {"+" format}]]]
    [macro
     ["[0]" template]]
    [math
     [number
      ["n" nat]
      ["i" int]
      ["r" rev]
      ["f" frac]]]]]
  [\\library
   ["[0]" /]])

(documentation: /.=>
  "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))])

(documentation: /.||>
  "A self-contained sequence of concatenative instructions."
  [(same? value
          (||> (push sample)))]
  [(||> (push 123)
        dup
        n/=)])

(documentation: /.word:
  "A named concatenative function."
  [(word: square
     (=> [Nat] [Nat])

     dup
     (apply/2 n.*))])

(documentation: /.apply
  "A generator for functions that turn arity N functions into arity N concatenative functions."
  [(: (=> [Nat] [Nat])
      ((apply 1) ++))])

(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> "."])]
     (documentation: <name>
       <doc>))]

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

(documentation: /.push
  "Push a value onto the stack.")

(documentation: /.drop
  "Drop/pop a value from the top of the stack.")

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

(documentation: /.dup
  "Duplicate the top of the stack.")

(documentation: /.swap
  "Swaps the 2 topmost stack values.")

(documentation: /.rotL
  "Rotes the 3 topmost stack values to the left.")

(documentation: /.rotR
  "Rotes the 3 topmost stack values to the right.")

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

(documentation: /.||L
  "Left-injects the top into sum.")

(documentation: /.||R
  "Right-injects the top into sum.")

(template [<input> <word> <func>]
  [(`` (documentation: (~~ (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.>=]
  )

(documentation: /.if
  "If expression."
  [(same? "then"
          (||> (push true)
               (push "then")
               (push "else")
               if))])

(documentation: /.call
  "Executes an anonymous block on the stack.")

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

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

(documentation: /.dip/2
  "Executes a block on the stack, save for the 2 topmost values.")

(documentation: /.do
  "Do-while loop expression."
  [(n.= (++ sample)
        (||> (push sample)
             (push (push false))
             (push (|>> (push 1) n/+))
             do while))])

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

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

(documentation: /.partial
  "Partial application."
  [(n.= (n.+ sample sample)
        (||> (push sample)
             (push sample)
             (push n/+)
             partial
             call))])

(documentation: /.when
  "Only execute the block when #1.")

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

(.def: .public documentation
  (.List $.Module)
  ($.module /._
            ""
            [..=>
             ..||>
             ..word:
             ..apply
             ..apply/1
             ..apply/2
             ..apply/3
             ..apply/4
             ..apply/5
             ..apply/6
             ..apply/7
             ..apply/8
             ..push
             ..drop
             ..nip
             ..dup
             ..swap
             ..rotL
             ..rotR
             ..&&
             ..||L
             ..||R
             ..if
             ..call
             ..loop
             ..dip
             ..dip/2
             ..do
             ..while
             ..compose
             ..partial
             ..when
             ..?

             ..n/+
             ..n/-
             ..n/*
             ..n//
             ..n/%
             ..n/=
             ..n/<
             ..n/<=
             ..n/>
             ..n/>=
             ..i/+
             ..i/-
             ..i/*
             ..i//
             ..i/%
             ..i/=
             ..i/<
             ..i/<=
             ..i/>
             ..i/>=
             ..r/+
             ..r/-
             ..r/*
             ..r//
             ..r/%
             ..r/=
             ..r/<
             ..r/<=
             ..r/>
             ..r/>=
             ..f/+
             ..f/-
             ..f/*
             ..f//
             ..f/%
             ..f/=
             ..f/<
             ..f/<=
             ..f/>
             ..f/>=]
            []))
