(.require
 [library
  [lux (.except)
   ["$" documentation]
   [data
    ["[0]" text (.only \n)
     ["%" \\format (.only format)]]]]]
 [\\library
  ["[0]" /]])

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

            ($.definition /.Frame
              "Meta-data about an abstract/nominal type in a stack of them.")

            ($.definition /.current
              "The currently-being-defined abstract/nominal type.")

            ($.definition /.specific
              "A specific abstract/nominal type still being defined somewhere in the scope."
              [(specific name)])

            (,, (with_template [<name> <from> <$> <to>]
                  [($.definition <name>
                     "Type-casting macro for abstract/nominal types."
                     [(|> value
                          (is <from>)
                          <$>
                          (is <to>))])]

                  [/.abstraction Representation abstraction Abstraction]
                  [/.representation Abstraction representation Representation]
                  ))

            ($.definition /.primitive
              (format "Define abstract/nominal types which hide their representation details."
                      \n "You can convert between the abstraction and its representation selectively to access the value, while hiding it from others.")
              [(primitive String
                 Text

                 (def (string value)
                   (-> Text String)
                   (abstraction value))

                 (def (text value)
                   (-> String Text)
                   (representation value)))]
              ["Type-parameters are optional."
               (primitive (Duplicate a)
                 [a a]

                 (def (duplicate value)
                   (All (_ a) (-> a (Duplicate a)))
                   (abstraction [value value])))]
              ["Definitions can be nested."
               (primitive (Single a)
                 a

                 (def (single value)
                   (All (_ a) (-> a (Single a)))
                   (abstraction value))

                 (primitive (Double a)
                   [a a]

                   (def (double value)
                     (All (_ a) (-> a (Double a)))
                     (abstraction [value value]))

                   (def (single' value)
                     (All (_ a) (-> a (Single a)))
                     (abstraction Single [value value]))

                   (let [value 0123]
                     (same? value
                            (|> value
                                single'
                                (representation Single)
                                double
                                representation)))))]
              ["Type-parameters do not necessarily have to be used in the representation type."
               "If they are not used, they become phantom types and can be used to customize types without changing the representation."
               (primitive (JavaScript a)
                 Text

                 (primitive Expression Any)
                 (primitive Statement Any)

                 (def (+ x y)
                   (-> (JavaScript Expression) (JavaScript Expression) (JavaScript Expression))
                   (abstraction
                    (format "(" (representation x) "+" (representation y) ")")))

                 (def (while test body)
                   (-> (JavaScript Expression) (JavaScript Statement) (JavaScript Statement))
                   (abstraction
                    (format "while(" (representation test) ") {"
                            (representation body)
                            "}"))))])

            ($.definition /.transmutation
              "Transmutes an abstract/nominal type's phantom types."
              [(primitive (JavaScript a)
                 Text

                 (primitive Expression Any)
                 (primitive Statement Any)

                 (def (statement expression)
                   (-> (JavaScript Expression) (JavaScript Statement))
                   (transmutation expression))

                 (def (statement' expression)
                   (-> (JavaScript Expression) (JavaScript Statement))
                   (transmutation JavaScript expression)))])
            )))
