marianoguerra/shrubbery/sexp does not have a README file

    Datum

    pub(all) enum Datum {
    Sym(String)
    Kw(String)
    Str(String)
    Bs(Bytes)
    Ch(Char)
    Bool_(Bool)
    Void
    Int_(
    BigInt
    )
    Rat(
    BigInt
    ,
    BigInt
    )
    Flo(Double)
    Nil
    Pair(Datum, Datum)
    Vec(Array[Datum])
    Rx(Bool, String)
    Other(String)
    } derive(Eq)

    A Racket datum: the value an atom of shrubbery notation denotes.

    Pair and Nil exist because a #{...} escape can contain an improper list. Rat exists because 1/2 is an exact rational and turning it into a Double would lose the exactness the reference keeps.

    Datum::canonical

    fn Datum::canonical(self : Datum) -> String

    A canonical text form, for comparing our parse against the reference's.

    Deliberately NOT Racket's write. Reproducing Racket's flonum printing byte for byte is a real piece of work — shortest-round-trip digits, the forced .0, the exponent thresholds — and getting it wrong would show up as a parse-parity failure that is really a formatting bug, which is the worst kind of red herring to hand someone. So a flonum is written as its IEEE-754 bits and the question does not arise. The oracle emits the same form from the Racket side.

    Where the reference's exact printing DOES matter is write_shrubbery, and there it is the thing under test rather than the measuring instrument.

    Datum::of_int

    fn Datum::of_int(n : Int) -> Datum

    An exact integer.

    Datum::of_ratio

    An exact rational, reduced, with the sign on the numerator.

    Reduces here rather than trusting the caller because the reference's reader produces reduced rationals and the canonical form has to match: 2/4 and 1/2 are the same number and must not compare as different parses.

    Datum::write_canonical

    fn Datum::write_canonical(self : Datum, buf : StringBuilder) -> Unit

    Source Files