(.require
 [library
  [lux (.except)
   ["$" documentation]
   [data
    [text (.only \n)
     ["%" \\format (.only format)]]
    [collection
     ["[0]" list (.use "[1]#[0]" monoid)]]]]]
 ["[0]" \\format]
 ["[0]" \\parser]
 [\\library
  ["[0]" /]])

(`` (def \\parser
      (List $.Documentation)
      (let [specific (list ($.definition \\parser.size_8)
                           ($.definition \\parser.size_16)
                           ($.definition \\parser.size_32)
                           ($.definition \\parser.size_64)
                           ($.definition \\parser.bits_8)
                           ($.definition \\parser.bits_16)
                           ($.definition \\parser.bits_32)
                           ($.definition \\parser.bits_64)
                           ($.definition \\parser.nat)
                           ($.definition \\parser.int)
                           ($.definition \\parser.rev)
                           ($.definition \\parser.frac)
                           ($.definition \\parser.invalid_tag)
                           ($.definition \\parser.or)
                           ($.definition \\parser.not_a_bit)
                           ($.definition \\parser.bit)
                           ($.definition \\parser.text)
                           ($.definition \\parser.maybe)
                           ($.definition \\parser.set_elements_are_not_unique)
                           ($.definition \\parser.symbol)
                           ($.definition \\parser.type)
                           ($.definition \\parser.location)
                           ($.definition \\parser.code)

                           ($.definition \\parser.segment
                             "Parses a chunk of data of a given size."
                             [(segment size)])

                           (,, (with_template [<size> <name>]
                                 [($.definition <name>
                                    (format "Parses a block of data prefixed with a size that is " (%.nat <size>) " bytes long."))]

                                 [08 \\parser.binary_8]
                                 [16 \\parser.binary_16]
                                 [32 \\parser.binary_32]
                                 [64 \\parser.binary_64]
                                 ))

                           (,, (with_template [<size> <name>]
                                 [($.definition <name>
                                    (format "Parses a block of (UTF-8 encoded) text prefixed with a size that is " (%.nat <size>) " bytes long."))]

                                 [08 \\parser.utf8_8]
                                 [16 \\parser.utf8_16]
                                 [32 \\parser.utf8_32]
                                 [64 \\parser.utf8_64]
                                 ))

                           (,, (with_template [<size> <name>]
                                 [($.definition <name>
                                    (format "Parses a sequence of values prefixed with a size that is " (%.nat <size>) " bytes long."))]

                                 [08 \\parser.sequence_8]
                                 [16 \\parser.sequence_16]
                                 [32 \\parser.sequence_32]
                                 [64 \\parser.sequence_64]
                                 ))

                           ($.definition \\parser.list
                             "Parses an arbitrarily long list of values."
                             [(list value)])

                           ($.definition \\parser.set
                             ""
                             [(set hash value)]))]
        (list.partial ($.module \\parser._
                                "")

                      ($.definition \\parser.binary_was_not_fully_read)

                      ($.definition \\parser.Offset
                        "An offset for reading within binary data.")

                      ($.definition (\\parser.Parser it)
                        "A parser for raw binary data.")

                      ($.definition \\parser.result
                        "Runs a parser and checks that all the binary data was read by it."
                        [(result parser input)])

                      ($.definition \\parser.end?
                        "Checks whether there is no more data to read.")

                      ($.definition \\parser.offset
                        "The current offset (i.e. how much data has been read).")

                      ($.definition \\parser.remaining
                        "How much of the data remains to be read.")

                      ($.definition \\parser.Size
                        "The size of a chunk of data within a binary array.")

                      ($.definition \\parser.rec
                        "Tie the knot for a recursive parser.")

                      ($.definition \\parser.any
                        "Does no parsing, and just returns a dummy value.")

                      specific
                      ))))

(def \\format
  (List $.Documentation)
  (let [specific (list ($.definition \\format.bits_8)
                       ($.definition \\format.bits_16)
                       ($.definition \\format.bits_32)
                       ($.definition \\format.bits_64)
                       ($.definition \\format.any)
                       ($.definition \\format.bit)
                       ($.definition \\format.nat)
                       ($.definition \\format.int)
                       ($.definition \\format.rev)
                       ($.definition \\format.frac)
                       ($.definition \\format.binary_8)
                       ($.definition \\format.binary_16)
                       ($.definition \\format.binary_32)
                       ($.definition \\format.binary_64)
                       ($.definition \\format.utf8_8)
                       ($.definition \\format.utf8_16)
                       ($.definition \\format.utf8_32)
                       ($.definition \\format.utf8_64)
                       ($.definition \\format.text)
                       ($.definition \\format.sequence_8)
                       ($.definition \\format.sequence_16)
                       ($.definition \\format.sequence_32)
                       ($.definition \\format.sequence_64)
                       ($.definition \\format.maybe)
                       ($.definition \\format.list)
                       ($.definition \\format.set)
                       ($.definition \\format.symbol)
                       ($.definition \\format.type)
                       ($.definition \\format.location)
                       ($.definition \\format.code)

                       ($.definition \\format.segment
                         "Writes at most 'size' bytes of an input binary blob."
                         [(segment size)]))]
    (list.partial ($.module \\format._
                            "")
                  
                  ($.definition \\format.monoid)

                  ($.definition \\format.Mutation
                    "A mutation of binary data, tracking where in the data to transform.")

                  ($.definition \\format.Specification
                    "A description of how to transform binary data.")

                  ($.definition \\format.no_op
                    "A specification for empty binary data.")

                  ($.definition \\format.instance
                    "Given a specification of how to construct binary data, yields a binary blob that matches it.")

                  ($.definition (\\format.Format it)
                    "An operation that knows how to write information into a binary blob.")

                  ($.definition \\format.result
                    "Yields a binary blob with all the information written to it."
                    [(result format value)])

                  ($.definition \\format.or
                    ""
                    [(or left right)])

                  ($.definition \\format.and
                    ""
                    [(and pre post)])

                  ($.definition \\format.rec
                    "A combinator for recursive formats."
                    [(rec body)])

                  specific
                  )))

(def .public documentation
  (List $.Documentation)
  (list.partial ($.module /._
                          "")

                ($.definition /.index_out_of_bounds)
                ($.definition /.slice_out_of_bounds)
                ($.definition /.size)
                ($.definition /.equivalence)
                ($.definition /.monoid)

                ($.definition /.Binary
                  "A binary BLOB of data.")

                ($.definition /.empty
                  "A fresh/empty binary BLOB of the specified size."
                  [(empty size)])

                ($.definition /.mix
                  ""
                  [(mix f init binary)])

                ($.definition /.bits_8
                  "Read 1 byte (8 bits) at the given index."
                  [(bits_8 index binary)])

                ($.definition /.bits_16
                  "Read 2 bytes (16 bits) at the given index."
                  [(bits_16 index binary)])

                ($.definition /.bits_32
                  "Read 4 bytes (32 bits) at the given index."
                  [(bits_32 index binary)])

                ($.definition /.bits_64
                  "Read 8 bytes (64 bits) at the given index."
                  [(bits_64 index binary)])

                ($.definition /.has_8!
                  "Write 1 byte (8 bits) at the given index."
                  [(has_8! index value binary)])

                ($.definition /.has_16!
                  "Write 2 bytes (16 bits) at the given index."
                  [(has_16! index value binary)])

                ($.definition /.has_32!
                  "Write 4 bytes (32 bits) at the given index."
                  [(has_32! index value binary)])

                ($.definition /.has_64!
                  "Write 8 bytes (64 bits) at the given index."
                  [(has_64! index value binary)])

                ($.definition /.copy!
                  "Mutates the target binary BLOB by copying bytes from the source BLOB to it."
                  [(copy! bytes source_offset source target_offset target)])

                ($.definition /.slice
                  "Yields a subset of the binary BLOB, so long as the specified range is valid."
                  [(slice offset length binary)])

                ($.definition /.after
                  "Yields a binary BLOB with at most the specified number of bytes removed."
                  [(after bytes binary)])

                (all list#composite
                     ..\\format
                     ..\\parser
                     )
                ))
