(.using
  [library
   [lux {"-" int char type :as}
    ["$" documentation {"+" documentation:}]
    [data
     ["[0]" text {"+" \n}
      ["%" format {"+" format}]]]
    [macro
     ["[0]" template]]]]
  [\\library
   ["[0]" /]])

(template [<name> <from> <to>]
  [(documentation: <name>
     "Type converter.")]

  [/.byte_to_long "java.lang.Byte"      "java.lang.Long"]

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

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

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

  [/.char_to_byte "java.lang.Character" "java.lang.Byte"]
  [/.char_to_short "java.lang.Character" "java.lang.Short"]
  [/.char_to_int "java.lang.Character" "java.lang.Integer"]
  [/.char_to_long "java.lang.Character" "java.lang.Long"]
  )

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

(documentation: /.interface:
  "Allows defining JVM interfaces."
  [(interface: TestInterface
     ([] foo [boolean String] void "throws" [Exception]))])

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

(documentation: /.null
  "Null object reference."
  (null))

(documentation: /.null?
  "Test for null object reference."
  [(= (null? (null))
      true)]
  [(= (null? "YOLO")
      false)])

(documentation: /.???
  "Takes a (potentially null) ObjectType reference and creates a (Maybe ObjectType) for it."
  [(= (??? (: java/lang/String (null)))
      {.#None})]
  [(= (??? "YOLO")
      {.#Some "YOLO"})])

(documentation: /.!!!
  "Takes a (Maybe ObjectType) and returns a ObjectType."
  [(= "foo"
      (!!! (??? "foo")))]
  ["A .#None would get translated into a (null)."
   (= (null)
      (!!! (??? (: java/lang/Thread (null)))))])

(documentation: /.check
  (format "Checks whether an object is an instance of a particular class."
          \n "Caveat emptor: Cannot check for polymorphism, so avoid using parameterized classes.")
  [(case (check java/lang/String "YOLO")
     {.#Some value_as_string}
     {.#None})])

(documentation: /.synchronized
  "Evaluates body, while holding a lock on a given object."
  [(synchronized object_to_be_locked
     (exec
       (do something)
       (do_something else)
       (finish the computation)))])

(documentation: /.do_to
  "Call a variety of methods on an object. Then, return the object."
  [(do_to object
     (ClassName::method0 arg0 arg1 arg2)
     (ClassName::method1 arg3 arg4 arg5))])

(documentation: /.import:
  (format "Allows importing JVM classes, and using them as types."
          \n "Their methods, fields and enum options can also be imported.")
  [(import: java/lang/Object
     ["[1]::[0]"
      (new [])
      (equals [java/lang/Object] boolean)
      (wait [int] "io" "try" void)])]
  ["Special options can also be given for the return values."
   "'?' means that the values will be returned inside a Maybe type. That way, null becomes .#None."
   "'try' means that the computation might throw an exception, and the return value will be wrapped by the Try type."
   "'io' means the computation has side effects, and will be wrapped by the IO type."
   "These options must show up in the following order ['io' 'try' '?'] (although, each option can be used independently)."
   (import: java/lang/String
     ["[1]::[0]"
      (new [[byte]])
      ("static" valueOf [char] java/lang/String)
      ("static" valueOf "as" int_valueOf [int] java/lang/String)])

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

   (import: (java/util/ArrayList a)
     ["[1]::[0]"
      ([T] toArray [[T]] [T])])]
  ["The class-type that is generated is of the fully-qualified name."
   "This avoids a clash between the java.util.List type, and Lux's own List type."
   "All enum options to be imported must be specified."
   (import: java/lang/Character$UnicodeScript
     ["[1]::[0]"
      ("enum" ARABIC CYRILLIC LATIN)])]
  ["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-parameters."
   "Lux types, such as Maybe cannot be named (otherwise, they'd be confused for Java classes)."
   (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))])]
  ["Also, the names of the imported members will look like Class::member"
   (java/lang/Object::new [])
   (java/lang/Object::equals [other_object] my_object)
   (java/util/List::size [] my_list)
   java/lang/Character$UnicodeScript::LATIN])

(documentation: /.array
  "Create an array of the given type, with the given size."
  [(array java/lang/Object 10)])

(documentation: /.length
  "Gives the length of an array."
  [(length my_array)])

(documentation: /.read!
  "Loads an element from an array."
  [(read! 10 my_array)])

(documentation: /.write!
  "Stores an element into an array."
  [(write! 10 my_object my_array)])

(documentation: /.class_for
  "Loads the class as a java.lang.Class object."
  [(: (Primitive "java.lang.Class" ["java.lang.Object"])
      (class_for java/lang/String))])

(documentation: /.type
  ""
  [(: .Type
      (type java/lang/String))])

(.def: .public documentation
  (.List $.Module)
  ($.module /._
            ""
            [..byte_to_long
             ..short_to_long
             ..double_to_int
             ..double_to_long
             ..double_to_float
             ..float_to_int
             ..float_to_long
             ..float_to_double
             ..int_to_byte
             ..int_to_short
             ..int_to_long
             ..int_to_float
             ..int_to_double
             ..int_to_char
             ..long_to_byte
             ..long_to_short
             ..long_to_int
             ..long_to_float
             ..long_to_double
             ..char_to_byte
             ..char_to_short
             ..char_to_int
             ..char_to_long
             ..class:
             ..interface:
             ..object
             ..null
             ..null?
             ..???
             ..!!!
             ..check
             ..synchronized
             ..do_to
             ..import:
             ..array
             ..length
             ..read!
             ..write!
             ..class_for
             ..type
             ($.default /.Privacy)
             ($.default /.State)
             ($.default /.Inheritance)]
            []))
