... 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
    ["[0]" text (.only \n)
     ["%" \\injection]]]
   [meta
    [macro
     ["[0]" template]]]]]
 [\\library
  ["[0]" /]])

(`` (the .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."
              ($.example (' (specific name))))

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

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

            ($.definition /.def
              (%.message "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.")
              ($.example (' (/.def String
                                   Text

                                   (.the (string value)
                                     (-> Text String)
                                     (abstraction value))

                                   (.the (text value)
                                     (-> String Text)
                                     (representation value)))))

              ($.comment "Type-parameters are optional.")
              ($.example (' (/.def (Duplicate a)
                                   [a a]

                                   (.the (duplicate value)
                                     (for_any (_ a) (-> a (Duplicate a)))
                                     (abstraction [value value])))))

              ($.comment "Definitions can be nested.")
              ($.example (' (/.def (Single a)
                                   a

                                   (.the (single value)
                                     (for_any (_ a) (-> a (Single a)))
                                     (abstraction value))

                                   (/.def (Double a)
                                          [a a]

                                          (.the (double value)
                                            (for_any (_ a) (-> a (Double a)))
                                            (abstraction [value value]))

                                          (.the (single' value)
                                            (for_any (_ a) (-> a (Single a)))
                                            (abstraction Single [value value]))

                                          (let [value 0123]
                                            (same? value
                                                   (|> value
                                                       single'
                                                       (representation Single)
                                                       double
                                                       representation)))))))

              ($.comment "Type-parameters do not necessarily have to be used in the representation type.")
              ($.comment "If they are not used, they become phantom types and can be used to customize types without changing the representation.")
              ($.example (' (/.def (JavaScript a)
                                   Text

                                   (/.def Expression Any)
                                   (/.def Statement Any)

                                   (.the (+ x y)
                                     (-> (JavaScript Expression) (JavaScript Expression) (JavaScript Expression))
                                     (abstraction
                                      (%.message "(" (representation x) "+" (representation y) ")")))

                                   (.the (while test body)
                                     (-> (JavaScript Expression) (JavaScript Statement) (JavaScript Statement))
                                     (abstraction
                                      (%.message "while(" (representation test) ") {"
                                                 (representation body)
                                                 "}")))))))

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

                                   (/.def Expression Any)
                                   (/.def Statement Any)

                                   (.the (statement expression)
                                     (-> (JavaScript Expression) (JavaScript Statement))
                                     (transmutation expression))

                                   (.the (statement' expression)
                                     (-> (JavaScript Expression) (JavaScript Statement))
                                     (transmutation JavaScript expression))))))
            )))
