(.require
 [library
  [lux (.except)
   ["$" documentation]
   [data
    ["[0]" text (.only \n)
     ["%" \\format (.only format)]]
    [collection
     ["[0]" list]]]]]
 [\\library
  ["[0]" /]]
 ["[0]" /
  ["[1][0]" code]
  ["[1][0]" location]
  ["[1][0]" symbol]
  ["[1][0]" type]
  ["[1][0]" macro]
  ["[1][0]" static]
  ["[1][0]" extension]
  ["[1][0]" target]
  ["[1][0]/" compiler
   ["[1][0]" phase]
   [language
    [lux
     ["[1][0]" analysis]
     ["[1][0]" declaration]
     ["[1][0]" generation]
     ["[1][0]" synthesis]]]]])

(def /compiler
  (List $.Documentation)
  (list.together
   (list /compiler/phase.documentation
         /compiler/analysis.documentation
         /compiler/declaration.documentation
         /compiler/generation.documentation
         /compiler/synthesis.documentation
         )))

(def .public documentation
  (List $.Documentation)
  (let [query (list ($.definition /.module
                      "Looks-up a module with the given name."
                      [(module name)])

                    ($.definition /.current_module_name
                      "The name of the module currently being compiled, if any.")

                    ($.definition /.current_module
                      "The module currently being compiled, if any.")

                    ($.definition /.macro
                      "Looks-up a macro known by the given name."
                      [(macro full_name)])

                    ($.definition /.seed
                      (format "The current value of a number tracked by the compiler."
                              \n "Also increases the value, so it's different next time it is seen."
                              \n "This number can be used for generating data 'randomly' during compilation."))

                    ($.definition /.module_exists?
                      ""
                      [(module_exists? module)])

                    ($.definition /.var_type
                      "Looks-up the type of a local variable somewhere in the environment."
                      [(var_type name)])

                    ($.definition /.definition
                      "Looks-up a definition's whole data in the available modules (including the current one)."
                      [(definition name)])

                    ($.definition /.export
                      (format "Looks-up a definition in the available modules (including the current one)."
                              \n "The look-up only succeeds if the definition has been exported.")
                      [(export name)])

                    ($.definition /.definition_type
                      "Looks-up a definition's type in the available modules (including the current one)."
                      [(definition_type name)])

                    ($.definition /.type
                      "Looks-up the type of either a local variable or a definition."
                      [(type name)])

                    ($.definition /.type_definition
                      "Finds the value of a type definition (such as Int, Any or Lux)."
                      [(type_definition name)])

                    ($.definition /.globals
                      "The entire list of globals in a module (including the non-exported/private ones)."
                      [(globals module)])

                    ($.definition /.definitions
                      "The entire list of definitions in a module (including the non-exported/private ones)."
                      [(definitions module)])

                    ($.definition /.exports
                      "All the exported definitions in a module."
                      [(exports module_name)])

                    ($.definition /.modules
                      "All the available modules (including the current one).")

                    ($.definition /.tags_of
                      "All the tags associated with a type definition."
                      [(tags_of type_name)])

                    ($.definition /.location
                      "The location of the current expression being analyzed.")

                    ($.definition /.expected_type
                      "The expected type of the current expression being analyzed.")

                    ($.definition /.imported_modules
                      "All the modules imported by a specified module."
                      [(imported_modules module_name)])

                    ($.definition /.imported_by?
                      ""
                      [(imported_by? import module)])

                    ($.definition /.imported?
                      "Checks if the given module has been imported by the current module."
                      [(imported? import)])

                    ($.definition /.tag
                      "Given a tag, finds out what is its index, its related tag-list and its associated type."
                      [(tag tag_name)])

                    ($.definition /.slot
                      "Given a slot, finds out what is its index, its related slot-list and its associated type."
                      [(slot slot_name)])

                    ($.definition /.tag_lists
                      "All the tag-lists defined in a module, with their associated types."
                      [(tag_lists module)])

                    ($.definition /.locals
                      "All the local variables currently in scope, separated in different scopes.")

                    ($.definition /.compiler_state
                      "Obtains the current state of the compiler.")

                    ($.definition /.type_context
                      "The current type-checking context."))
        computation (list ($.definition /.lifted)
                          ($.definition /.try)

                          ($.definition /.result'
                            (format "Evaluates a computation that depends on Lux's compiler state."
                                    \n "Also returns a (potentially modified) compiler state.")
                            [(result' lux action)])

                          ($.definition /.result
                            "Evaluates a computation that depends on Lux's compiler state."
                            [(result lux action)])

                          ($.definition /.either
                            "Pick whichever computation succeeds."
                            [(either left right)])

                          ($.definition /.assertion
                            "Fails with the given message if the test is #0."
                            [(assertion message test)])

                          ($.definition /.failure
                            "Fails with the given error message."
                            [(failure error)]))]
    (list.partial ($.module /._
                            "Functions for extracting information from the state of the compiler.")

                  ($.definition /.functor)
                  ($.definition /.apply)
                  ($.definition /.monad)

                  ($.definition /.normal
                    (format "If given a name without a module prefix, gives it the current module's name as prefix."
                            \n "Otherwise, returns the name as-is.")
                    [(normal name)])

                  ($.definition /.de_aliased
                    "Given an aliased definition's name, returns the original definition being referenced."
                    [(de_aliased def_name)])

                  ($.definition /.eval
                    ""
                    [(eval type code)])

                  (list.together
                   (list query
                         computation
                         ../compiler

                         /code.documentation
                         /location.documentation
                         /symbol.documentation
                         /type.documentation
                         /macro.documentation
                         /static.documentation
                         /extension.documentation
                         /target.documentation
                         ))
                  )))
