... 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 /.Privacy)
            ($.definition /.State)
            ($.definition /.Inheritance)
            ($.definition /.class_names_cannot_contain_periods)
            ($.definition /.class_name_cannot_be_a_type_variable)
            ($.definition /.cannot_convert_to_jvm_type)
            ($.definition /.cannot_cast_to_non_object)

            (,, (template.with [<name>]
                  [(`` ($.definition <name>
                         (%.message "The type of a (boxed) " (,, (template.text [<name>])) " object.")))]

                  [/.Boolean]
                  [/.Byte]
                  [/.Short]
                  [/.Integer]
                  [/.Long]
                  [/.Float]
                  [/.Double]
                  [/.Character]
                  ))

            (,, (template.with [<name>]
                  [(`` ($.definition <name>
                         (%.message "The type of an (unboxed) " (,, (template.text [<name>])) " value.")))]

                  [/.boolean]
                  [/.byte]
                  [/.short]
                  [/.int]
                  [/.long]
                  [/.float]
                  [/.double]
                  [/.char]
                  ))

            (,, (template.with [<name> <from> <to>]
                  [(`` ($.definition <name>
                         "Type converter."))]

                  [/.byte_to_long    Byte      Long]

                  [/.short_to_long   Short     Long]
                  
                  [/.double_to_int   Double    Integer]
                  [/.double_to_long  Double    Long]
                  [/.double_to_float Double    Float]

                  [/.float_to_int    Float     Integer]
                  [/.float_to_long   Float     Long]
                  [/.float_to_double Float     Double]
                  
                  [/.int_to_byte     Integer   Byte]
                  [/.int_to_short    Integer   Short]
                  [/.int_to_long     Integer   Long]
                  [/.int_to_float    Integer   Float]
                  [/.int_to_double   Integer   Double]
                  [/.int_to_char     Integer   Character]

                  [/.long_to_byte    Long      Byte]
                  [/.long_to_short   Long      Short]
                  [/.long_to_int     Long      Integer]
                  [/.long_to_float   Long      Float]
                  [/.long_to_double  Long      Double]

                  [/.char_to_byte    Character Byte]
                  [/.char_to_short   Character Short]
                  [/.char_to_int     Character Integer]
                  [/.char_to_long    Character Long]

                  [/.long_to_char    Long      Character]
                  [/.byte_to_int     Byte      Integer]
                  [/.short_to_int    Short     Integer]
                  [/.byte_to_char    Byte      Character]
                  [/.short_to_char   Short     Character]
                  ))

            ($.definition /.class
              "Allows defining JVM classes in Lux code."
              ($.example (' (class "final" (TestClass A) [Runnable]
                              ... Fields
                              ("private" foo boolean)
                              ("private" bar A)
                              ("private" baz java/lang/Object)
                              ... Methods
                              ("public" [] (new [value A]) []
                               (exec
                                 (:= ::foo true)
                                 (:= ::bar value)
                                 (:= ::baz "")
                                 []))
                              ("public" (virtual) java/lang/Object
                               "")
                              ("public" "static" (static) java/lang/Object
                               "")
                              (Runnable [] (run) void
                                        [])
                              )))
              ($.comment "The tuple corresponds to parent interfaces.")
              ($.comment "An optional super-class can be specified before the tuple. If not specified, java.lang.Object will be assumed.")
              ($.comment "Fields and methods defined in the class can be used with special syntax.")
              ($.comment "For example:")
              ($.comment "::resolved, for accessing the 'resolved' field.")
              ($.comment "(:= ::resolved true) for modifying it.")
              ($.comment "(::new! []) for calling the class's constructor.")
              ($.comment "(::resolve! container [value]) for calling the 'resolve' method."))

            ($.definition /.interface
              "Allows defining JVM interfaces."
              ($.example (' (interface TestInterface
                              ([] foo [boolean String] void "throws" [Exception])))))

            ($.definition /.object
              "Allows defining anonymous classes."
              ($.comment "The 1st tuple corresponds to class-level type-variables.")
              ($.comment "The 2nd tuple corresponds to parent interfaces.")
              ($.comment "The 3rd tuple corresponds to arguments to the super class constructor.")
              ($.comment "An optional super-class can be specified before the 1st tuple. If not specified, java.lang.Object will be assumed.")
              ($.example (' (object [] [Runnable]
                              []
                              (Runnable [] (run self) void
                                        (exec
                                          (do_something some_value)
                                          []))))))

            ($.definition /.null
              "The null pointer."
              ($.example (' (null))))

            ($.definition /.null?
              "Test for the null pointer."
              ($.example (' (= true
                               (null? (null)))))
              ($.example (' (= false
                               (null? "YOLO")))))

            ($.definition /.???
              "Takes a (potentially null) ObjectType reference and creates a (Maybe ObjectType) for it."
              ($.example (' (= (??? (is java/lang/String (null)))
                               {.#None})))
              ($.example (' (= (??? "YOLO")
                               {.#Some "YOLO"}))))

            ($.definition /.!!!
              (%.message "Takes a (Maybe ObjectType) and returns a ObjectType."
                         \n "A .#None would get translated into a (null).")
              ($.example (' (= (null)
                               (!!! (??? (is java/lang/Thread (null)))))))
              ($.example (' (= "foo"
                               (!!! (??? "foo"))))))

            ($.definition /.as
              (%.message "Checks whether an object is an instance of a particular class."
                         \n "Caveat emptor: Cannot check for polymorphism, so avoid using parameterized classes.")
              ($.example (' (when (as String "YOLO")
                              {.#Some value_as_string}
                              {.#None}))))

            ($.definition /.synchronized
              "Evaluates body, while holding a lock on a given object."
              ($.example (' (synchronized object_to_be_locked
                              (exec
                                (do something)
                                (dosomething else)
                                (finish the computation))))))

            ($.definition /.to
              "Call a variety of methods on an object. Then, return the object."
              ($.example (' (to object
                                (ClassName::method1 arg0 arg1 arg2)
                                (ClassName::method2 arg3 arg4 arg5)))))

            ($.definition /.import
              "Allows importing JVM classes, and using them as types."

              ($.comment "Their methods, fields and enum options can also be imported.")
              ($.example (' (import java/lang/Object
                              "[1]::[0]"
                              (new [])
                              (equals [java/lang/Object] boolean)
                              (wait [int] "io" "try" void))))

              ($.comment "Special options can also be given for the return values.")
              ($.comment "'?' means that the values will be returned inside a Maybe type. That way, null becomes .#None.")
              ($.comment "'try' means that the computation might throw an exception, and the return value will be wrapped by the Try type.")
              ($.comment "'io' means the computation has side effects, and will be wrapped by the IO type.")
              ($.comment "These options must show up in the following order ['io' 'try' '?'] (although, each option can be used independently).")
              ($.example (' (import java/lang/String
                              "[1]::[0]"
                              (new [[byte]])
                              ("static" valueOf [char] java/lang/String)
                              ("static" valueOf "as" int_valueOf [int] java/lang/String))))

              ($.example (' (import (java/util/List e)
                              "[1]::[0]"
                              (size [] int)
                              (get [int] e))))

              ($.example (' (import (java/util/ArrayList a)
                              "[1]::[0]"
                              ([T] toArray [[T]] [T]))))

              ($.comment "The class-type that is generated is of the fully-qualified name.")
              ($.comment "This avoids a clash between the java.util.List type, and Lux's own List type.")
              ($.comment "All enum options to be imported must be specified.")
              ($.example (' (import java/lang/Character$UnicodeScript
                              "[1]::[0]"
                              ("enum" ARABIC CYRILLIC LATIN))))
              
              ($.comment "It should also be noted, the only types that may show up in method arguments or return values may be Java classes, arrays, primitives, void or type-vars.")
              ($.comment "Lux types, such as Maybe cannot be named (otherwise, they'd be confused for Java classes).")
              ($.example (' (import (lux/concurrency/async/JvmAsync A)
                              "[1]::[0]"
                              (resolve [A] boolean)
                              (poll [] A)
                              (wasResolved [] boolean)
                              (waitOn [lux/Function] void)
                              ("static" [A] make [A] (lux/concurrency/async/JvmAsync A)))))
              
              ($.comment "Also, the names of the imported members will look like Class::member")
              ($.example (' (java/lang/Object::new [])))
              ($.example (' (java/lang/Object::equals [other_object] my_object)))
              ($.example (' (java/util/List::size [] my_list)))
              ($.example (' java/lang/Character$UnicodeScript::LATIN)))

            ($.definition /.array
              "Create an array of the given type, with the given size."
              ($.example (' (array java/lang/Object 10))))

            ($.definition /.length
              "Gives the length of an array."
              ($.example (' (length my_array))))

            ($.definition /.read!
              "Loads an element from an array."
              ($.example (' (read! 10 my_array))))

            ($.definition /.write!
              "Stores an element into an array."
              ($.example (' (write! 10 my_object my_array))))

            ($.definition /.class_for
              "Loads the class as a java.lang.Class object."
              ($.example (' (class_for java/lang/String))))

            ($.definition /.type
              ""
              ($.example (' (is Type
                                (type java/lang/String)))))

            ($.definition /.is
              ""
              ($.example (' (is java/lang/Object
                                (is java/lang/String
                                    ???)))))
            )))
