(.using
  [library
   [lux {"-" char symbol}
    ["$" documentation {"+" documentation:}]
    [data
     [text {"+" \n}
      ["%" format {"+" format}]]
     [collection
      ["[0]" list]]]]]
  ["[0]" / "_"
   ["[1][0]" code]
   ["[1][0]" local]
   ["[1][0]" syntax]
   ["[1][0]" template]]
  [\\library
   ["[0]" /]])

(documentation: /.single_expansion
  (format "Given code that requires applying a macro, does it once and returns the result."
          \n "Otherwise, returns the code as-is.")
  [(single_expansion syntax)])

(documentation: /.expansion
  (format "Given code that requires applying a macro, expands repeatedly until no more direct macro-calls are left."
          \n "Otherwise, returns the code as-is.")
  [(expansion syntax)])

(documentation: /.full_expansion
  "Expands all macro-calls everywhere recursively, until only primitive/base code remains."
  [(full_expansion syntax)])

(documentation: /.symbol
  (format "Generates a unique name as a Code node (ready to be used in code templates)."
          \n "A prefix can be given (or just be empty text) to better identify the code for debugging purposes.")
  [(symbol prefix)])

(documentation: /.wrong_syntax_error
  "A generic error message for macro syntax failures.")

(documentation: /.with_symbols
  "Creates new symbols and offers them to the body expression."
  [(syntax: (synchronized [lock any
                           body any])
     (with_symbols [g!lock g!body g!_]
       (in (list (` (let [(~ g!lock) (~ lock)
                          (~ g!_) ("jvm monitorenter" (~ g!lock))
                          (~ g!body) (~ body)
                          (~ g!_) ("jvm monitorexit" (~ g!lock))]
                      (~ g!body)))))))])

(documentation: /.one_expansion
  "Works just like expand, except that it ensures that the output is a single Code token."
  [(one_expansion token)])

(documentation: /.log_single_expansion!
  (format "Performs a macro-expansion and logs the resulting code."
          \n "You can either use the resulting code, or omit them."
          \n "By omitting them, this macro produces nothing (just like the lux.comment macro).")
  [(log_single_expansion!
    (def: (foo bar baz)
      (-> Int Int Int)
      (int.+ bar baz)))
   (log_single_expansion! "omit"
                          (def: (foo bar baz)
                            (-> Int Int Int)
                            (int.+ bar baz)))])

(documentation: /.log_expansion!
  (format "Performs a macro-expansion and logs the resulting code."
          \n "You can either use the resulting code, or omit them."
          \n "By omitting them, this macro produces nothing (just like the lux.comment macro).")
  [(log_expansion!
    (def: (foo bar baz)
      (-> Int Int Int)
      (int.+ bar baz)))
   (log_expansion! "omit"
                   (def: (foo bar baz)
                     (-> Int Int Int)
                     (int.+ bar baz)))])

(documentation: /.log_full_expansion!
  (format "Performs a macro-expansion and logs the resulting code."
          \n "You can either use the resulting code, or omit them."
          \n "By omitting them, this macro produces nothing (just like the lux.comment macro).")
  [(log_full_expansion!
    (def: (foo bar baz)
      (-> Int Int Int)
      (int.+ bar baz)))
   (log_full_expansion! "omit"
                        (def: (foo bar baz)
                          (-> Int Int Int)
                          (int.+ bar baz)))])

(.def: .public documentation
  (.List $.Module)
  ($.module /._
            ""
            [..single_expansion
             ..expansion
             ..full_expansion
             ..symbol
             ..wrong_syntax_error
             ..with_symbols
             ..one_expansion
             ..log_single_expansion!
             ..log_expansion!
             ..log_full_expansion!]
            [/code.documentation
             /local.documentation
             /syntax.documentation
             /template.documentation]))
