Racket impl; update test data; tweak spec

This commit is contained in:
Tony Garnock-Jones 2022-11-06 23:55:33 +01:00
parent 2d3df32749
commit 5a18b192ba
8 changed files with 204 additions and 88 deletions

View File

@ -74,9 +74,35 @@
dict3: @"Duplicate key" <ParseError "{ a: 1, a: 2 }">
dict4: @"Unexpected close brace" <ParseError "}">
dict5: @"Missing value" <DecodeError #x"b7 91 92 93 84">
double0: <Test #x"830000000000000000" 0.0>
double+0: <Test #x"830000000000000000" +0.0>
double-0: <Test #x"838000000000000000" -0.0>
double1: <Test #x"833ff0000000000000" 1.0>
double2: <Test #x"83fe3cb7b759bf0426" -1.202e300>
double3: <Test #x"83123456789abcdef0" #xd"123456789abcdef0">
double4: @"Fewer than 16 digits" <ParseError "#xd\"12345678\"">
double5: @"More than 16 digits" <ParseError "#xd\"123456789abcdef012\"">
double6: @"Invalid chars" <ParseError "#xd\"12zz56789abcdef0\"">
double7: @"Positive infinity" <Test #x"837ff0000000000000" #xd"7ff0000000000000">
double8: @"Negative infinity" <Test #x"83fff0000000000000" #xd"fff0000000000000">
double9: @"-NaN" <Test #x"83fff0000000000001" #xd"fff0000000000001">
double10: @"-NaN" <Test #x"83fff0000000000111" #xd"fff0000000000111">
double11: @"+NaN" <Test #x"837ff0000000000001" #xd"7ff0000000000001">
double12: @"+NaN" <Test #x"837ff0000000000111" #xd"7ff0000000000111">
float0: <Test #x"8200000000" 0.0f>
float+0: <Test #x"8200000000" +0.0f>
float-0: <Test #x"8280000000" -0.0f>
float1: <Test #x"823f800000" 1.0f>
float2: <Test #x"8212345678" #xf"12345678">
float3: @"Fewer than 8 digits" <ParseError "#xf\"123456\"">
float4: @"More than 8 digits" <ParseError "#xf\"123456789a\"">
float5: @"Invalid chars" <ParseError "#xf\"12zz5678\"">
float6: @"Positive infinity" <Test #x"827f800000" #xf"7f800000">
float7: @"Negative infinity" <Test #x"82ff800000" #xf"ff800000">
float8: @"+NaN" <Test #x"827f800001" #xf"7f800001">
float9: @"+NaN" <Test #x"827f800111" #xf"7f800111">
float10: @"-NaN" <Test #x"82ff800001" #xf"ff800001">
float11: @"-NaN" <Test #x"82ff800111" #xf"ff800111">
int-257: <Test #x"a1feff" -257>
int-256: <Test #x"a1ff00" -256>
int-255: <Test #x"a1ff01" -255>
@ -89,10 +115,13 @@
int-2: <Test #x"9e" -2>
int-1: <Test #x"9f" -1>
int0: <Test #x"90" 0>
int+0: <Test #x"90" +0>
int-0: <Test #x"90" -0>
int1: <Test #x"91" 1>
int12: <Test #x"9c" 12>
int13: <Test #x"a00d" 13>
int127: <Test #x"a07f" 127>
int+127: <Test #x"a07f" +127>
int128: <Test #x"a10080" 128>
int255: <Test #x"a100ff" 255>
int256: <Test #x"a10100" 256>
@ -112,6 +141,8 @@
list8: @"Missing close bracket" <ParseShort "[">
list9: @"Unexpected close bracket" <ParseError "]">
list10: @"Missing end byte" <DecodeShort #x"b58080">
list11: <Test #x"b59184" [01]>
list12: <Test #x"b59c84" [12]>
noinput0: @"No input at all" <DecodeEOF #x"">
embed0: <Test #x"8690" #!0>
embed1: <Test #x"868690" #!#!0>
@ -138,17 +169,22 @@
string5: <Test #x"b104f09d849e" "\uD834\uDD1E">
symbol0: <Test #x"b300" ||>
symbol2: <Test #x"b30568656c6c6f" hello>
symbol3: <Test #x"b305312d322d33" 1-2-3>
symbol4: <Test #x"b305612d622d63" a-b-c>
symbol5: <Test #x"b305612b622b63" a+b+c>
symbol6: <Test #x"b3012b" +>
symbol7: <Test #x"b3032b2b2b" +++>
symbol8: <Test #x"b3012d" ->
symbol9: <Test #x"b3032d2d2d" --->
symbol10: <Test #x"b3022d61" -a>
symbol11: <Test #x"b3042d2d2d61" ---a>
symbol12: <Test #x"b3042d2d2d31" ---1>
symbol13: <Test #x"b3042b312e78" +1.x>
tag0: @"Unexpected end tag" <DecodeError #x"84">
tag1: @"Invalid tag" <DecodeError #x"10">
tag2: @"Invalid tag" <DecodeError #x"61b10110">
whitespace0: @"Leading spaces have to eventually yield something" <ParseShort " ">
whitespace1: @"No input at all" <ParseEOF "">
value1: <Test #"\xB2\x06corymb" #=#"\xB2\x06corymb">
value2: <Test #"\x81" #=#"\x81">
value3: <Test #"\x81" #=#[gQ]>
value4: <Test #"\x81" #=#[gQ==]>
value5: <Test #"\x81" #= #[gQ==]>
value6: <Test #x"b591929384" #=#x"b591929384">
longlist14: <Test #x"b5808080808080808080808080808084"
[#f #f #f #f #f

View File

@ -67,8 +67,6 @@
(define (next*)
(skip-whitespace)
(match (next-char)
[#\- (read-intpart (list #\-) (next-char))]
[(and c (or #\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)) (read-intpart '() c)]
[#\" (read-string #\")]
[(== PIPE) (string->symbol (read-string PIPE))]
@ -82,21 +80,12 @@
[#\t #t]
[#\{ (sequence-fold (set) set-add* values #\})]
[#\" (read-literal-binary)]
[#\x (if (eqv? (next-char) #\")
(read-hex-binary '())
(parse-error "Expected open-quote at start of hex ByteString"))]
[#\x (match (next-char)
[#\" (read-hex-binary '())]
[#\f (float (read-hex-float 4))]
[#\d (read-hex-float 8)]
[c (parse-error "Invalid #x syntax: ~v" c)])]
[#\[ (read-base64-binary '())]
[#\= (define bs (read-preserve/text in-port #:read-syntax? #t #:source source))
(when (not (bytes? (annotated-item bs)))
(parse-error "ByteString must follow #="))
(when (not (null? (annotated-annotations bs)))
(parse-error "Annotations not permitted after #="))
(bytes->preserve
(annotated-item bs)
(lambda (message . args)
(apply parse-error (string-append "Inline binary value: " message) args))
#:read-syntax? read-syntax?
#:on-short (lambda () (parse-error "Incomplete inline binary value")))]
[#\! (embedded (decode-embedded (next)))]
[c (parse-error "Invalid # syntax: ~v" c)])]
@ -110,7 +99,7 @@
[#\] (parse-error "Unexpected ]")]
[#\} (parse-error "Unexpected }")]
[c (read-raw-symbol (list c))]))
[c (read-raw-symbol-or-number (list c))]))
(define (set-add* s e)
(when (set-member? s e) (parse-error "Duplicate set element: ~v" e))
@ -159,49 +148,6 @@
(annotated '() loc v))))
(lambda (pos0 v) v)))
;;---------------------------------------------------------------------------
;; Numbers
(define (read-intpart acc-rev ch)
(match ch
[#\0 (read-fracexp (cons ch acc-rev))]
[_ (read-digit+ acc-rev read-fracexp ch)]))
(define (read-digit* acc-rev k)
(match (peek-char in-port)
[(? char? (? char-numeric?)) (read-digit* (cons (read-char in-port) acc-rev) k)]
[_ (k acc-rev)]))
(define (read-digit+ acc-rev k [ch (read-char in-port)])
(match ch
[(? char? (? char-numeric?)) (read-digit* (cons ch acc-rev) k)]
[_ (parse-error "Incomplete number")]))
(define (read-fracexp acc-rev)
(match (peek-char in-port)
[#\. (read-digit+ (cons (read-char in-port) acc-rev) read-exp)]
[_ (read-exp acc-rev)]))
(define (read-exp acc-rev)
(match (peek-char in-port)
[(or #\e #\E) (read-sign-and-exp (cons (read-char in-port) acc-rev))]
[_ (finish-number acc-rev)]))
(define (read-sign-and-exp acc-rev)
(match (peek-char in-port)
[(or #\+ #\-) (read-digit+ (cons (read-char in-port) acc-rev) finish-number)]
[_ (read-digit+ acc-rev finish-number)]))
(define (finish-number acc-rev)
(define s (list->string (reverse acc-rev)))
(define n (string->number s 10))
(when (not n) (parse-error "Invalid number: ~v" s))
(if (flonum? n)
(match (peek-char in-port)
[(or #\f #\F) (read-char in-port) (float n)]
[_ n])
n))
;;---------------------------------------------------------------------------
;; String-like things
@ -279,6 +225,17 @@
[else
(parse-error "Invalid hex character")]))
;;---------------------------------------------------------------------------
;; Hex-encoded floating point numbers
(define (read-hex-float byte-count)
(unless (eqv? (next-char) #\")
(parse-error "Missing open-double-quote in hex-encoded floating-point number"))
(define bs (read-hex-binary '()))
(unless (= (bytes-length bs) byte-count)
(parse-error "Incorrect number of bytes in hex-encoded floating-point number"))
(floating-point-bytes->real bs #t 0 byte-count))
;;---------------------------------------------------------------------------
;; Base64-encoded ByteStrings
@ -334,16 +291,56 @@
#\}))
;;---------------------------------------------------------------------------
;; "Raw" symbols
;; "Raw" symbols and numbers
(define (read-raw-symbol acc)
(define (read-raw-symbol-or-number acc)
(match (peek-char in-port)
[(or (? eof-object?)
(? char? (or #\( #\) #\{ #\} #\[ #\] #\< #\>
#\" #\; #\, #\@ #\# #\: (== PIPE)
(? char-whitespace?))))
(string->symbol (list->string (reverse acc)))]
[_ (read-raw-symbol (cons (read-char in-port) acc))]))
(let ((input (reverse acc)))
(or (analyze-number input)
(string->symbol (list->string input))))]
[_ (read-raw-symbol-or-number (cons (read-char in-port) acc))]))
(define (analyze-number input)
(match input
[(cons (and sign (or #\+ #\-)) input) (read-digit+ (list sign) read-fracexp input)]
[_ (read-digit+ (list) read-fracexp input)]))
(define (read-digit* acc-rev k input)
(match input
[(cons (? char? (? char-numeric? d)) input) (read-digit* (cons d acc-rev) k input)]
[_ (k acc-rev input)]))
(define (read-digit+ acc-rev k input)
(match input
[(cons (? char? (? char-numeric? d)) input) (read-digit* (cons d acc-rev) k input)]
[_ #f]))
(define (read-fracexp acc-rev input)
(match input
[(cons #\. input) (read-digit+ (cons #\. acc-rev) read-exp input)]
[_ (read-exp acc-rev input)]))
(define (read-exp acc-rev input)
(match input
[(cons (and e (or #\e #\E)) input) (read-sign-and-exp (cons e acc-rev) input)]
[_ (finish-number acc-rev input)]))
(define (read-sign-and-exp acc-rev input)
(match input
[(cons (and sign (or #\+ #\-)) input) (read-digit+ (cons sign acc-rev) finish-number input)]
[_ (read-digit+ acc-rev finish-number input)]))
(define (finish-number acc-rev input)
(define s (list->string (reverse acc-rev)))
(define n (string->number s 10))
(cond [(not n) #f]
[(and (flonum? n) (member input '((#\f) (#\F)))) (float n)]
[(equal? input '()) n]
[else #f]))
;;---------------------------------------------------------------------------
;; Main entry point to parser

View File

@ -74,9 +74,35 @@
dict3: @"Duplicate key" <ParseError "{ a: 1, a: 2 }">
dict4: @"Unexpected close brace" <ParseError "}">
dict5: @"Missing value" <DecodeError #x"b7 91 92 93 84">
double0: <Test #x"830000000000000000" 0.0>
double+0: <Test #x"830000000000000000" +0.0>
double-0: <Test #x"838000000000000000" -0.0>
double1: <Test #x"833ff0000000000000" 1.0>
double2: <Test #x"83fe3cb7b759bf0426" -1.202e300>
double3: <Test #x"83123456789abcdef0" #xd"123456789abcdef0">
double4: @"Fewer than 16 digits" <ParseError "#xd\"12345678\"">
double5: @"More than 16 digits" <ParseError "#xd\"123456789abcdef012\"">
double6: @"Invalid chars" <ParseError "#xd\"12zz56789abcdef0\"">
double7: @"Positive infinity" <Test #x"837ff0000000000000" #xd"7ff0000000000000">
double8: @"Negative infinity" <Test #x"83fff0000000000000" #xd"fff0000000000000">
double9: @"-NaN" <Test #x"83fff0000000000001" #xd"fff0000000000001">
double10: @"-NaN" <Test #x"83fff0000000000111" #xd"fff0000000000111">
double11: @"+NaN" <Test #x"837ff0000000000001" #xd"7ff0000000000001">
double12: @"+NaN" <Test #x"837ff0000000000111" #xd"7ff0000000000111">
float0: <Test #x"8200000000" 0.0f>
float+0: <Test #x"8200000000" +0.0f>
float-0: <Test #x"8280000000" -0.0f>
float1: <Test #x"823f800000" 1.0f>
float2: <Test #x"8212345678" #xf"12345678">
float3: @"Fewer than 8 digits" <ParseError "#xf\"123456\"">
float4: @"More than 8 digits" <ParseError "#xf\"123456789a\"">
float5: @"Invalid chars" <ParseError "#xf\"12zz5678\"">
float6: @"Positive infinity" <Test #x"827f800000" #xf"7f800000">
float7: @"Negative infinity" <Test #x"82ff800000" #xf"ff800000">
float8: @"+NaN" <Test #x"827f800001" #xf"7f800001">
float9: @"+NaN" <Test #x"827f800111" #xf"7f800111">
float10: @"-NaN" <Test #x"82ff800001" #xf"ff800001">
float11: @"-NaN" <Test #x"82ff800111" #xf"ff800111">
int-257: <Test #x"a1feff" -257>
int-256: <Test #x"a1ff00" -256>
int-255: <Test #x"a1ff01" -255>
@ -89,10 +115,13 @@
int-2: <Test #x"9e" -2>
int-1: <Test #x"9f" -1>
int0: <Test #x"90" 0>
int+0: <Test #x"90" +0>
int-0: <Test #x"90" -0>
int1: <Test #x"91" 1>
int12: <Test #x"9c" 12>
int13: <Test #x"a00d" 13>
int127: <Test #x"a07f" 127>
int+127: <Test #x"a07f" +127>
int128: <Test #x"a10080" 128>
int255: <Test #x"a100ff" 255>
int256: <Test #x"a10100" 256>
@ -112,6 +141,8 @@
list8: @"Missing close bracket" <ParseShort "[">
list9: @"Unexpected close bracket" <ParseError "]">
list10: @"Missing end byte" <DecodeShort #x"b58080">
list11: <Test #x"b59184" [01]>
list12: <Test #x"b59c84" [12]>
noinput0: @"No input at all" <DecodeEOF #x"">
embed0: <Test #x"8690" #!0>
embed1: <Test #x"868690" #!#!0>
@ -138,17 +169,22 @@
string5: <Test #x"b104f09d849e" "\uD834\uDD1E">
symbol0: <Test #x"b300" ||>
symbol2: <Test #x"b30568656c6c6f" hello>
symbol3: <Test #x"b305312d322d33" 1-2-3>
symbol4: <Test #x"b305612d622d63" a-b-c>
symbol5: <Test #x"b305612b622b63" a+b+c>
symbol6: <Test #x"b3012b" +>
symbol7: <Test #x"b3032b2b2b" +++>
symbol8: <Test #x"b3012d" ->
symbol9: <Test #x"b3032d2d2d" --->
symbol10: <Test #x"b3022d61" -a>
symbol11: <Test #x"b3042d2d2d61" ---a>
symbol12: <Test #x"b3042d2d2d31" ---1>
symbol13: <Test #x"b3042b312e78" +1.x>
tag0: @"Unexpected end tag" <DecodeError #x"84">
tag1: @"Invalid tag" <DecodeError #x"10">
tag2: @"Invalid tag" <DecodeError #x"61b10110">
whitespace0: @"Leading spaces have to eventually yield something" <ParseShort " ">
whitespace1: @"No input at all" <ParseEOF "">
value1: <Test #"\xB2\x06corymb" #=#"\xB2\x06corymb">
value2: <Test #"\x81" #=#"\x81">
value3: <Test #"\x81" #=#[gQ]>
value4: <Test #"\x81" #=#[gQ==]>
value5: <Test #"\x81" #= #[gQ==]>
value6: <Test #x"b591929384" #=#x"b591929384">
longlist14: <Test #x"b5808080808080808080808080808084"
[#f #f #f #f #f

View File

@ -17,6 +17,8 @@
(require racket/dict)
(require racket/set)
(require (only-in racket/port with-output-to-string))
(require (only-in racket/math nan? infinite?))
(require (only-in file/sha1 bytes->hex-string))
(define PIPE #\|)
@ -132,6 +134,13 @@
(write-binary-stringlike v)
(write-binary-base64 outer-distance v)))))
(define (write-float v byte-count hextype suffix)
(if (or (nan? v) (infinite? v))
(! "#x~a\"~a\""
hextype
(bytes->hex-string (real->floating-point-bytes v byte-count #t)))
(! "~v~a" v suffix)))
(define (write-value distance v)
(match v
[(annotated annotations _ item)
@ -143,8 +152,8 @@
(write-value distance item)]
[#f (! "#f")]
[#t (! "#t")]
[(float v) (! "~vf" v)]
[(? flonum?) (! "~v" v)]
[(float v) (write-float v 4 "f" "f")]
[(? flonum?) (write-float v 8 "d" "")]
[(? integer? x) (! "~v" v)]
[(? string?)
(! "\"")

View File

@ -42,7 +42,8 @@ Any `Value` may be preceded by whitespace.
Value = ws (Record / Collection / Atom / Embedded)
Collection = Sequence / Dictionary / Set
Atom = Boolean / String / ByteString / QuotedSymbol / SymbolOrNumber
Atom = Boolean / String / ByteString /
QuotedSymbol / SymbolOrNumber
Each `Record` is an angle-bracket enclosed grouping of its
label-`Value` followed by its field-`Value`s.
@ -211,13 +212,14 @@ represented as raw hexadecimal strings similar to hexadecimal
syntax whereever convenient, even for values representable using the
grammar above.[^rationale-no-general-machine-syntax]
Float =/ "#xf" %x22 8HEXDIG %x22
Double =/ "#xd" %x22 16HEXDIG %x22
Value =/ HexFloat / HexDouble
HexFloat = "#xf" %x22 4(ws 2HEXDIG) ws %x22
HexDouble = "#xd" %x22 8(ws 2HEXDIG) ws %x22
[^rationale-no-general-machine-syntax]: **Rationale.** Previous versions
of this specification included an escape to the [machine-oriented
binary syntax](preserves-binary.html) by prefixing a `ByteString`
containing the binary representation of the `Value` with `#=`. The only
containing the binary representation of a `Value` with `#=`. The only
true need for this feature was to represent otherwise-unrepresentable
floating-point values. Instead, this specification allows such
floating-point values to be written directly. Removing the `#=` syntax

Binary file not shown.

View File

@ -74,9 +74,35 @@
dict3: @"Duplicate key" <ParseError "{ a: 1, a: 2 }">
dict4: @"Unexpected close brace" <ParseError "}">
dict5: @"Missing value" <DecodeError #x"b7 91 92 93 84">
double0: <Test #x"830000000000000000" 0.0>
double+0: <Test #x"830000000000000000" +0.0>
double-0: <Test #x"838000000000000000" -0.0>
double1: <Test #x"833ff0000000000000" 1.0>
double2: <Test #x"83fe3cb7b759bf0426" -1.202e300>
double3: <Test #x"83123456789abcdef0" #xd"123456789abcdef0">
double4: @"Fewer than 16 digits" <ParseError "#xd\"12345678\"">
double5: @"More than 16 digits" <ParseError "#xd\"123456789abcdef012\"">
double6: @"Invalid chars" <ParseError "#xd\"12zz56789abcdef0\"">
double7: @"Positive infinity" <Test #x"837ff0000000000000" #xd"7ff0000000000000">
double8: @"Negative infinity" <Test #x"83fff0000000000000" #xd"fff0000000000000">
double9: @"-NaN" <Test #x"83fff0000000000001" #xd"fff0000000000001">
double10: @"-NaN" <Test #x"83fff0000000000111" #xd"fff0000000000111">
double11: @"+NaN" <Test #x"837ff0000000000001" #xd"7ff0000000000001">
double12: @"+NaN" <Test #x"837ff0000000000111" #xd"7ff0000000000111">
float0: <Test #x"8200000000" 0.0f>
float+0: <Test #x"8200000000" +0.0f>
float-0: <Test #x"8280000000" -0.0f>
float1: <Test #x"823f800000" 1.0f>
float2: <Test #x"8212345678" #xf"12345678">
float3: @"Fewer than 8 digits" <ParseError "#xf\"123456\"">
float4: @"More than 8 digits" <ParseError "#xf\"123456789a\"">
float5: @"Invalid chars" <ParseError "#xf\"12zz5678\"">
float6: @"Positive infinity" <Test #x"827f800000" #xf"7f800000">
float7: @"Negative infinity" <Test #x"82ff800000" #xf"ff800000">
float8: @"+NaN" <Test #x"827f800001" #xf"7f800001">
float9: @"+NaN" <Test #x"827f800111" #xf"7f800111">
float10: @"-NaN" <Test #x"82ff800001" #xf"ff800001">
float11: @"-NaN" <Test #x"82ff800111" #xf"ff800111">
int-257: <Test #x"a1feff" -257>
int-256: <Test #x"a1ff00" -256>
int-255: <Test #x"a1ff01" -255>
@ -89,10 +115,13 @@
int-2: <Test #x"9e" -2>
int-1: <Test #x"9f" -1>
int0: <Test #x"90" 0>
int+0: <Test #x"90" +0>
int-0: <Test #x"90" -0>
int1: <Test #x"91" 1>
int12: <Test #x"9c" 12>
int13: <Test #x"a00d" 13>
int127: <Test #x"a07f" 127>
int+127: <Test #x"a07f" +127>
int128: <Test #x"a10080" 128>
int255: <Test #x"a100ff" 255>
int256: <Test #x"a10100" 256>
@ -112,6 +141,8 @@
list8: @"Missing close bracket" <ParseShort "[">
list9: @"Unexpected close bracket" <ParseError "]">
list10: @"Missing end byte" <DecodeShort #x"b58080">
list11: <Test #x"b59184" [01]>
list12: <Test #x"b59c84" [12]>
noinput0: @"No input at all" <DecodeEOF #x"">
embed0: <Test #x"8690" #!0>
embed1: <Test #x"868690" #!#!0>
@ -138,17 +169,22 @@
string5: <Test #x"b104f09d849e" "\uD834\uDD1E">
symbol0: <Test #x"b300" ||>
symbol2: <Test #x"b30568656c6c6f" hello>
symbol3: <Test #x"b305312d322d33" 1-2-3>
symbol4: <Test #x"b305612d622d63" a-b-c>
symbol5: <Test #x"b305612b622b63" a+b+c>
symbol6: <Test #x"b3012b" +>
symbol7: <Test #x"b3032b2b2b" +++>
symbol8: <Test #x"b3012d" ->
symbol9: <Test #x"b3032d2d2d" --->
symbol10: <Test #x"b3022d61" -a>
symbol11: <Test #x"b3042d2d2d61" ---a>
symbol12: <Test #x"b3042d2d2d31" ---1>
symbol13: <Test #x"b3042b312e78" +1.x>
tag0: @"Unexpected end tag" <DecodeError #x"84">
tag1: @"Invalid tag" <DecodeError #x"10">
tag2: @"Invalid tag" <DecodeError #x"61b10110">
whitespace0: @"Leading spaces have to eventually yield something" <ParseShort " ">
whitespace1: @"No input at all" <ParseEOF "">
value1: <Test #"\xB2\x06corymb" #=#"\xB2\x06corymb">
value2: <Test #"\x81" #=#"\x81">
value3: <Test #"\x81" #=#[gQ]>
value4: <Test #"\x81" #=#[gQ==]>
value5: <Test #"\x81" #= #[gQ==]>
value6: <Test #x"b591929384" #=#x"b591929384">
longlist14: <Test #x"b5808080808080808080808080808084"
[#f #f #f #f #f