diff --git a/preserves.nimble b/preserves.nimble index 627e8bb..8a15e08 100644 --- a/preserves.nimble +++ b/preserves.nimble @@ -1,6 +1,6 @@ # Package -version = "20231219" +version = "20231220" author = "Emery Hemingway" description = "data model and serialization format" license = "Unlicense" diff --git a/src/preserves/pegs.nim b/src/preserves/pegs.nim index 23c437a..2b33c62 100644 --- a/src/preserves/pegs.nim +++ b/src/preserves/pegs.nim @@ -9,6 +9,8 @@ when defined(nimHasUsed): {.used.} grammar "Preserves": + ws <- *(' ' | '\t' | '\r' | '\n' | ',') + Document <- Value * ws * !1 Value <- @@ -18,7 +20,7 @@ grammar "Preserves": Collection <- Sequence | Dictionary | Set - Atom <- Boolean | Float | Double | SignedInteger | String | ByteString | Symbol + Atom <- Boolean | Float | Double | FloatRaw | DoubleRaw | SignedInteger | String | ByteString | Symbol Record <- '<' * Value * *Value * ws * '>' @@ -30,29 +32,28 @@ grammar "Preserves": Boolean <- "#f" | "#t" - Float <- >flt * 'f' - Double <- flt - SignedInteger <- int - nat <- '0' | (Digit-'0') * *Digit int <- ?'-' * nat frac <- '.' * +Digit exp <- 'e' * ?('-'|'+') * +Digit flt <- int * ((frac * exp) | frac | exp) + Float <- >flt * 'f' + Double <- flt + + SignedInteger <- int + char <- unescaped | '|' | (escape * (escaped | '"' | ('u' * Xdigit[4]))) String <- '"' * >(*char) * '"' ByteString <- charByteString | hexByteString | b64ByteString charByteString <- "#\"" * >(*binchar) * '"' - hexByteString <- "#x\"" * ws * >(*(Xdigit[2] * ws)) * '"' - b64ByteString <- "#[" * ws * >(*(base64char * ws)) * ']' + hexByteString <- "#x\"" * >(*(ws * Xdigit[2])) * ws * '"' + base64char <- {'A'..'Z', 'a'..'z', '0'..'9', '+', '/', '-', '_', '='} + b64ByteString <- "#[" * >(*(ws * base64char)) * ws * ']' binchar <- binunescaped | (escape * (escaped | '"' | ('x' * Xdigit[2]))) binunescaped <- {' '..'!', '#'..'[', ']'..'~'} - base64char <- {'A'..'Z', 'a'..'z', '0'..'9', '+', '/', '-', '_', '='} - - Symbol <- >(symstart * *symcont) | ('|' * >(*symchar) * '|') symstart <- Alpha | sympunct | symustart symcont <- Alpha | sympunct | symustart | symucont | Digit | '-' @@ -61,6 +62,7 @@ grammar "Preserves": symustart <- utf8.any - {0..127} symucont <- utf8.any - {0..127} # TODO: exclude some unicode ranges + Symbol <- >(symstart * *symcont) | ('|' * >(*symchar) * '|') Embedded <- "#!" * Value @@ -73,4 +75,5 @@ grammar "Preserves": escaped <- {'\\', '/', 'b', 'f', 'n', 'r', 't'} escape <- '\\' - ws <- *(' ' | '\t' | '\r' | '\n' | ',') + FloatRaw <- "#xf\"" * >((ws * Xdigit[2])[4]) * ws * '"' + DoubleRaw <- "#xd\"" * >((ws * Xdigit[2])[8]) * ws * '"' diff --git a/src/preserves/private/parsing.nim b/src/preserves/private/parsing.nim index 17702f2..0ce0ebd 100644 --- a/src/preserves/private/parsing.nim +++ b/src/preserves/private/parsing.nim @@ -74,6 +74,14 @@ template unescape(buf: var seq[byte]; capture: string) = add(buf, byte capture[i]) inc(i) +proc pushHexNibble[T](result: var T; c: char) = + var n = case c + of '0'..'9': T(ord(c) - ord('0')) + of 'a'..'f': T(ord(c) - ord('a') + 10) + of 'A'..'F': T(ord(c) - ord('A') + 10) + else: 0 + result = (result shl 4) or n + proc parsePreserves*(text: string): Preserve[void] = ## Parse a text-encoded Preserves `string` to a `Preserve` value. runnableExamples: @@ -138,6 +146,16 @@ proc parsePreserves*(text: string): Preserve[void] = let i = stack.high discard parseBiggestFloat($0, stack[i].value.double) + Preserves.FloatRaw <- Preserves.FloatRaw: + var reg: uint32 + for c in $1: pushHexNibble(reg, c) + pushStack Value(kind: pkFloat, float: cast[float32](reg)) + + Preserves.DoubleRaw <- Preserves.DoubleRaw: + var reg: uint64 + for c in $1: pushHexNibble(reg, c) + pushStack Value(kind: pkDouble, double: cast[float64](reg)) + Preserves.SignedInteger <- Preserves.SignedInteger: pushStack Value(kind: pkSignedInteger, int: parseInt($0))