#lang racket/base
(require "bitstring.rkt")
(provide bit-string)
(define-syntax bit-string
(syntax-rules ()
((_)
(bytes))
((_ spec)
(parse-spec spec))
((_ spec0 specs ...)
(bit-string-append (parse-spec spec0) (bit-string specs ...)))))
(define-syntax parse-spec
(syntax-rules (:)
((_ (expr : option ...))
(parse-options (option ...) expr))
((_ expr)
(parse-options () expr))))
(define-syntax parse-options
(syntax-rules (binary integer float
little-endian big-endian native-endian
bytes bits default)
((_ options value)
(parse-options options
value
integer
big-endian
default))
((_ () value type endianness width-in-bits)
(build-bit-string-segment value type endianness width-in-bits))
((_ (binary rest ...) value type endianness width-in-bits)
(parse-options (rest ...) value binary endianness width-in-bits))
((_ (integer rest ...) value type endianness width-in-bits)
(parse-options (rest ...) value integer endianness width-in-bits))
((_ (float rest ...) value type endianness width-in-bits)
(parse-options (rest ...) value float endianness width-in-bits))
((_ (little-endian rest ...) value type endianness width-in-bits)
(parse-options (rest ...) value type little-endian width-in-bits))
((_ (big-endian rest ...) value type endianness width-in-bits)
(parse-options (rest ...) value type big-endian width-in-bits))
((_ (native-endian rest ...) value type endianness width-in-bits)
(parse-options (rest ...) value type native-endian width-in-bits))
((_ (bytes n rest ...) value type endianness width-in-bits)
(parse-options (rest ...) value type endianness (* 8 n)))
((_ (bits n rest ...) value type endianness width-in-bits)
(parse-options (rest ...) value type endianness n))
((_ (default rest ...) value type endianness width-in-bits)
(parse-options (rest ...) value type endianness default))))
(define-syntax build-bit-string-segment
(syntax-rules (binary integer float default)
((_ value binary dontcare1 default)
value)
((_ value binary dontcare1 width-in-bits)
(let-values (((lhs rhs) (bit-string-split-at value width-in-bits)))
lhs))
((_ value float endianness default)
(build-bit-string-segment value float endianness 64))
((_ value float endianness 32)
(real->floating-point-bytes value 4 (build-bit-string-endianness endianness)))
((_ value float endianness 64)
(real->floating-point-bytes value 8 (build-bit-string-endianness endianness)))
((_ value integer endianness default)
(build-bit-string-segment value integer endianness 8))
((_ value integer endianness width-in-bits)
(integer->bit-string value width-in-bits (build-bit-string-endianness endianness)))))
(define-syntax build-bit-string-endianness
(syntax-rules (little-endian big-endian native-endian)
((_ little-endian)
#f)
((_ big-endian)
#t)
((_ native-endian)
(system-big-endian?))))