Error processing request

Parameters

CONTENT_LENGTH0
REQUEST_METHODGET
REQUEST_URI/revision/Alternative+JSON?V=12
QUERY_STRINGV=12
CONTENT_TYPE
DOCUMENT_URI/revision/Alternative+JSON
DOCUMENT_ROOT/var/www/nikit/nikit/nginx/../docroot
SCGI1
SERVER_PROTOCOLHTTP/1.1
HTTPSon
REMOTE_ADDR172.70.126.35
REMOTE_PORT62582
SERVER_PORT4443
SERVER_NAMEwiki.tcl-lang.org
HTTP_HOSTwiki.tcl-lang.org
HTTP_CONNECTIONKeep-Alive
HTTP_ACCEPT_ENCODINGgzip, br
HTTP_X_FORWARDED_FOR18.218.55.14
HTTP_CF_RAY87bab4b93add2919-ORD
HTTP_X_FORWARDED_PROTOhttps
HTTP_CF_VISITOR{"scheme":"https"}
HTTP_ACCEPT*/*
HTTP_USER_AGENTMozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; [email protected])
HTTP_CF_CONNECTING_IP18.218.55.14
HTTP_CDN_LOOPcloudflare
HTTP_CF_IPCOUNTRYUS

Body


Error

Unknow state transition: LINE -> END

-code

1

-level

0

-errorstack

INNER {returnImm {Unknow state transition: LINE -> END} {}} CALL {my render_wikit {Alternative JSON} \[AMG\]:\ \[\[json::encode\]\]\ and\ \[\[json::decode\]\]\ convert\ between\ a\ tagged\ data\ format\ and\ JSON.\ \ \[\[json::schema\]\]\ and\ \[\[json::values\]\]\ split\ the\ tagged\ data\ format\ into\ the\ schema\ and\ values\ components,\ and\ \[\[json::unite\]\]\ combine\ the\ schema\ and\ value\ components\ into\ the\ tagged\ data\ format.\n\n**Types**\n\nThe\ available\ type\ tags\ are:\n\n\ \ \ array\ \ \ :\ \ \ List\ of\ elements.\n\ \ \ object\ \ \ :\ \ \ Key-value\ dictionary\ of\ elements.\n\ \ \ string\ \ \ :\ \ \ Arbitrary\ string\ value.\n\ \ \ number\ \ \ :\ \ \ Integer\ and\ real\ numeric\ value.\n\ \ \ literal\ \ \ :\ \ \ false,\ null,\ or\ true.\n\ \ \ raw\ \ \ :\ \ \ Preformatted\ JSON\ text.\n\nArray\ and\ object\ type\ composition\ is\ supported\ in\ two\ ways.\ \ If\ the\ type\ is\ array\ or\ object,\ each\ element\ is\ represented\ as\ a\ two-element\ list,\ being\ the\ type\ and\ the\ value.\ \ This\ gets\ quite\ cumbersome\ when\ the\ values\ all\ have\ uniform\ type,\ so\ the\ outer\ type\ may\ be\ a\ two-element\ list,\ the\ second\ of\ which\ is\ the\ type\ used\ for\ all\ values.\ \ More\ deeply\ nested\ data\ structures\ can\ be\ defined\ either\ by\ further\ nesting\ the\ second\ type\ element\ or\ by\ flattening\ the\ list.\n\n**Examples**\n\n***Format***\n\n%|JSON|Tagged\ Data|%\n&|`\"hello\"`|`string\ hello`|&\n&|`42`|`number\ 42`|&\n&|`null`|`literal\ null`|&\n&|`\[\[\"hello\",42,null\]\]`|`array\ \{\{string\ hello\}\ \{number\ 42\}\ \{literal\ null\}\}`|&\n&|`\[\[\[\[1,2\]\],\[\[3,4\]\]\]\]`|`\{array\ array\ number\}\ \{\{1\ 2\}\ \{3\ 4\}\}`|&\n&|`\{\"a\":1,\"b\":2\}`|`\{object\ number\}\ \{a\ 1\ b\ 2\}`|&\n&|`\{\"a\":1,\"b\":2\}`|`raw\ \{\{\"a\":1,\"b\":2\}\}`|&\n\n***Usage***\n\n======none\n%\ json::encode\ \{string\ hello\}\n\"hello\"\n%\ json::encode\ \{number\ 42\}\n42\n%\ json::encode\ \{literal\ null\}\nnull\n%\ json::encode\ \{array\ \{\{string\ hello\}\ \{number\ 42\}\ \{literal\ null\}\}\}\n\[\"hello\",42,null\]\n%\ json::encode\ \{object\ \{foo\ \{string\ hello\}\ bar\ \{number\ 42\}\ quux\ \{literal\ null\}\}\}\n\{\"foo\":\"hello\",\"bar\":42,\"quux\":null\}\n%\ json::encode\ \{array\ \{\{array\ \{\{number\ 1\}\ \{number\ 2\}\}\}\ \{array\ \{\{number\ 3\}\ \{number\ 4\}\}\}\}\}\n\[\[1,2\],\[3,4\]\]\n%\ json::encode\ \{\{array\ \{array\ number\}\}\ \{\{1\ 2\}\ \{3\ 4\}\}\}\n\[\[1,2\],\[3,4\]\]\n%\ json::encode\ \{\{array\ array\ number\}\ \{\{1\ 2\}\ \{3\ 4\}\}\}\n\[\[1,2\],\[3,4\]\]\n%\ json::encode\ \{\{array\ array\ string\}\ \{\{1\ 2\}\ \{3\ 4\}\}\}\n\[\[\"1\",\"2\"\],\[\"3\",\"4\"\]\]\n%\ json::encode\ \{\{object\ object\ string\}\ \{name\ \{first\ Andy\ last\ Goth\}\ address\ \{web\ http://tcl.tk/\}\}\}\n\{\"name\":\{\"first\":\"Andy\",\"last\":\"Goth\"\},\"address\":\{\"web\":\"http://tcl.tk/\"\}\}\n%\ json::decode\ \{\"hello\"\}\nstring\ hello\n%\ json::decode\ 42\nnumber\ 42\n%\ json::decode\ null\nliteral\ null\n%\ json::decode\ \{\[\"hello\",42,null\]\}\narray\ \{\{string\ hello\}\ \{number\ 42\}\ \{literal\ null\}\}\n%\ json::decode\ \{\{\"foo\":\"hello\",\"bar\":42,\"quux\":null\}\}\nobject\ \{foo\ \{string\ hello\}\ bar\ \{number\ 42\}\ quux\ \{literal\ null\}\}\n%\ json::decode\ \{\[\[1,2\],\[3,4\]\]\}\narray\ \{\{array\ \{\{number\ 1\}\ \{number\ 2\}\}\}\ \{array\ \{\{number\ 3\}\ \{number\ 4\}\}\}\}\n%\ json::decode\ \{\{\"name\":\{\"first\":\"Andy\",\"last\":\"Goth\"\},\"address\":\{\"web\":\"http://tcl.tk/\"\}\}\}\nobject\ \{name\ \{object\ \{first\ \{string\ Andy\}\ last\ \{string\ Goth\}\}\}\ address\ \{object\ \{web\ \{string\ http://tcl.tk/\}\}\}\}\n%\ json::schema\ \{\{\"name\":\{\"first\":\"Andy\",\"last\":\"Goth\"\},\"address\":\{\"web\":\"http://tcl.tk/\"\}\}\}\nobject\ \{name\ \{object\ \{first\ string\}\}\ last\ string\}\ address\ \{object\ \{web\ string\}\}\n%\ json::values\ \{\{\"name\":\{\"first\":\"Andy\",\"last\":\"Goth\"\},\"address\":\{\"web\":\"http://tcl.tk/\"\}\}\}\nname\ \{first\ Andy\ last\ Goth\}\ address\ \{web\ http://tcl.tk/\}\n%\ json::schema\ \[json::decode\ \{\"foo\":\"hello\",\"bar\":42,\"quux\":null\}\]\nobject\ \{foo\ string\ bar\ number\ quux\ literal\}\n%\ json::values\ \[json::decode\ \{\"foo\":\"hello\",\"bar\":42,\"quux\":null\}\]\nfoo\ hello\ bar\ 42\ quux\ null\n%\ json::unite\ \{object\ \{foo\ string\ bar\ number\ quux\ literal\}\}\ \{foo\ hello\ bar\ 42\ quux\ null\}\n\{object\ \{foo\ \{string\ hello\}\ bar\ \{number\ 42\}\ quux\ \{literal\ null\}\}\}\n%\ json::encode\ \[json::unite\ \{object\ \{foo\ string\ bar\ number\ quux\ literal\}\}\ \{foo\ hello\ bar\ 42\ quux\ null\}\]\n\{\"foo\":\"hello\",\"bar\":42,\"quux\":null\}\n======\n\n**Implementation**\n\nFirst,\ create\ the\ namespace.\n\n======none\nnamespace\ eval\ ::json\ \{\}\n======\n\n***\[\[json::encode\]\]***\n\n======none\n#\ ::json::encode\ --\n#\ Encodes\ data\ in\ the\ JSON\ format\ per\ https://tools.ietf.org/html/rfc7159.\nproc\ ::json::encode\ \{data\}\ \{\n\ \ \ \ #\ Extract\ type\ and\ value\ from\ data\ argument.\n\ \ \ \ if\ \{\[llength\ \$data\]\ !=\ 2\}\ \{\n\ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ data:\ must\ be\ a\ two-element\ list\ consisting\ of\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ type\ and\ value\"\n\ \ \ \ \}\n\ \ \ \ lassign\ \$data\ type\ value\n\n\ \ \ \ #\ Extract\ top\ and\ subtype\ from\ type\ element.\n\ \ \ \ set\ toptype\ \[lindex\ \$type\ 0\]\n\ \ \ \ if\ \{\[llength\ \$type\]\ >=\ 2\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$type\]\ ==\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ subtype\ \[lindex\ \$type\ 1\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ subtype\ \[lrange\ \$type\ 1\ end\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\$toptype\ ni\ \{array\ object\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ toptype\ \{\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Perform\ type-specific\ JSON\ encoding.\n\ \ \ \ switch\ \$toptype\ \{\n\ \ \ \ array\ \{\n\ \ \ \ \ \ \ \ #\ Recursively\ encode\ each\ array\ element.\ \ If\ a\ subtype\ was\ specified,\ it\n\ \ \ \ \ \ \ \ #\ is\ shared\ between\ all\ elements.\ \ Otherwise,\ each\ element\ is\ itself\ a\n\ \ \ \ \ \ \ \ #\ two-element\ list\ consisting\ of\ type\ and\ value.\n\ \ \ \ \ \ \ \ set\ comma\ \{\}\n\ \ \ \ \ \ \ \ set\ result\ \\\[\n\ \ \ \ \ \ \ \ foreach\ element\ \$value\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ append\ result\ \$comma\n\ \ \ \ \ \ \ \ \ \ \ \ set\ comma\ ,\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ subtype\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ result\ \[encode\ \[list\ \$subtype\ \$element\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ result\ \[encode\ \$element\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ append\ result\ \\\]\n\ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \}\ object\ \{\n\ \ \ \ \ \ \ \ #\ Recursively\ encode\ each\ object\ key\ and\ element.\ \ Keys\ are\ always\n\ \ \ \ \ \ \ \ #\ strings.\ \ If\ a\ subtype\ was\ specified,\ it\ is\ shared\ between\ all\n\ \ \ \ \ \ \ \ #\ elements.\ \ Otherwise,\ each\ element\ is\ itself\ a\ two-element\ list\n\ \ \ \ \ \ \ \ #\ consisting\ of\ type\ and\ underlying\ data\ value.\n\ \ \ \ \ \ \ \ set\ comma\ \{\}\n\ \ \ \ \ \ \ \ set\ result\ \\\{\n\ \ \ \ \ \ \ \ foreach\ \{key\ element\}\ \$value\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ append\ result\ \$comma\n\ \ \ \ \ \ \ \ \ \ \ \ set\ comma\ ,\n\ \ \ \ \ \ \ \ \ \ \ \ append\ result\ \[encode\ \[list\ string\ \$key\]\]\ :\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ subtype\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ result\ \[encode\ \[list\ \$subtype\ \$element\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ result\ \[encode\ \$element\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ append\ result\ \\\}\n\ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \}\ string\ \{\n\ \ \ \ \ \ \ \ #\ Encode\ the\ minimal\ set\ of\ required\ escape\ sequences.\n\ \ \ \ \ \ \ \ return\ \\\"\[string\ map\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \\x00\ \\\\u0000\ \ \ \ \\x01\ \\\\u0001\ \ \ \ \\x02\ \\\\u0002\ \ \ \ \\x03\ \\\\u0003\n\ \ \ \ \ \ \ \ \ \ \ \ \\x04\ \\\\u0004\ \ \ \ \\x05\ \\\\u0005\ \ \ \ \\x06\ \\\\u0006\ \ \ \ \\x07\ \\\\u0007\n\ \ \ \ \ \ \ \ \ \ \ \ \\x08\ \\\\u0008\ \ \ \ \\x09\ \\\\u0009\ \ \ \ \\x0a\ \\\\u000a\ \ \ \ \\x0b\ \\\\u000b\n\ \ \ \ \ \ \ \ \ \ \ \ \\x0c\ \\\\u000c\ \ \ \ \\x0d\ \\\\u000d\ \ \ \ \\x0e\ \\\\u000e\ \ \ \ \\x0f\ \\\\u000f\n\ \ \ \ \ \ \ \ \ \ \ \ \\x10\ \\\\u0010\ \ \ \ \\x11\ \\\\u0011\ \ \ \ \\x12\ \\\\u0012\ \ \ \ \\x13\ \\\\u0013\n\ \ \ \ \ \ \ \ \ \ \ \ \\x14\ \\\\u0014\ \ \ \ \\x15\ \\\\u0015\ \ \ \ \\x16\ \\\\u0016\ \ \ \ \\x17\ \\\\u0017\n\ \ \ \ \ \ \ \ \ \ \ \ \\x18\ \\\\u0018\ \ \ \ \\x19\ \\\\u0019\ \ \ \ \\x1a\ \\\\u001a\ \ \ \ \\x1b\ \\\\u001b\n\ \ \ \ \ \ \ \ \ \ \ \ \\x1c\ \\\\u001c\ \ \ \ \\x1d\ \\\\u001d\ \ \ \ \\x1e\ \\\\u001e\ \ \ \ \\x1f\ \\\\u001f\n\ \ \ \ \ \ \ \ \ \ \ \ \\\\\ \ \ \\\\\\\\\ \ \ \ \ \ \ \\\"\ \ \ \\\\\\\"\n\ \ \ \ \ \ \ \ \}\ \$value\]\\\"\n\ \ \ \ \}\ number\ \{\n\ \ \ \ \ \ \ \ #\ Attempt\ to\ normalize\ the\ number\ to\ comply\ with\ the\ JSON\ standard.\n\ \ \ \ \ \ \ \ regsub\ \{^\[\\f\\n\\r\\t\\v\ \]+\}\ \$value\ \{\}\ result\ \ \ \ \ \;#\ Strip\ leading\ space.\n\ \ \ \ \ \ \ \ regsub\ \{\[\\f\\n\\r\\t\\v\ \]+\$\}\ \$result\ \{\}\ result\ \ \ \ \;#\ Strip\ trailing\ space.\n\ \ \ \ \ \ \ \ regsub\ \{^\\+(?=\[\\d.\])\}\ \$result\ \{\}\ result\ \ \ \ \ \ \ \;#\ Strip\ leading\ plus.\n\ \ \ \ \ \ \ \ regsub\ \{^(-?)0+(?=\\d)\}\ \$result\ \{\\1\}\ result\ \ \ \ \;#\ Strip\ leading\ zeroes.\n\ \ \ \ \ \ \ \ regsub\ \{(\\.\\d*\[1-9\])0+\}\ \$result\ \{\\1\}\ result\ \ \ \;#\ Strip\ trailing\ zeroes.\n\ \ \ \ \ \ \ \ regsub\ \{E\}\ \$result\ \{e\}\ result\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \;#\ Normalize\ exponent,\ 1.\n\ \ \ \ \ \ \ \ regsub\ \{^(-?\\d+)e\}\ \$result\ \{\\1.0e\}\ result\ \ \ \ \ \;#\ Normalize\ exponent,\ 2.\n\ \ \ \ \ \ \ \ regsub\ \{\\.e\}\ \$result\ \{.0e\}\ result\ \ \ \ \ \ \ \ \ \ \ \ \ \;#\ Normalize\ exponent,\ 3.\n\ \ \ \ \ \ \ \ regsub\ \{e(\\d)\}\ \$result\ \{e+\\1\}\ result\ \ \ \ \ \ \ \ \ \ \;#\ Normalize\ exponent,\ 4.\n\ \ \ \ \ \ \ \ regsub\ \{(^|-)\\.(?=\\d)\}\ \$result\ \{\\10.\}\ result\ \ \;#\ Prefix\ leading\ dot.\n\ \ \ \ \ \ \ \ regsub\ \{(\\d)\\.(?=\\D|\$)\}\ \$result\ \{\\1.0\}\ result\ \;#\ Suffix\ trailing\ dot.\n\ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{^-?(?:0|\[1-9\]\\d*)(?:\\.\\d+)?(?:\[eE\]\[-+\]?\\d+)?\$\}\ \$result\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ number\ \\\"\$value\\\":\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ see\ https://tools.ietf.org/html/rfc7159#section-6\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \}\ literal\ \{\n\ \ \ \ \ \ \ \ #\ The\ only\ valid\ literals\ are\ false,\ null,\ and\ true.\n\ \ \ \ \ \ \ \ if\ \{\$value\ ni\ \{false\ null\ true\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ literal\ \\\"\$value\\\":\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ must\ be\ false,\ null,\ or\ true\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$value\n\ \ \ \ \}\ encoded\ \{\n\ \ \ \ \ \ \ \ #\ Raw\ data.\ \ The\ caller\ must\ supply\ correctly\ formatted\ JSON.\n\ \ \ \ \ \ \ \ return\ \$value\n\ \ \ \ \}\ decoded\ \{\n\ \ \ \ \ \ \ \ #\ Nested\ decoded\ data.\n\ \ \ \ \ \ \ \ encode\ \$value\n\ \ \ \ \}\ default\ \{\n\ \ \ \ \ \ \ \ #\ Invalid\ type.\n\ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ type\ \\\"\$type\\\":\ must\ be\ array,\ object,\ string,\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ number,\ literal,\ encoded,\ decoded,\ or\ \{array|object\ ?...?\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subtype\},\ where\ subtype\ is\ recursively\ any\ valid\ JSON\ type\"\n\ \ \ \ \}\}\n\}\n======\n\n***\[\[json::decode\]\]***\n\n======none\n#\ ::json::decode\ --\n#\ Decodes\ data\ from\ the\ JSON\ format\ per\ https://tools.ietf.org/html/rfc7159.\n#\ The\ optional\ indexVar\ argument\ is\ the\ name\ of\ a\ variable\ that\ holds\ the\ index\n#\ at\ which\ decoding\ begins\ (defaults\ to\ 0\ if\ the\ variable\ doesn't\ exist)\ and\n#\ will\ hold\ the\ index\ immediately\ following\ the\ end\ of\ the\ decoded\ element.\ \ If\n#\ indexVar\ is\ not\ specified,\ the\ entire\ JSON\ input\ is\ decoded,\ and\ it\ is\ an\n#\ error\ for\ it\ to\ be\ followed\ by\ any\ non-whitespace\ characters.\nproc\ ::json::decode\ \{json\ \{indexVar\ \{\}\}\}\ \{\n\ \ \ \ #\ Link\ to\ the\ caller's\ index\ variable.\n\ \ \ \ if\ \{\$indexVar\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ upvar\ 1\ \$indexVar\ index\n\ \ \ \ \}\n\n\ \ \ \ #\ By\ default,\ start\ decoding\ at\ the\ start\ of\ the\ input.\n\ \ \ \ if\ \{!\[info\ exists\ index\]\}\ \{\n\ \ \ \ \ \ \ \ set\ index\ 0\n\ \ \ \ \}\n\n\ \ \ \ #\ Skip\ leading\ whitespace.\ \ Return\ empty\ at\ end\ of\ input.\n\ \ \ \ if\ \{!\[regexp\ -indices\ -start\ \$index\ \{\[^\\t\\n\\r\ \]\}\ \$json\ range\]\}\ \{\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\ \ \ \ set\ index\ \[lindex\ \$range\ 0\]\n\n\ \ \ \ #\ The\ first\ character\ determines\ the\ JSON\ element\ type.\n\ \ \ \ switch\ \[string\ index\ \$json\ \$index\]\ \{\n\ \ \ \ \\\"\ \{\n\ \ \ \ \ \ \ \ #\ JSON\ strings\ start\ with\ double\ quote.\n\ \ \ \ \ \ \ \ set\ type\ string\n\n\ \ \ \ \ \ \ \ #\ The\ value\ is\ the\ text\ between\ matching\ double\ quotes.\n\ \ \ \ \ \ \ \ if\ \{!\[regexp\ -indices\ -start\ \$index\ \{\\A\\\"((?:\[^\"\]|\\\\.)*)\\\"\}\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$json\ range\ sub\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ error\ \"invalid\ JSON\ string\ at\ index\ \$index:\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ must\ end\ with\ close\ quote\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ value\ \[string\ range\ \$json\ \{*\}\$sub\]\n\n\ \ \ \ \ \ \ \ #\ Process\ all\ backslash\ substitutions\ in\ the\ value.\n\ \ \ \ \ \ \ \ set\ start\ 0\n\ \ \ \ \ \ \ \ while\ \{\[regexp\ -indices\ -start\ \$start\ \{\\\\u\[\[:xdigit:\]\]\{4\}|\\\\\[^u\]\}\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$value\ sub\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ char\ \[string\ index\ \$value\ \[expr\ \{\[lindex\ \$sub\ 0\]\ +\ 1\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ switch\ \$char\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ u\ \{set\ char\ \[subst\ \[string\ range\ \$value\ \{*\}\$sub\]\]\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ b\ \{set\ char\ \\b\}\ f\ \{set\ char\ \\f\}\ n\ \{set\ char\ \\n\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ r\ \{set\ char\ \\r\}\ t\ \{set\ char\ \\t\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ value\ \[string\ replace\ \$value\ \{*\}\$sub\ \$char\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ start\ \[expr\ \{\[lindex\ \$sub\ 0\]\ +\ 1\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ \\\{\ -\ \\\[\ \{\n\ \ \ \ \ \ \ \ #\ JSON\ objects/arrays\ start\ with\ open\ brace/bracket.\n\ \ \ \ \ \ \ \ if\ \{\[string\ index\ \$json\ \$index\]\ eq\ \"\\\{\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ type\ object\n\ \ \ \ \ \ \ \ \ \ \ \ set\ endRe\ \{\\A\[\\t\\n\\r\ \]*\\\}\}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ charName\ brace\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ type\ array\n\ \ \ \ \ \ \ \ \ \ \ \ set\ endRe\ \{\\A\[\\t\\n\\r\ \]*\\\]\}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ charName\ bracket\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ value\ \{\}\n\ \ \ \ \ \ \ \ incr\ index\n\n\ \ \ \ \ \ \ \ #\ Loop\ until\ close\ brace/bracket\ is\ encountered.\n\ \ \ \ \ \ \ \ while\ \{!\[regexp\ -indices\ -start\ \$index\ \$endRe\ \$json\ range\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Each\ element\ other\ than\ the\ first\ is\ preceded\ by\ comma.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$value\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[regexp\ -indices\ -start\ \$index\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{\\A\[\\t\\n\\r\ \]*,\}\ \$json\ range\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ error\ \"invalid\ JSON\ \$type\ at\ index\ \$index:\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ element\ not\ followed\ by\ comma\ or\ close\ \$charName\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ index\ \[expr\ \{\[lindex\ \$range\ 1\]\ +\ 1\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ For\ objects,\ get\ key\ and\ confirm\ it\ is\ followed\ by\ colon.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$type\ eq\ \"object\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ key\ \[decode\ \$json\ index\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[llength\ \$key\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ error\ \"invalid\ JSON\ object\ at\ index\ \$index:\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ must\ end\ with\ close\ brace\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\[lindex\ \$key\ 0\]\ ne\ \"string\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ error\ \"invalid\ JSON\ object\ at\ index\ \$index:\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ key\ type\ is\ \\\"\[lindex\ \$key\ 0\]\\\",\ must\ be\ string\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{!\[regexp\ -indices\ -start\ \$index\ \{\\A\[\\t\\n\\r\ \]*:\}\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$json\ range\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ error\ \"invalid\ JSON\ object\ at\ index\ \$index:\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ key\ not\ followed\ by\ colon\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ index\ \[expr\ \{\[lindex\ \$range\ 1\]\ +\ 1\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ value\ \[lindex\ \$key\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Get\ element\ value.\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ value\ \[decode\ \$json\ index\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ t\ -\ f\ -\ n\ \{\n\ \ \ \ \ \ \ \ #\ JSON\ literals\ are\ true,\ false,\ or\ null.\n\ \ \ \ \ \ \ \ set\ type\ literal\n\ \ \ \ \ \ \ \ if\ \{!\[regexp\ -indices\ -start\ \$index\ \{(?:true|false|null)\\M\}\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$json\ range\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ error\ \"invalid\ JSON\ literal\ at\ index\ \$index\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ value\ \[string\ range\ \$json\ \{*\}\$range\]\n\ \ \ \ \}\ -\ -\ +\ -\ 0\ -\ 1\ -\ 2\ -\ 3\ -\ 4\ -\ 5\ -\ 6\ -\ 7\ -\ 8\ -\ 9\ -\ .\ \{\n\ \ \ \ \ \ \ \ #\ JSON\ numbers\ are\ integers\ or\ real\ numbers.\n\ \ \ \ \ \ \ \ set\ type\ number\n\ \ \ \ \ \ \ \ if\ \{!\[regexp\ -indices\ -start\ \$index\ --\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{-?(?:0|\[1-9\]\\d*)(?:\\.\\d+)?(?:\[eE\]\[-+\]?\\d+)?\\M\}\ \$json\ range\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ error\ \"invalid\ JSON\ number\ at\ index\ \$index\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ value\ \[string\ range\ \$json\ \{*\}\$range\]\n\ \ \ \ \}\ default\ \{\n\ \ \ \ \ \ \ \ #\ JSON\ allows\ only\ the\ above-listed\ types.\n\ \ \ \ \ \ \ \ return\ -code\ error\ \"invalid\ JSON\ data\ at\ index\ \$index\"\n\ \ \ \ \}\}\n\n\ \ \ \ #\ Continue\ decoding\ after\ the\ last\ character\ matched\ above.\n\ \ \ \ set\ index\ \[expr\ \{\[lindex\ \$range\ 1\]\ +\ 1\}\]\n\n\ \ \ \ #\ When\ performing\ a\ full\ decode,\ ensure\ only\ whitespace\ appears\ at\ end.\n\ \ \ \ if\ \{\$indexVar\ eq\ \{\}\ &&\ \[regexp\ -start\ \$index\ \{\[^\\t\\n\\r\\\ \]\}\ \$json\]\}\ \{\n\ \ \ \ \ \ \ \ return\ -code\ error\ \"junk\ at\ end\ of\ JSON\"\n\ \ \ \ \}\n\n\ \ \ \ #\ Return\ the\ type\ and\ value.\n\ \ \ \ list\ \$type\ \$value\n\}\n======\n\n***\[\[json::schema\]\]***\n\n======none\n#\ ::json::schema\ --\n#\ Extracts\ JSON\ type\ information\ from\ the\ output\ of\ \[json::decode\].\nproc\ ::json::schema\ \{data\}\ \{\n\ \ \ \ #\ Extract\ type\ and\ value\ from\ data\ argument.\n\ \ \ \ if\ \{\[llength\ \$data\]\ !=\ 2\}\ \{\n\ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ data:\ must\ be\ a\ two-element\ list\ consisting\ of\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ type\ and\ value\"\n\ \ \ \ \}\n\ \ \ \ lassign\ \$data\ type\ value\n\n\ \ \ \ #\ Extract\ top\ and\ subtype\ from\ type\ element.\n\ \ \ \ set\ toptype\ \[lindex\ \$type\ 0\]\n\ \ \ \ if\ \{\[llength\ \$type\]\ >=\ 2\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$type\]\ ==\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ subtype\ \[lindex\ \$type\ 1\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ subtype\ \[lrange\ \$type\ 1\ end\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\$toptype\ ni\ \{array\ object\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ toptype\ \{\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Perform\ type-specific\ JSON\ processing.\n\ \ \ \ switch\ \$toptype\ \{\n\ \ \ \ array\ \{\n\ \ \ \ \ \ \ \ list\ \$toptype\ \[lmap\ element\ \$value\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ subtype\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ schema\ \[list\ \$subtype\ \$element\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ schema\ \$element\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\ object\ \{\n\ \ \ \ \ \ \ \ list\ \$toptype\ \[dict\ map\ \{key\ element\}\ \$value\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ subtype\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ schema\ \[list\ \$subtype\ \$element\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ schema\ \$element\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\ string\ -\ number\ -\ literal\ \{\n\ \ \ \ \ \ \ \ return\ \$toptype\n\ \ \ \ \}\ encoded\ \{\n\ \ \ \ \ \ \ \ schema\ \[decode\ \$value\]\n\ \ \ \ \}\ decoded\ \{\n\ \ \ \ \ \ \ \ schema\ \$value\n\ \ \ \ \}\ default\ \{\n\ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ type\ \\\"\$type\\\":\ must\ be\ array,\ object,\ string,\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ number,\ literal,\ encoded,\ decoded,\ or\ \{array|object\ ?...?\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subtype\},\ where\ subtype\ is\ recursively\ any\ valid\ JSON\ type\"\n\ \ \ \ \}\}\n\}\n======\n\n***\[\[json::values\]\]***\n\n======none\n#\ ::json::values\ --\n#\ Extracts\ JSON\ value\ information\ from\ the\ output\ of\ \[json::decode\].\nproc\ ::json::values\ \{data\}\ \{\n\ \ \ \ #\ Extract\ type\ and\ value\ from\ data\ argument.\n\ \ \ \ if\ \{\[llength\ \$data\]\ !=\ 2\}\ \{\n\ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ data:\ must\ be\ a\ two-element\ list\ consisting\ of\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ type\ and\ value\"\n\ \ \ \ \}\n\ \ \ \ lassign\ \$data\ type\ value\n\n\ \ \ \ #\ Extract\ top\ and\ subtype\ from\ type\ element.\n\ \ \ \ set\ toptype\ \[lindex\ \$type\ 0\]\n\ \ \ \ if\ \{\[llength\ \$type\]\ >=\ 2\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$type\]\ ==\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ subtype\ \[lindex\ \$type\ 1\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ subtype\ \[lrange\ \$type\ 1\ end\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\$toptype\ ni\ \{array\ object\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ toptype\ \{\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Perform\ type-specific\ JSON\ processing.\n\ \ \ \ switch\ \$toptype\ \{\n\ \ \ \ array\ \{\n\ \ \ \ \ \ \ \ lmap\ element\ \$value\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ subtype\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ values\ \[list\ \$subtype\ \$element\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ values\ \$element\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ object\ \{\n\ \ \ \ \ \ \ \ dict\ map\ \{key\ element\}\ \$value\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ subtype\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ values\ \[list\ \$subtype\ \$element\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ values\ \$element\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ string\ -\ number\ -\ literal\ \{\n\ \ \ \ \ \ \ \ return\ \$value\n\ \ \ \ \}\ encoded\ \{\n\ \ \ \ \ \ \ \ values\ \[decode\ \$value\]\n\ \ \ \ \}\ decoded\ \{\n\ \ \ \ \ \ \ \ values\ \$value\n\ \ \ \ \}\ default\ \{\n\ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ type\ \\\"\$type\\\":\ must\ be\ array,\ object,\ string,\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ number,\ literal,\ encoded,\ decoded,\ or\ \{array|object\ ?...?\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subtype\},\ where\ subtype\ is\ recursively\ any\ valid\ JSON\ type\"\n\ \ \ \ \}\}\n\}\n\n***\[\[json::unite\]\]***\n\n======none\n#\ ::json::unite\ --\n#\ Combines\ the\ output\ of\ \[json::schema\]\ with\ the\ output\ of\ \[json::values\]\ to\n#\ produce\ a\ suitable\ input\ for\ \[json::encode\].\ \ The\ \[json::schema\]\ input\ format\n#\ is\ extended\ to\ allow\ variable-length\ arrays\ and\ objects\ with\ extra,\ missing,\n#\ or\ reordered\ keys.\ \ Repeated\ keys\ are\ not\ allowed.\ \ Variable-length\ arrays\ are\n#\ implemented\ by\ repeating\ the\ defined\ element\ types\ in\ a\ loop.\ \ The\ schema\ may\n#\ also\ contain\ encoded\ and\ decoded\ types,\ signifying\ that\ the\ corresponding\n#\ value\ is\ a\ raw\ JSON\ string\ or\ a\ decoded\ JSON\ document.\nproc\ ::json::unite\ \{schema\ values\}\ \{\n\ \ \ \ switch\ \[lindex\ \$schema\ 0\]\ \{\n\ \ \ \ array\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$schema\]\ !=\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ array:\ must\ be\ a\ two-element\ list\ with\ second\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ element\ being\ list\ of\ array\ element\ types\"\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Repeat\ and/or\ trim\ the\ subtype\ list\ to\ the\ value\ list\ length.\n\ \ \ \ \ \ \ \ set\ subtypes\ \[lindex\ \$schema\ 1\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$subtypes\]\ <\ \[llength\ \$values\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ subtypes\ \[lrepeat\ \[expr\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\[llength\ \$values\]\ +\ \[llength\ \$subtypes\]\ -\ 1)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ /\ \[llength\ \$subtypes\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \{*\}\$subtypes\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$subtypes\]\ >\ \[llength\ \$values\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ subtypes\ \[lreplace\ \$subtypes\ \[llength\ \$values\]\ end\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Process\ each\ element.\n\ \ \ \ \ \ \ \ list\ array\ \[lmap\ subtype\ \$subtypes\ value\ \$values\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ unite\ \$subtype\ \$value\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\ object\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$schema\]\ !=\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ array:\ must\ be\ a\ two-element\ list\ with\ second\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ element\ being\ dict\ of\ object\ element\ types\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ list\ object\ \[dict\ map\ \{key\ value\}\ \$values\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \[lindex\ \$schema\ 1\]\ \$key\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unite\ \[dict\ get\ \[lindex\ \$schema\ 1\]\ \$key\]\ \$value\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\[dict\ exists\ \[lindex\ \$schema\ 1\]\ \{\}\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unite\ \[dict\ get\ \[lindex\ \$schema\ 1\]\ \{\}\]\ \$value\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"key\ not\ defined\ in\ schema:\ \$key\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\ string\ -\ number\ -\ literal\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$schema\]\ !=\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ \[lindex\ \$schema\ 0\]:\ must\ be\ a\ one-element\ list\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ list\ \[lindex\ \$schema\ 0\]\ \$values\n\ \ \ \ \}\ encoded\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$schema\]\ !=\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"invalid\ encoded\ JSON:\ must\ be\ a\ one-element\ list\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ decode\ \[lindex\ \$values\ 0\]\n\ \ \ \ \}\ decoded\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$schema\]\ !=\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"invalid\ decoded\ JSON:\ must\ be\ a\ two-element\ list\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$values\n\ \ \ \ \}\ default\ \{\n\ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ type\ \\\"\[lindex\ \$schema\ 0\]\\\":\ must\ be\ array,\ object,\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ string,\ number,\ literal,\ encoded,\ or\ decoded\"\n\ \ \ \ \}\}\n\}\n======\n\n**Testing**\n\nOld\ test\ suite:\n\n======none\npackage\ require\ tcltest\nforeach\ \{name\ json::encode\ json::decode\ description\ tcl\ json\}\ \{\n\ \ \ \ 1.1\ 1\ 1\ \"empty\ string\"\n\ \ \ \ \ \ \ \ \{string\ \{\}\}\n\ \ \ \ \ \ \ \ \{\"\"\}\n\ \ \ \ 1.2\ 1\ 1\ \"nonempty\ string\"\n\ \ \ \ \ \ \ \ \{string\ hello\}\n\ \ \ \ \ \ \ \ \{\"hello\"\}\n\ \ \ \ 1.3\ 1\ 0\ \"string\ with\ quoted\ characters\"\n\ \ \ \ \ \ \ \ \{string\ \\\"a\\nb\\\\c\\\"\}\n\ \ \ \ \ \ \ \ \{\"\\\"a\\u000ab\\\\c\\\"\"\}\n\ \ \ \ 1.4\ 1\ 1\ \"string\ with\ canonical\ quoted\ characters\"\n\ \ \ \ \ \ \ \ \"string\ \\\{\\\"a\\nb\\\\c\\\"\\\}\"\n\ \ \ \ \ \ \ \ \{\"\\\"a\\u000ab\\\\c\\\"\"\}\n\ \ \ \ 2.1\ 1\ 1\ integer\n\ \ \ \ \ \ \ \ \{number\ 42\}\n\ \ \ \ \ \ \ \ 42\n\ \ \ \ 2.2\ 1\ 1\ \"negative\ integer\"\n\ \ \ \ \ \ \ \ \{number\ -42\}\n\ \ \ \ \ \ \ \ -42\n\ \ \ \ 2.3\ 1\ 0\ \"positive\ integer\"\n\ \ \ \ \ \ \ \ \{number\ +42\}\n\ \ \ \ \ \ \ \ 42\n\ \ \ \ 2.4\ 1\ 0\ \"leading\ zeroes\"\n\ \ \ \ \ \ \ \ \{number\ 000\}\n\ \ \ \ \ \ \ \ 0\n\ \ \ \ 2.5\ 1\ 1\ zero\n\ \ \ \ \ \ \ \ \{number\ 0\}\n\ \ \ \ \ \ \ \ 0\n\ \ \ \ 2.6\ 1\ 1\ \"negative\ zero\"\n\ \ \ \ \ \ \ \ \{number\ -0\}\n\ \ \ \ \ \ \ \ -0\n\ \ \ \ 2.7\ 1\ 0\ \"negative\ zero\ with\ leading\ zeroes\"\n\ \ \ \ \ \ \ \ \{number\ -000\}\n\ \ \ \ \ \ \ \ -0\n\ \ \ \ 2.8\ 1\ 1\ \"real\ number\"\n\ \ \ \ \ \ \ \ \{number\ 1.23\}\n\ \ \ \ \ \ \ \ 1.23\n\ \ \ \ 2.9\ 1\ 1\ \"negative\ real\ number\"\n\ \ \ \ \ \ \ \ \{number\ -1.23\}\n\ \ \ \ \ \ \ \ -1.23\n\ \ \ \ 2.10\ 1\ 1\ \"negative\ real\ number\ with\ exponent\"\n\ \ \ \ \ \ \ \ \{number\ -1e5\}\n\ \ \ \ \ \ \ \ -1e5\n\ \ \ \ 2.11\ 1\ 1\ \"real\ number\ with\ capital\ exponent\"\n\ \ \ \ \ \ \ \ \{number\ 1E5\}\n\ \ \ \ \ \ \ \ 1E5\n\ \ \ \ 2.12\ 1\ 1\ \"real\ number\ with\ fraction\ and\ exponent\"\n\ \ \ \ \ \ \ \ \{number\ 1.23e4\}\n\ \ \ \ \ \ \ \ 1.23e4\n\ \ \ \ 2.13\ 1\ 0\ \"positive\ real\ number\ with\ fraction\ and\ positive\ exponent\"\n\ \ \ \ \ \ \ \ \{number\ +1.23e+4\}\n\ \ \ \ \ \ \ \ 1.23e+4\n\ \ \ \ 2.14\ 1\ 1\ \"real\ number\ with\ fraction\ and\ negative\ exponent\"\n\ \ \ \ \ \ \ \ \{number\ 1.23e-4\}\n\ \ \ \ \ \ \ \ 1.23e-4\n\ \ \ \ 2.15\ 1\ 0\ \"real\ number\ with\ dot\ and\ no\ fraction\"\n\ \ \ \ \ \ \ \ \{number\ 1.\}\n\ \ \ \ \ \ \ \ 1.0\n\ \ \ \ 2.16\ 1\ 0\ \"real\ number\ with\ dot\ and\ no\ integer\"\n\ \ \ \ \ \ \ \ \{number\ .1\}\n\ \ \ \ \ \ \ \ 0.1\n\ \ \ \ 2.17\ 1\ 0\ \"real\ number\ with\ dot,\ no\ fraction,\ and\ exponent\"\n\ \ \ \ \ \ \ \ \{number\ 1.E5\}\n\ \ \ \ \ \ \ \ 1.0E5\n\ \ \ \ 2.18\ 1\ 0\ \"real\ number\ with\ dot,\ no\ integer,\ and\ exponent\"\n\ \ \ \ \ \ \ \ \{number\ .1E-5\}\n\ \ \ \ \ \ \ \ 0.1E-5\n\ \ \ \ 2.19\ 1\ 0\ \"real\ number\ with\ leading\ zeroes\"\n\ \ \ \ \ \ \ \ \{number\ 00123.45\}\n\ \ \ \ \ \ \ \ 123.45\n\ \ \ \ 2.20\ 1\ 0\ \"small\ real\ number\ with\ leading\ zeroes\"\n\ \ \ \ \ \ \ \ \{number\ 00000.45\}\n\ \ \ \ \ \ \ \ 0.45\n\ \ \ \ 2.21\ 1\ 0\ \"zero\ real\ number\ with\ leading\ zeroes\ and\ exponent\"\n\ \ \ \ \ \ \ \ \{number\ 00000e9\}\n\ \ \ \ \ \ \ \ 0e9\n\ \ \ \ 3.1\ 1\ 1\ \"literal\ false\"\n\ \ \ \ \ \ \ \ \{literal\ false\}\n\ \ \ \ \ \ \ \ false\n\ \ \ \ 3.2\ 1\ 1\ \"literal\ null\"\n\ \ \ \ \ \ \ \ \{literal\ null\}\n\ \ \ \ \ \ \ \ null\n\ \ \ \ 3.3\ 1\ 1\ \"literal\ true\"\n\ \ \ \ \ \ \ \ \{literal\ true\}\n\ \ \ \ \ \ \ \ true\n\ \ \ \ 4.1\ 1\ 1\ \"array\ with\ variable\ type\"\n\ \ \ \ \ \ \ \ \{array\ \{\{string\ hello\}\ \{number\ 42\}\ \{literal\ null\}\}\}\n\ \ \ \ \ \ \ \ \{\[\"hello\",42,null\]\}\n\ \ \ \ 4.2\ 1\ 1\ \"array\ with\ constant\ but\ unshared\ type\"\n\ \ \ \ \ \ \ \ \{array\ \{\{array\ \{\{number\ 1\}\ \{number\ 2\}\}\}\ \{array\ \{\{number\ 3\}\ \{number\ 4\}\}\}\}\}\n\ \ \ \ \ \ \ \ \{\[\[1,2\],\[3,4\]\]\}\n\ \ \ \ 4.3\ 1\ 0\ \"array\ with\ shared\ type,\ nested\ syntax\"\n\ \ \ \ \ \ \ \ \{\{array\ \{array\ number\}\}\ \{\{1\ 2\}\ \{3\ 4\}\}\}\n\ \ \ \ \ \ \ \ \{\[\[1,2\],\[3,4\]\]\}\n\ \ \ \ 4.4\ 1\ 0\ \"array\ with\ shared\ type,\ flattened\ syntax\"\n\ \ \ \ \ \ \ \ \{\{array\ array\ number\}\ \{\{1\ 2\}\ \{3\ 4\}\}\}\n\ \ \ \ \ \ \ \ \{\[\[1,2\],\[3,4\]\]\}\n\ \ \ \ 4.5\ 1\ 0\ \"array\ of\ strings\"\n\ \ \ \ \ \ \ \ \{\{array\ array\ string\}\ \{\{1\ 2\}\ \{3\ 4\}\}\}\n\ \ \ \ \ \ \ \ \{\[\[\"1\",\"2\"\],\[\"3\",\"4\"\]\]\}\n\ \ \ \ 4.6\ 1\ 1\ \"empty\ array\"\n\ \ \ \ \ \ \ \ \{array\ \{\}\}\n\ \ \ \ \ \ \ \ \{\[\]\}\n\ \ \ \ 4.7\ 1\ 0\ \"empty\ array\ with\ unnecessary\ shared\ type\"\n\ \ \ \ \ \ \ \ \{\{array\ string\}\ \{\}\}\n\ \ \ \ \ \ \ \ \{\[\]\}\n\ \ \ \ 5.1\ 1\ 1\ \"object\ with\ variable\ type\"\n\ \ \ \ \ \ \ \ \{object\ \{foo\ \{string\ hello\}\ bar\ \{number\ 42\}\ quux\ \{literal\ null\}\}\}\n\ \ \ \ \ \ \ \ \{\{\"foo\":\"hello\",\"bar\":42,\"quux\":null\}\}\n\ \ \ \ 5.2\ 1\ 1\ \"object\ with\ constant\ but\ unshared\ type\"\n\ \ \ \ \ \ \ \ \{object\ \{name\ \{object\ \{first\ \{string\ Andy\}\ last\ \{string\ Goth\}\}\}\ address\ \{object\ \{web\ \{string\ http://tcl.tk/\}\}\}\}\}\n\ \ \ \ \ \ \ \ \{\{\"name\":\{\"first\":\"Andy\",\"last\":\"Goth\"\},\"address\":\{\"web\":\"http://tcl.tk/\"\}\}\}\n\ \ \ \ 5.3\ 1\ 0\ \"object\ with\ shared\ type,\ flattened\ syntax\"\n\ \ \ \ \ \ \ \ \{\{object\ object\ string\}\ \{name\ \{first\ Andy\ last\ Goth\}\ address\ \{web\ http://tcl.tk/\}\}\}\n\ \ \ \ \ \ \ \ \{\{\"name\":\{\"first\":\"Andy\",\"last\":\"Goth\"\},\"address\":\{\"web\":\"http://tcl.tk/\"\}\}\}\n\ \ \ \ 5.4\ 1\ 1\ \"empty\ object\"\n\ \ \ \ \ \ \ \ \{object\ \{\}\}\n\ \ \ \ \ \ \ \ \{\{\}\}\n\ \ \ \ 5.5\ 1\ 0\ \"empty\ object\ with\ unnecessary\ shared\ type\"\n\ \ \ \ \ \ \ \ \{\{object\ string\}\ \{\}\}\n\ \ \ \ \ \ \ \ \{\{\}\}\n\ \ \ \ 6.1\ 1\ 0\ \"empty\ raw\"\n\ \ \ \ \ \ \ \ \{raw\ \{\}\}\n\ \ \ \ \ \ \ \ \{\}\n\ \ \ \ 6.2\ 1\ 0\ \"nonempty\ raw\"\n\ \ \ \ \ \ \ \ \{raw\ \{\"foobar\"\}\}\n\ \ \ \ \ \ \ \ \{\"foobar\"\}\n\}\ \{\n\ \ \ \ if\ \{\$json::encode\}\ \{\n\ \ \ \ \ \ \ \ tcltest::test\ json::encode-\$name\ \$description\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -body\ \[list\ json::encode\ \$tcl\]\ -result\ \$json\n\ \ \ \ \}\n\ \ \ \ if\ \{\$json::decode\}\ \{\n\ \ \ \ \ \ \ \ tcltest::test\ json::decode-\$name\ \$description\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -body\ \[list\ json::decode\ \$json\]\ -result\ \$tcl\n\ \ \ \ \}\n\}\ntcltest::cleanupTests\n======\n\nNew\ test\ suite:\n\n======none\npackage\ require\ Tcl\ 8.5.7\npackage\ require\ json\npackage\ require\ tcltest\n\nforeach\ \{name\ description\ input\ output\}\ \{\n\ \ \ \ json-1.1\ \"encode\ array\ document\"\n\ \ \ \ \{array\ \{\{number\ 0\}\ \{number\ 1\}\ \{number\ 2\}\ \{number\ 3\}\}\}\ \{\[0,1,2,3\]\}\n\n\ \ \ \ json-1.2\ \"encode\ object\ document\"\n\ \ \ \ \{object\ \{foo\ \{number\ 0\}\ bar\ \{number\ 1\}\ quux\ \{number\ 2\}\}\}\n\ \ \ \ \{\{\"foo\":0,\"bar\":1,\"quux\":2\}\}\n\n\ \ \ \ json-1.3.1\ \"encode\ string\ document\"\n\ \ \ \ \{string\ \"hello\ world\"\}\ \{\"hello\ world\"\}\n\n\ \ \ \ json-1.3.2\ \"encode\ empty\ string\ document\"\n\ \ \ \ \{string\ \"\"\}\ \{\"\"\}\n\n\ \ \ \ json-1.3.3\ \"encode\ NUL\ string\ document\"\n\ \ \ \ \{string\ \"\\x00\"\}\ \{\"\\u0000\"\}\n\n\ \ \ \ json-1.3.4\ \"encode\ quoted\ string\ document\"\n\ \ \ \ \{string\ \"\\x1f\\\\x\\\"y\\\"z\"\}\ \{\"\\u001f\\\\x\\\"y\\\"z\"\}\n\n\ \ \ \ json-1.4.1\ \"encode\ integer\ number\ document\"\n\ \ \ \ \{number\ 42\}\ 42\n\n\ \ \ \ json-1.4.2\ \"encode\ negative\ integer\ number\ document\"\n\ \ \ \ \{number\ -42\}\ -42\n\n\ \ \ \ json-1.4.3\ \"encode\ positive\ integer\ number\ document\"\n\ \ \ \ \{number\ +42\}\ 42\n\n\ \ \ \ json-1.4.4\ \"encode\ spaced\ integer\ number\ document\"\n\ \ \ \ \{number\ \"\ +084\ \"\}\ 84\n\n\ \ \ \ json-1.4.5\ \"encode\ real\ number\ document\"\n\ \ \ \ \{number\ 4.2\}\ 4.2\n\n\ \ \ \ json-1.4.6\ \"encode\ negative\ real\ number\ document\"\n\ \ \ \ \{number\ -4.2\}\ -4.2\n\n\ \ \ \ json-1.4.6\ \"encode\ positive\ real\ number\ document\"\n\ \ \ \ \{number\ +4.2\}\ 4.2\n\n\ \ \ \ json-1.4.7\ \"encode\ spaced\ real\ number\ document\"\n\ \ \ \ \{number\ \"\ +04.20\ \"\}\ 4.2\n\n\ \ \ \ json-1.4.8\ \"encode\ real\ number\ document\ w/o\ leading\ zero\"\n\ \ \ \ \{number\ -.2\}\ -0.2\n\n\ \ \ \ json-1.4.9\ \"encode\ real\ number\ document\ w/o\ trailing\ zero\"\n\ \ \ \ \{number\ +2.\}\ 2.0\n\n\ \ \ \ json-1.4.10\ \"encode\ exponential\ number\ document\"\n\ \ \ \ \{number\ 2e5\}\ 2.0e+5\n\n\ \ \ \ json-1.5.1\ \"encode\ literal\ true\ document\"\n\ \ \ \ \{literal\ true\}\ true\n\n\ \ \ \ json-1.5.2\ \"encode\ literal\ false\ document\"\n\ \ \ \ \{literal\ false\}\ false\n\n\ \ \ \ json-1.5.3\ \"encode\ literal\ null\ document\"\n\ \ \ \ \{literal\ null\}\ null\n\n\ \ \ \ json-1.6\ \"encode\ pre-encoded\ document\"\n\ \ \ \ \{encoded\ \{\"hello\ world\"\}\}\ \{\"hello\ world\"\}\n\n\ \ \ \ json-1.7\ \"encode\ decoded\ document\"\n\ \ \ \ \{decoded\ \{string\ \"hello\ world\"\}\}\ \{\"hello\ world\"\}\n\n\ \ \ \ json-1.8.1\ \"encode\ array\ array\ document\"\n\ \ \ \ \{\{array\ array\}\ \{\{\{number\ 1\}\ \{number\ 2\}\}\ \{\{string\ 3\}\}\}\}\ \{\[\[1,2\],\[\"3\"\]\]\}\n\n\ \ \ \ json-1.8.2\ \"encode\ array\ array\ number\ document\"\n\ \ \ \ \{\{array\ array\ number\}\ \{\{1\ 2\}\ \{3\ 4\}\}\}\ \{\[\[1,2\],\[3,4\]\]\}\n\n\ \ \ \ json-1.8.3\ \"encode\ array\ object\ document\"\n\ \ \ \ \{\{array\ object\}\ \{\{a\ \{number\ 1\}\ b\ \{string\ 2\}\}\ \{a\ \{string\ 3\}\ b\ \{number\ 4\}\}\}\}\n\ \ \ \ \{\[\{\"a\":1,\"b\":\"2\"\},\{\"a\":\"3\",\"b\":4\}\]\}\n\n\ \ \ \ json-1.8.4\ \"encode\ array\ object\ number\ document\"\n\ \ \ \ \{\{array\ object\ number\}\ \{\{a\ 1\ b\ 2\}\ \{a\ 3\ b\ 4\}\}\}\n\ \ \ \ \{\[\{\"a\":1,\"b\":2\},\{\"a\":3,\"b\":4\}\]\}\n\n\ \ \ \ json-1.8.5\ \"encode\ array\ string\ document\"\n\ \ \ \ \{\{array\ string\}\ \{1\ 2\ 3\ 4\}\}\ \{\[\"1\",\"2\",\"3\",\"4\"\]\}\n\n\ \ \ \ json-1.8.6\ \"encode\ array\ number\ document\"\n\ \ \ \ \{\{array\ number\}\ \{1\ 2\ 3\ 4\}\}\ \{\[1,2,3,4\]\}\n\n\ \ \ \ json-1.8.7\ \"encode\ array\ literal\ document\"\n\ \ \ \ \{\{array\ literal\}\ \{true\ false\ null\}\}\ \{\[true,false,null\]\}\n\n\ \ \ \ json-1.8.8\ \"encode\ array\ encoded\ document\"\n\ \ \ \ \{\{array\ encoded\}\ \{\{\"x\"\}\ \[0,0\]\ null\}\}\ \{\[\"x\",\[0,0\],null\]\}\n\n\ \ \ \ json-1.8.9\ \"encode\ array\ decoded\ document\"\n\ \ \ \ \{\{array\ decoded\}\ \{\{literal\ true\}\ \{literal\ false\}\ \{literal\ null\}\}\}\n\ \ \ \ \{\[true,false,null\]\}\n\n\ \ \ \ json-1.9.1\ \"encode\ object\ array\ document\"\n\ \ \ \ \{\{object\ array\}\ \{a\ \{\{number\ 1\}\ \{number\ 2\}\}\ b\ \{\{string\ 3\}\}\}\}\n\ \ \ \ \{\{\"a\":\[1,2\],\"b\":\[\"3\"\]\}\}\n\n\ \ \ \ json-1.9.2\ \"encode\ object\ array\ number\ document\"\n\ \ \ \ \{\{object\ array\ number\}\ \{a\ \{1\ 2\}\ b\ \{3\ 4\}\}\}\ \{\{\"a\":\[1,2\],\"b\":\[3,4\]\}\}\n\n\ \ \ \ json-1.9.3\ \"encode\ object\ object\ document\"\n\ \ \ \ \{\{object\ object\}\ \{x\ \{a\ \{number\ 1\}\ b\ \{string\ 2\}\}\ y\ \{a\ \{string\ 3\}\}\}\}\n\ \ \ \ \{\{\"x\":\{\"a\":1,\"b\":\"2\"\},\"y\":\{\"a\":\"3\"\}\}\}\n\n\ \ \ \ json-1.9.4\ \"encode\ object\ object\ number\ document\"\n\ \ \ \ \{\{object\ object\ number\}\ \{x\ \{a\ 1\ b\ 2\}\ y\ \{a\ 3\ b\ 4\}\}\}\n\ \ \ \ \{\{\"x\":\{\"a\":1,\"b\":2\},\"y\":\{\"a\":3,\"b\":4\}\}\}\n\n\ \ \ \ json-1.9.5\ \"encode\ object\ string\ document\"\n\ \ \ \ \{\{object\ string\}\ \{1\ 2\ 3\ 4\}\}\ \{\{\"1\":\"2\",\"3\":\"4\"\}\}\n\n\ \ \ \ json-1.9.6\ \"encode\ object\ number\ document\"\n\ \ \ \ \{\{object\ number\}\ \{1\ 2\ 3\ 4\}\}\ \{\{\"1\":2,\"3\":4\}\}\n\n\ \ \ \ json-1.9.7\ \"encode\ object\ literal\ document\"\n\ \ \ \ \{\{object\ literal\}\ \{true\ true\ false\ false\ null\ null\}\}\n\ \ \ \ \{\{\"true\":true,\"false\":false,\"null\":null\}\}\n\n\ \ \ \ json-1.9.8\ \"encode\ object\ encoded\ document\"\n\ \ \ \ \{\{object\ encoded\}\ \{true\ \{\"x\"\}\ false\ \[0,0\]\ null\ null\}\}\n\ \ \ \ \{\{\"true\":\"x\",\"false\":\[0,0\],\"null\":null\}\}\n\n\ \ \ \ json-1.9.9\ \"encode\ object\ decoded\ document\"\n\ \ \ \ \{\{object\ decoded\}\ \{true\ \{string\ x\}\ false\ \{number\ -1.20\}\ null\ \{literal\ null\}\}\}\n\ \ \ \ \{\{\"true\":\"x\",\"false\":-1.2,\"null\":null\}\}\n\}\ \{\n\ \ \ \ tcltest::test\ \$name\ \$description\ -body\ \[list\ json::encode\ \$input\]\\\n\ \ \ \ \ \ \ \ \ \ \ \ -result\ \$output\n\}\n\n#\ TODO:\ more\ error\ cases?\ntcltest::test\ json-1.5.4\ \"encode\ literal\ invalid\ document\"\ -body\ \{\n\ \ \ \ json::encode\ \{literal\ invalid\}\n\}\ -returnCodes\ error\\\n-result\ \{invalid\ JSON\ literal\ \"invalid\":\ must\ be\ false,\ null,\ or\ true\}\n\nforeach\ \{name\ description\ input\ output\}\ \{\n\ \ \ \ json-2.1\ \"decode\ array\ document\"\n\ \ \ \ \{\[0,1,2,3\]\}\ \{array\ \{\{number\ 0\}\ \{number\ 1\}\ \{number\ 2\}\ \{number\ 3\}\}\}\n\n\ \ \ \ json-2.2\ \"decode\ object\ document\"\n\ \ \ \ \{\{\"foo\":0,\"bar\":1,\"quux\":2\}\}\n\ \ \ \ \{object\ \{foo\ \{number\ 0\}\ bar\ \{number\ 1\}\ quux\ \{number\ 2\}\}\}\n\n\ \ \ \ json-2.3.1\ \"decode\ string\ document\"\n\ \ \ \ \{\"hello\ world\"\}\ \{string\ \{hello\ world\}\}\n\n\ \ \ \ json-2.3.2\ \"decode\ empty\ string\ document\"\n\ \ \ \ \{\"\"\}\ \{string\ \{\}\}\n\n\ \ \ \ json-2.3.3\ \"decode\ NUL\ string\ document\"\n\ \ \ \ \{\"\\u0000\"\}\ \"string\ \\x00\"\n\n\ \ \ \ json-2.3.4\ \"decode\ quoted\ string\ document\"\n\ \ \ \ \{\"\\u001f\\\\x\\\"y\\\"z\"\}\ \"string\ \{\\x1f\\\\x\\\"y\\\"z\}\"\n\n\ \ \ \ json-2.4.1\ \"decode\ integer\ number\ document\"\n\ \ \ \ 42\ \{number\ 42\}\n\n\ \ \ \ json-2.4.2\ \"decode\ negative\ integer\ number\ document\"\n\ \ \ \ -42\ \{number\ -42\}\n\n\ \ \ \ json-2.4.3\ \"decode\ positive\ integer\ number\ document\"\n\ \ \ \ +42\ \{number\ 42\}\n\n\ \ \ \ json-2.4.5\ \"decode\ real\ number\ document\"\n\ \ \ \ 4.2\ \{number\ 4.2\}\n\n\ \ \ \ json-2.4.6\ \"decode\ negative\ real\ number\ document\"\n\ \ \ \ -4.2\ \{number\ -4.2\}\n\n\ \ \ \ json-2.4.6\ \"decode\ positive\ real\ number\ document\"\n\ \ \ \ +4.2\ \{number\ 4.2\}\n\n\ \ \ \ json-2.5.1\ \"decode\ literal\ true\ document\"\n\ \ \ \ true\ \{literal\ true\}\n\n\ \ \ \ json-2.5.2\ \"decode\ literal\ false\ document\"\n\ \ \ \ false\ \{literal\ false\}\n\n\ \ \ \ json-2.5.3\ \"decode\ literal\ null\ document\"\n\ \ \ \ null\ \{literal\ null\}\n\n\ \ \ \ json-2.6.1\ \"decode\ array\ array\ document\"\n\ \ \ \ \{\[\[1\],\[\"3\"\]\]\}\ \{array\ \{\{array\ \{\{number\ 1\}\}\}\ \{array\ \{\{string\ 3\}\}\}\}\}\n\n\ \ \ \ json-2.6.2\ \"decode\ array\ array\ number\ document\"\n\ \ \ \ \{\[\[1,2\],\[3,4\]\]\}\n\ \ \ \ \{array\ \{\{array\ \{\{number\ 1\}\ \{number\ 2\}\}\}\ \{array\ \{\{number\ 3\}\ \{number\ 4\}\}\}\}\}\n\n\ \ \ \ json-2.6.3\ \"decode\ array\ object\ document\"\n\ \ \ \ \{\[\{\"a\":1,\"b\":\"2\"\},\{\"a\":\"3\"\}\]\}\n\ \ \ \ \{array\ \{\{object\ \{a\ \{number\ 1\}\ b\ \{string\ 2\}\}\}\ \{object\ \{a\ \{string\ 3\}\}\}\}\}\n\n\ \ \ \ json-2.6.4\ \"encode\ array\ string\ document\"\n\ \ \ \ \{\[\"1\",\"2\",\"3\",\"4\"\]\}\ \{array\ \{\{string\ 1\}\ \{string\ 2\}\ \{string\ 3\}\ \{string\ 4\}\}\}\n\n\ \ \ \ json-2.6.5\ \"decode\ array\ number\ document\"\n\ \ \ \ \{\[1,2,3,4\]\}\ \{array\ \{\{number\ 1\}\ \{number\ 2\}\ \{number\ 3\}\ \{number\ 4\}\}\}\n\n\ \ \ \ json-2.6.6\ \"decode\ array\ literal\ document\"\n\ \ \ \ \{\[true,false,null\]\}\ \{array\ \{\{literal\ true\}\ \{literal\ false\}\ \{literal\ null\}\}\}\n\n\ \ \ \ json-2.7.1\ \"decode\ object\ array\ document\"\n\ \ \ \ \{\{\"a\":\[1,2\],\"b\":\[\"3\"\]\}\}\n\ \ \ \ \{object\ \{a\ \{array\ \{\{number\ 1\}\ \{number\ 2\}\}\}\ b\ \{array\ \{\{string\ 3\}\}\}\}\}\n\n\ \ \ \ json-2.7.2\ \"decode\ object\ object\ document\"\n\ \ \ \ \{\{\"x\":\{\"a\":1,\"b\":\"2\"\},\"y\":\{\"a\":\"3\"\}\}\}\n\ \ \ \ \{object\ \{x\ \{object\ \{a\ \{number\ 1\}\ b\ \{string\ 2\}\}\}\ y\ \{object\ \{a\ \{string\ 3\}\}\}\}\}\n\n\ \ \ \ json-2.7.3\ \"decode\ object\ string\ document\"\n\ \ \ \ \{\{\"1\":\"2\",\"3\":\"4\"\}\}\ \{object\ \{1\ \{string\ 2\}\ 3\ \{string\ 4\}\}\}\n\n\ \ \ \ json-2.7.4\ \"encode\ object\ number\ document\"\n\ \ \ \ \{\{\"1\":2,\"3\":4\}\}\ \{object\ \{1\ \{number\ 2\}\ 3\ \{number\ 4\}\}\}\n\n\ \ \ \ json-2.7.5\ \"decode\ object\ literal\ document\"\n\ \ \ \ \{\{\"true\":true,\"false\":false,\"null\":null\}\}\n\ \ \ \ \{object\ \{true\ \{literal\ true\}\ false\ \{literal\ false\}\ null\ \{literal\ null\}\}\}\n\}\ \{\n\ \ \ \ tcltest::test\ \$name\ \$description\ -body\ \[list\ json::decode\ \$input\]\\\n\ \ \ \ \ \ \ \ \ \ \ \ -result\ \$output\n\}\n\nforeach\ \{name\ description\ input\ output\}\ \{\n\ \ \ \ json-3.1\ \"array\ schema\"\n\ \ \ \ \{array\ \{\{number\ 0\}\ \{number\ 1\}\ \{number\ 2\}\ \{number\ 3\}\}\}\n\ \ \ \ \{array\ \{number\ number\ number\ number\}\}\n\n\ \ \ \ json-3.2\ \"object\ schema\"\n\ \ \ \ \{object\ \{foo\ \{number\ 0\}\ bar\ \{number\ 1\}\ quux\ \{number\ 2\}\}\}\n\ \ \ \ \{object\ \{foo\ number\ bar\ number\ quux\ number\}\}\n\n\ \ \ \ json-3.3\ \"string\ schema\"\n\ \ \ \ \{string\ \{hello\ world\}\}\ string\n\n\ \ \ \ json-3.4\ \"number\ schema\"\n\ \ \ \ \{number\ 42\}\ number\n\n\ \ \ \ json-3.5\ \"literal\ schema\"\n\ \ \ \ \{literal\ true\}\ literal\n\n\ \ \ \ json-3.6.1\ \"array\ array\ schema\"\n\ \ \ \ \{array\ \{\{array\ \{\{number\ 1\}\}\}\ \{array\ \{\{string\ 3\}\ \{literal\ false\}\}\}\}\}\n\ \ \ \ \{array\ \{\{array\ number\}\ \{array\ \{string\ literal\}\}\}\}\n\n\ \ \ \ json-3.6.2\ \"array\ array\ number\ schema\"\n\ \ \ \ \{array\ \{\{array\ \{\{number\ 1\}\ \{number\ 2\}\}\}\ \{array\ \{\{number\ 3\}\ \{number\ 4\}\}\}\}\}\n\ \ \ \ \{array\ \{\{array\ \{number\ number\}\}\ \{array\ \{number\ number\}\}\}\}\n\n\ \ \ \ json-3.6.3\ \"array\ object\ schema\"\n\ \ \ \ \{array\ \{\{object\ \{a\ \{number\ 1\}\ b\ \{string\ 2\}\}\}\ \{object\ \{a\ \{string\ 3\}\}\}\}\}\n\ \ \ \ \{array\ \{\{object\ \{a\ number\ b\ string\}\}\ \{object\ \{a\ string\}\}\}\}\n\n\ \ \ \ json-3.6.4\ \"array\ string\ schema\"\n\ \ \ \ \{array\ \{\{string\ 1\}\ \{string\ 2\}\ \{string\ 3\}\ \{string\ 4\}\}\}\n\ \ \ \ \{array\ \{string\ string\ string\ string\}\}\n\n\ \ \ \ json-3.6.5\ \"array\ number\ schema\"\n\ \ \ \ \{array\ \{\{number\ 1\}\ \{number\ 2\}\ \{number\ 3\}\ \{number\ 4\}\}\}\n\ \ \ \ \{array\ \{number\ number\ number\ number\}\}\n\n\ \ \ \ json-3.6.6\ \"array\ literal\ schema\"\n\ \ \ \ \{array\ \{\{literal\ true\}\ \{literal\ false\}\ \{literal\ null\}\}\}\n\ \ \ \ \{array\ \{literal\ literal\ literal\}\}\n\n\ \ \ \ json-3.7.1\ \"object\ array\ schema\"\n\ \ \ \ \{object\ \{a\ \{array\ \{\{number\ 1\}\ \{number\ 2\}\}\}\ b\ \{array\ \{\{string\ 3\}\}\}\}\}\n\ \ \ \ \{object\ \{a\ \{array\ \{number\ number\}\}\ b\ \{array\ string\}\}\}\n\n\ \ \ \ json-3.7.2\ \"object\ object\ schema\"\n\ \ \ \ \{object\ \{x\ \{object\ \{a\ \{number\ 1\}\ b\ \{string\ 2\}\}\}\ y\ \{object\ \{a\ \{string\ 3\}\}\}\}\}\n\ \ \ \ \{object\ \{x\ \{object\ \{a\ number\ b\ string\}\}\ y\ \{object\ \{a\ string\}\}\}\}\n\n\ \ \ \ json-3.7.3\ \"object\ string\ schema\"\n\ \ \ \ \{object\ \{1\ \{string\ 2\}\ 3\ \{string\ 4\}\}\}\n\ \ \ \ \{object\ \{1\ string\ 3\ string\}\}\n\n\ \ \ \ json-3.7.4\ \"object\ number\ schema\"\n\ \ \ \ \{object\ \{1\ \{number\ 2\}\ 3\ \{number\ 4\}\}\}\n\ \ \ \ \{object\ \{1\ number\ 3\ number\}\}\n\n\ \ \ \ json-3.7.5\ \"object\ literal\ schema\"\n\ \ \ \ \{object\ \{true\ \{literal\ true\}\ false\ \{literal\ false\}\ null\ \{literal\ null\}\}\}\n\ \ \ \ \{object\ \{true\ literal\ false\ literal\ null\ literal\}\}\n\}\ \{\n\ \ \ \ tcltest::test\ \$name\ \$description\ -body\ \[list\ json::schema\ \$input\]\\\n\ \ \ \ \ \ \ \ \ \ \ \ -result\ \$output\n\}\n\nforeach\ \{name\ description\ input\ output\}\ \{\n\ \ \ \ json-4.1\ \"array\ values\"\n\ \ \ \ \{array\ \{\{number\ 0\}\ \{number\ 1\}\ \{number\ 2\}\ \{number\ 3\}\}\}\ \{0\ 1\ 2\ 3\}\n\n\ \ \ \ json-4.2\ \"object\ values\"\n\ \ \ \ \{object\ \{foo\ \{number\ 0\}\ bar\ \{number\ 1\}\ quux\ \{number\ 2\}\}\}\n\ \ \ \ \{foo\ 0\ bar\ 1\ quux\ 2\}\n\n\ \ \ \ json-4.3\ \"string\ values\"\n\ \ \ \ \{string\ \{hello\ world\}\}\ \{hello\ world\}\n\n\ \ \ \ json-4.4\ \"number\ values\"\n\ \ \ \ \{number\ 42\}\ 42\n\n\ \ \ \ json-4.5\ \"literal\ values\"\n\ \ \ \ \{literal\ true\}\ true\n\n\ \ \ \ json-4.6.1\ \"array\ array\ values\"\n\ \ \ \ \{array\ \{\{array\ \{\{number\ 1\}\}\}\ \{array\ \{\{string\ 3\}\ \{literal\ false\}\}\}\}\}\n\ \ \ \ \{1\ \{3\ false\}\}\n\n\ \ \ \ json-4.6.2\ \"array\ array\ number\ values\"\n\ \ \ \ \{array\ \{\{array\ \{\{number\ 1\}\ \{number\ 2\}\}\}\ \{array\ \{\{number\ 3\}\ \{number\ 4\}\}\}\}\}\n\ \ \ \ \{\{1\ 2\}\ \{3\ 4\}\}\n\n\ \ \ \ json-4.6.3\ \"array\ object\ values\"\n\ \ \ \ \{array\ \{\{object\ \{a\ \{number\ 1\}\ b\ \{string\ 2\}\}\}\ \{object\ \{a\ \{string\ 3\}\}\}\}\}\n\ \ \ \ \{\{a\ 1\ b\ 2\}\ \{a\ 3\}\}\n\n\ \ \ \ json-4.6.4\ \"array\ string\ values\"\n\ \ \ \ \{array\ \{\{string\ 1\}\ \{string\ 2\}\ \{string\ 3\}\ \{string\ 4\}\}\}\ \{1\ 2\ 3\ 4\}\n\n\ \ \ \ json-4.6.5\ \"array\ number\ values\"\n\ \ \ \ \{array\ \{\{number\ 1\}\ \{number\ 2\}\ \{number\ 3\}\ \{number\ 4\}\}\}\ \{1\ 2\ 3\ 4\}\n\n\ \ \ \ json-4.6.6\ \"array\ literal\ values\"\n\ \ \ \ \{array\ \{\{literal\ true\}\ \{literal\ false\}\ \{literal\ null\}\}\}\ \{true\ false\ null\}\n\n\ \ \ \ json-4.7.1\ \"object\ array\ values\"\n\ \ \ \ \{object\ \{a\ \{array\ \{\{number\ 1\}\ \{number\ 2\}\}\}\ b\ \{array\ \{\{string\ 3\}\}\}\}\}\n\ \ \ \ \{a\ \{1\ 2\}\ b\ 3\}\n\n\ \ \ \ json-4.7.2\ \"object\ object\ values\"\n\ \ \ \ \{object\ \{x\ \{object\ \{a\ \{number\ 1\}\ b\ \{string\ 2\}\}\}\ y\ \{object\ \{a\ \{string\ 3\}\}\}\}\}\n\ \ \ \ \{x\ \{a\ 1\ b\ 2\}\ y\ \{a\ 3\}\}\n\n\ \ \ \ json-4.7.3\ \"object\ string\ values\"\n\ \ \ \ \{object\ \{1\ \{string\ 2\}\ 3\ \{string\ 4\}\}\}\ \{1\ 2\ 3\ 4\}\n\n\ \ \ \ json-4.7.4\ \"object\ number\ values\"\n\ \ \ \ \{object\ \{1\ \{number\ 2\}\ 3\ \{number\ 4\}\}\}\ \{1\ 2\ 3\ 4\}\n\n\ \ \ \ json-4.7.5\ \"object\ literal\ values\"\n\ \ \ \ \{object\ \{true\ \{literal\ true\}\ false\ \{literal\ false\}\ null\ \{literal\ null\}\}\}\n\ \ \ \ \{true\ true\ false\ false\ null\ null\}\n\}\ \{\n\ \ \ \ tcltest::test\ \$name\ \$description\ -body\ \[list\ json::values\ \$input\]\\\n\ \ \ \ \ \ \ \ \ \ \ \ -result\ \$output\n\}\n\nforeach\ \{name\ description\ schema\ values\ output\}\ \{\n\ \ \ \ json-5.1\ \"unite\ array\"\n\ \ \ \ \{array\ \{number\ number\ number\ number\}\}\ \{0\ 1\ 2\ 3\}\n\ \ \ \ \{array\ \{\{number\ 0\}\ \{number\ 1\}\ \{number\ 2\}\ \{number\ 3\}\}\}\n\n\ \ \ \ json-5.2\ \"unite\ object\"\n\ \ \ \ \{object\ \{foo\ number\ bar\ number\ quux\ number\}\}\ \{foo\ 0\ bar\ 1\ quux\ 2\}\n\ \ \ \ \{object\ \{foo\ \{number\ 0\}\ bar\ \{number\ 1\}\ quux\ \{number\ 2\}\}\}\n\n\ \ \ \ json-5.3\ \"unite\ string\"\n\ \ \ \ string\ \{hello\ world\}\ \{string\ \{hello\ world\}\}\n\n\ \ \ \ json-5.4\ \"unite\ number\"\n\ \ \ \ number\ 42\ \{number\ 42\}\n\n\ \ \ \ json-5.5\ \"unite\ literal\"\n\ \ \ \ literal\ true\ \{literal\ true\}\n\n\ \ \ \ json-5.6.1\ \"unite\ array\ array\"\n\ \ \ \ \{array\ \{\{array\ number\}\ \{array\ \{string\ literal\}\}\}\}\ \{1\ \{3\ false\}\}\n\ \ \ \ \{array\ \{\{array\ \{\{number\ 1\}\}\}\ \{array\ \{\{string\ 3\}\ \{literal\ false\}\}\}\}\}\n\n\ \ \ \ json-5.6.2\ \"unite\ array\ array\ number\"\n\ \ \ \ \{array\ \{\{array\ \{number\ number\}\}\ \{array\ \{number\ number\}\}\}\}\ \{\{1\ 2\}\ \{3\ 4\}\}\n\ \ \ \ \{array\ \{\{array\ \{\{number\ 1\}\ \{number\ 2\}\}\}\ \{array\ \{\{number\ 3\}\ \{number\ 4\}\}\}\}\}\n\n\ \ \ \ json-5.6.3\ \"unite\ array\ object\"\n\ \ \ \ \{array\ \{\{object\ \{a\ number\ b\ string\}\}\ \{object\ \{a\ string\}\}\}\}\ \{\{a\ 1\ b\ 2\}\ \{a\ 3\}\}\n\ \ \ \ \{array\ \{\{object\ \{a\ \{number\ 1\}\ b\ \{string\ 2\}\}\}\ \{object\ \{a\ \{string\ 3\}\}\}\}\}\n\n\ \ \ \ json-5.6.4\ \"unite\ array\ string\"\n\ \ \ \ \{array\ \{string\ string\ string\ string\}\}\ \{1\ 2\ 3\ 4\}\n\ \ \ \ \{array\ \{\{string\ 1\}\ \{string\ 2\}\ \{string\ 3\}\ \{string\ 4\}\}\}\n\n\ \ \ \ json-5.6.5\ \"unite\ array\ number\"\n\ \ \ \ \{array\ \{number\ number\ number\ number\}\}\ \{1\ 2\ 3\ 4\}\n\ \ \ \ \{array\ \{\{number\ 1\}\ \{number\ 2\}\ \{number\ 3\}\ \{number\ 4\}\}\}\n\n\ \ \ \ json-5.6.6\ \"unite\ array\ literal\"\n\ \ \ \ \{array\ \{literal\ literal\ literal\}\}\ \{true\ false\ null\}\n\ \ \ \ \{array\ \{\{literal\ true\}\ \{literal\ false\}\ \{literal\ null\}\}\}\n\n\ \ \ \ json-5.7.1\ \"unite\ object\ array\"\n\ \ \ \ \{object\ \{a\ \{array\ \{number\ number\}\}\ b\ \{array\ string\}\}\}\ \{a\ \{1\ 2\}\ b\ 3\}\n\ \ \ \ \{object\ \{a\ \{array\ \{\{number\ 1\}\ \{number\ 2\}\}\}\ b\ \{array\ \{\{string\ 3\}\}\}\}\}\n\n\ \ \ \ json-5.7.2\ \"unite\ object\ object\"\n\ \ \ \ \{object\ \{x\ \{object\ \{a\ number\ b\ string\}\}\ y\ \{object\ \{a\ string\}\}\}\}\n\ \ \ \ \{x\ \{a\ 1\ b\ 2\}\ y\ \{a\ 3\}\}\n\ \ \ \ \{object\ \{x\ \{object\ \{a\ \{number\ 1\}\ b\ \{string\ 2\}\}\}\ y\ \{object\ \{a\ \{string\ 3\}\}\}\}\}\n\n\ \ \ \ json-5.7.3\ \"unite\ object\ string\"\n\ \ \ \ \{object\ \{1\ string\ 3\ string\}\}\ \{1\ 2\ 3\ 4\}\ \{object\ \{1\ \{string\ 2\}\ 3\ \{string\ 4\}\}\}\n\n\ \ \ \ json-5.7.4\ \"unite\ object\ number\"\n\ \ \ \ \{object\ \{1\ number\ 3\ number\}\}\ \{1\ 2\ 3\ 4\}\ \{object\ \{1\ \{number\ 2\}\ 3\ \{number\ 4\}\}\}\n\n\ \ \ \ json-5.7.5\ \"unite\ object\ literal\"\n\ \ \ \ \{object\ \{true\ literal\ false\ literal\ null\ literal\}\}\n\ \ \ \ \{true\ true\ false\ false\ null\ null\}\n\ \ \ \ \{object\ \{true\ \{literal\ true\}\ false\ \{literal\ false\}\ null\ \{literal\ null\}\}\}\n\}\ \{\n\ \ \ \ tcltest::test\ \$name\ \$description\ -body\ \[list\ json::unite\ \$schema\ \$values\]\\\n\ \ \ \ \ \ \ \ \ \ \ \ -result\ \$output\n\}\n\ntcltest::cleanupTests\n======\n\n**TODO**\n\n\ \ \ *\ \[\[json::encode\]\]\ pretty\ print\ options\n\ \ \ *\ \[\[json::decode\]\]\ type\ compression\ option\n\ \ \ *\ \[\[json::decode\]\]\ type\ suppression\ option\n\ \ \ *\ Tests\ for\ \[\[json::decode\]\]\ whitespace\ tolerance\n\ \ \ *\ Tests\ for\ error\ detection\n\ \ \ *\ Submit\ to\ \[tcllib\],\ or\ too\ much\ overlap\ with\ \[huddle\]\ and\ \[Tcllib\ JSON\]?\n\n<<categories>>\ Internet\ |\ JSON regexp2} CALL {my render {Alternative JSON} \[AMG\]:\ \[\[json::encode\]\]\ and\ \[\[json::decode\]\]\ convert\ between\ a\ tagged\ data\ format\ and\ JSON.\ \ \[\[json::schema\]\]\ and\ \[\[json::values\]\]\ split\ the\ tagged\ data\ format\ into\ the\ schema\ and\ values\ components,\ and\ \[\[json::unite\]\]\ combine\ the\ schema\ and\ value\ components\ into\ the\ tagged\ data\ format.\n\n**Types**\n\nThe\ available\ type\ tags\ are:\n\n\ \ \ array\ \ \ :\ \ \ List\ of\ elements.\n\ \ \ object\ \ \ :\ \ \ Key-value\ dictionary\ of\ elements.\n\ \ \ string\ \ \ :\ \ \ Arbitrary\ string\ value.\n\ \ \ number\ \ \ :\ \ \ Integer\ and\ real\ numeric\ value.\n\ \ \ literal\ \ \ :\ \ \ false,\ null,\ or\ true.\n\ \ \ raw\ \ \ :\ \ \ Preformatted\ JSON\ text.\n\nArray\ and\ object\ type\ composition\ is\ supported\ in\ two\ ways.\ \ If\ the\ type\ is\ array\ or\ object,\ each\ element\ is\ represented\ as\ a\ two-element\ list,\ being\ the\ type\ and\ the\ value.\ \ This\ gets\ quite\ cumbersome\ when\ the\ values\ all\ have\ uniform\ type,\ so\ the\ outer\ type\ may\ be\ a\ two-element\ list,\ the\ second\ of\ which\ is\ the\ type\ used\ for\ all\ values.\ \ More\ deeply\ nested\ data\ structures\ can\ be\ defined\ either\ by\ further\ nesting\ the\ second\ type\ element\ or\ by\ flattening\ the\ list.\n\n**Examples**\n\n***Format***\n\n%|JSON|Tagged\ Data|%\n&|`\"hello\"`|`string\ hello`|&\n&|`42`|`number\ 42`|&\n&|`null`|`literal\ null`|&\n&|`\[\[\"hello\",42,null\]\]`|`array\ \{\{string\ hello\}\ \{number\ 42\}\ \{literal\ null\}\}`|&\n&|`\[\[\[\[1,2\]\],\[\[3,4\]\]\]\]`|`\{array\ array\ number\}\ \{\{1\ 2\}\ \{3\ 4\}\}`|&\n&|`\{\"a\":1,\"b\":2\}`|`\{object\ number\}\ \{a\ 1\ b\ 2\}`|&\n&|`\{\"a\":1,\"b\":2\}`|`raw\ \{\{\"a\":1,\"b\":2\}\}`|&\n\n***Usage***\n\n======none\n%\ json::encode\ \{string\ hello\}\n\"hello\"\n%\ json::encode\ \{number\ 42\}\n42\n%\ json::encode\ \{literal\ null\}\nnull\n%\ json::encode\ \{array\ \{\{string\ hello\}\ \{number\ 42\}\ \{literal\ null\}\}\}\n\[\"hello\",42,null\]\n%\ json::encode\ \{object\ \{foo\ \{string\ hello\}\ bar\ \{number\ 42\}\ quux\ \{literal\ null\}\}\}\n\{\"foo\":\"hello\",\"bar\":42,\"quux\":null\}\n%\ json::encode\ \{array\ \{\{array\ \{\{number\ 1\}\ \{number\ 2\}\}\}\ \{array\ \{\{number\ 3\}\ \{number\ 4\}\}\}\}\}\n\[\[1,2\],\[3,4\]\]\n%\ json::encode\ \{\{array\ \{array\ number\}\}\ \{\{1\ 2\}\ \{3\ 4\}\}\}\n\[\[1,2\],\[3,4\]\]\n%\ json::encode\ \{\{array\ array\ number\}\ \{\{1\ 2\}\ \{3\ 4\}\}\}\n\[\[1,2\],\[3,4\]\]\n%\ json::encode\ \{\{array\ array\ string\}\ \{\{1\ 2\}\ \{3\ 4\}\}\}\n\[\[\"1\",\"2\"\],\[\"3\",\"4\"\]\]\n%\ json::encode\ \{\{object\ object\ string\}\ \{name\ \{first\ Andy\ last\ Goth\}\ address\ \{web\ http://tcl.tk/\}\}\}\n\{\"name\":\{\"first\":\"Andy\",\"last\":\"Goth\"\},\"address\":\{\"web\":\"http://tcl.tk/\"\}\}\n%\ json::decode\ \{\"hello\"\}\nstring\ hello\n%\ json::decode\ 42\nnumber\ 42\n%\ json::decode\ null\nliteral\ null\n%\ json::decode\ \{\[\"hello\",42,null\]\}\narray\ \{\{string\ hello\}\ \{number\ 42\}\ \{literal\ null\}\}\n%\ json::decode\ \{\{\"foo\":\"hello\",\"bar\":42,\"quux\":null\}\}\nobject\ \{foo\ \{string\ hello\}\ bar\ \{number\ 42\}\ quux\ \{literal\ null\}\}\n%\ json::decode\ \{\[\[1,2\],\[3,4\]\]\}\narray\ \{\{array\ \{\{number\ 1\}\ \{number\ 2\}\}\}\ \{array\ \{\{number\ 3\}\ \{number\ 4\}\}\}\}\n%\ json::decode\ \{\{\"name\":\{\"first\":\"Andy\",\"last\":\"Goth\"\},\"address\":\{\"web\":\"http://tcl.tk/\"\}\}\}\nobject\ \{name\ \{object\ \{first\ \{string\ Andy\}\ last\ \{string\ Goth\}\}\}\ address\ \{object\ \{web\ \{string\ http://tcl.tk/\}\}\}\}\n%\ json::schema\ \{\{\"name\":\{\"first\":\"Andy\",\"last\":\"Goth\"\},\"address\":\{\"web\":\"http://tcl.tk/\"\}\}\}\nobject\ \{name\ \{object\ \{first\ string\}\}\ last\ string\}\ address\ \{object\ \{web\ string\}\}\n%\ json::values\ \{\{\"name\":\{\"first\":\"Andy\",\"last\":\"Goth\"\},\"address\":\{\"web\":\"http://tcl.tk/\"\}\}\}\nname\ \{first\ Andy\ last\ Goth\}\ address\ \{web\ http://tcl.tk/\}\n%\ json::schema\ \[json::decode\ \{\"foo\":\"hello\",\"bar\":42,\"quux\":null\}\]\nobject\ \{foo\ string\ bar\ number\ quux\ literal\}\n%\ json::values\ \[json::decode\ \{\"foo\":\"hello\",\"bar\":42,\"quux\":null\}\]\nfoo\ hello\ bar\ 42\ quux\ null\n%\ json::unite\ \{object\ \{foo\ string\ bar\ number\ quux\ literal\}\}\ \{foo\ hello\ bar\ 42\ quux\ null\}\n\{object\ \{foo\ \{string\ hello\}\ bar\ \{number\ 42\}\ quux\ \{literal\ null\}\}\}\n%\ json::encode\ \[json::unite\ \{object\ \{foo\ string\ bar\ number\ quux\ literal\}\}\ \{foo\ hello\ bar\ 42\ quux\ null\}\]\n\{\"foo\":\"hello\",\"bar\":42,\"quux\":null\}\n======\n\n**Implementation**\n\nFirst,\ create\ the\ namespace.\n\n======none\nnamespace\ eval\ ::json\ \{\}\n======\n\n***\[\[json::encode\]\]***\n\n======none\n#\ ::json::encode\ --\n#\ Encodes\ data\ in\ the\ JSON\ format\ per\ https://tools.ietf.org/html/rfc7159.\nproc\ ::json::encode\ \{data\}\ \{\n\ \ \ \ #\ Extract\ type\ and\ value\ from\ data\ argument.\n\ \ \ \ if\ \{\[llength\ \$data\]\ !=\ 2\}\ \{\n\ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ data:\ must\ be\ a\ two-element\ list\ consisting\ of\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ type\ and\ value\"\n\ \ \ \ \}\n\ \ \ \ lassign\ \$data\ type\ value\n\n\ \ \ \ #\ Extract\ top\ and\ subtype\ from\ type\ element.\n\ \ \ \ set\ toptype\ \[lindex\ \$type\ 0\]\n\ \ \ \ if\ \{\[llength\ \$type\]\ >=\ 2\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$type\]\ ==\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ subtype\ \[lindex\ \$type\ 1\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ subtype\ \[lrange\ \$type\ 1\ end\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\$toptype\ ni\ \{array\ object\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ toptype\ \{\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Perform\ type-specific\ JSON\ encoding.\n\ \ \ \ switch\ \$toptype\ \{\n\ \ \ \ array\ \{\n\ \ \ \ \ \ \ \ #\ Recursively\ encode\ each\ array\ element.\ \ If\ a\ subtype\ was\ specified,\ it\n\ \ \ \ \ \ \ \ #\ is\ shared\ between\ all\ elements.\ \ Otherwise,\ each\ element\ is\ itself\ a\n\ \ \ \ \ \ \ \ #\ two-element\ list\ consisting\ of\ type\ and\ value.\n\ \ \ \ \ \ \ \ set\ comma\ \{\}\n\ \ \ \ \ \ \ \ set\ result\ \\\[\n\ \ \ \ \ \ \ \ foreach\ element\ \$value\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ append\ result\ \$comma\n\ \ \ \ \ \ \ \ \ \ \ \ set\ comma\ ,\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ subtype\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ result\ \[encode\ \[list\ \$subtype\ \$element\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ result\ \[encode\ \$element\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ append\ result\ \\\]\n\ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \}\ object\ \{\n\ \ \ \ \ \ \ \ #\ Recursively\ encode\ each\ object\ key\ and\ element.\ \ Keys\ are\ always\n\ \ \ \ \ \ \ \ #\ strings.\ \ If\ a\ subtype\ was\ specified,\ it\ is\ shared\ between\ all\n\ \ \ \ \ \ \ \ #\ elements.\ \ Otherwise,\ each\ element\ is\ itself\ a\ two-element\ list\n\ \ \ \ \ \ \ \ #\ consisting\ of\ type\ and\ underlying\ data\ value.\n\ \ \ \ \ \ \ \ set\ comma\ \{\}\n\ \ \ \ \ \ \ \ set\ result\ \\\{\n\ \ \ \ \ \ \ \ foreach\ \{key\ element\}\ \$value\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ append\ result\ \$comma\n\ \ \ \ \ \ \ \ \ \ \ \ set\ comma\ ,\n\ \ \ \ \ \ \ \ \ \ \ \ append\ result\ \[encode\ \[list\ string\ \$key\]\]\ :\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ subtype\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ result\ \[encode\ \[list\ \$subtype\ \$element\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ result\ \[encode\ \$element\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ append\ result\ \\\}\n\ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \}\ string\ \{\n\ \ \ \ \ \ \ \ #\ Encode\ the\ minimal\ set\ of\ required\ escape\ sequences.\n\ \ \ \ \ \ \ \ return\ \\\"\[string\ map\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \\x00\ \\\\u0000\ \ \ \ \\x01\ \\\\u0001\ \ \ \ \\x02\ \\\\u0002\ \ \ \ \\x03\ \\\\u0003\n\ \ \ \ \ \ \ \ \ \ \ \ \\x04\ \\\\u0004\ \ \ \ \\x05\ \\\\u0005\ \ \ \ \\x06\ \\\\u0006\ \ \ \ \\x07\ \\\\u0007\n\ \ \ \ \ \ \ \ \ \ \ \ \\x08\ \\\\u0008\ \ \ \ \\x09\ \\\\u0009\ \ \ \ \\x0a\ \\\\u000a\ \ \ \ \\x0b\ \\\\u000b\n\ \ \ \ \ \ \ \ \ \ \ \ \\x0c\ \\\\u000c\ \ \ \ \\x0d\ \\\\u000d\ \ \ \ \\x0e\ \\\\u000e\ \ \ \ \\x0f\ \\\\u000f\n\ \ \ \ \ \ \ \ \ \ \ \ \\x10\ \\\\u0010\ \ \ \ \\x11\ \\\\u0011\ \ \ \ \\x12\ \\\\u0012\ \ \ \ \\x13\ \\\\u0013\n\ \ \ \ \ \ \ \ \ \ \ \ \\x14\ \\\\u0014\ \ \ \ \\x15\ \\\\u0015\ \ \ \ \\x16\ \\\\u0016\ \ \ \ \\x17\ \\\\u0017\n\ \ \ \ \ \ \ \ \ \ \ \ \\x18\ \\\\u0018\ \ \ \ \\x19\ \\\\u0019\ \ \ \ \\x1a\ \\\\u001a\ \ \ \ \\x1b\ \\\\u001b\n\ \ \ \ \ \ \ \ \ \ \ \ \\x1c\ \\\\u001c\ \ \ \ \\x1d\ \\\\u001d\ \ \ \ \\x1e\ \\\\u001e\ \ \ \ \\x1f\ \\\\u001f\n\ \ \ \ \ \ \ \ \ \ \ \ \\\\\ \ \ \\\\\\\\\ \ \ \ \ \ \ \\\"\ \ \ \\\\\\\"\n\ \ \ \ \ \ \ \ \}\ \$value\]\\\"\n\ \ \ \ \}\ number\ \{\n\ \ \ \ \ \ \ \ #\ Attempt\ to\ normalize\ the\ number\ to\ comply\ with\ the\ JSON\ standard.\n\ \ \ \ \ \ \ \ regsub\ \{^\[\\f\\n\\r\\t\\v\ \]+\}\ \$value\ \{\}\ result\ \ \ \ \ \;#\ Strip\ leading\ space.\n\ \ \ \ \ \ \ \ regsub\ \{\[\\f\\n\\r\\t\\v\ \]+\$\}\ \$result\ \{\}\ result\ \ \ \ \;#\ Strip\ trailing\ space.\n\ \ \ \ \ \ \ \ regsub\ \{^\\+(?=\[\\d.\])\}\ \$result\ \{\}\ result\ \ \ \ \ \ \ \;#\ Strip\ leading\ plus.\n\ \ \ \ \ \ \ \ regsub\ \{^(-?)0+(?=\\d)\}\ \$result\ \{\\1\}\ result\ \ \ \ \;#\ Strip\ leading\ zeroes.\n\ \ \ \ \ \ \ \ regsub\ \{(\\.\\d*\[1-9\])0+\}\ \$result\ \{\\1\}\ result\ \ \ \;#\ Strip\ trailing\ zeroes.\n\ \ \ \ \ \ \ \ regsub\ \{E\}\ \$result\ \{e\}\ result\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \;#\ Normalize\ exponent,\ 1.\n\ \ \ \ \ \ \ \ regsub\ \{^(-?\\d+)e\}\ \$result\ \{\\1.0e\}\ result\ \ \ \ \ \;#\ Normalize\ exponent,\ 2.\n\ \ \ \ \ \ \ \ regsub\ \{\\.e\}\ \$result\ \{.0e\}\ result\ \ \ \ \ \ \ \ \ \ \ \ \ \;#\ Normalize\ exponent,\ 3.\n\ \ \ \ \ \ \ \ regsub\ \{e(\\d)\}\ \$result\ \{e+\\1\}\ result\ \ \ \ \ \ \ \ \ \ \;#\ Normalize\ exponent,\ 4.\n\ \ \ \ \ \ \ \ regsub\ \{(^|-)\\.(?=\\d)\}\ \$result\ \{\\10.\}\ result\ \ \;#\ Prefix\ leading\ dot.\n\ \ \ \ \ \ \ \ regsub\ \{(\\d)\\.(?=\\D|\$)\}\ \$result\ \{\\1.0\}\ result\ \;#\ Suffix\ trailing\ dot.\n\ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{^-?(?:0|\[1-9\]\\d*)(?:\\.\\d+)?(?:\[eE\]\[-+\]?\\d+)?\$\}\ \$result\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ number\ \\\"\$value\\\":\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ see\ https://tools.ietf.org/html/rfc7159#section-6\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \}\ literal\ \{\n\ \ \ \ \ \ \ \ #\ The\ only\ valid\ literals\ are\ false,\ null,\ and\ true.\n\ \ \ \ \ \ \ \ if\ \{\$value\ ni\ \{false\ null\ true\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ literal\ \\\"\$value\\\":\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ must\ be\ false,\ null,\ or\ true\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$value\n\ \ \ \ \}\ encoded\ \{\n\ \ \ \ \ \ \ \ #\ Raw\ data.\ \ The\ caller\ must\ supply\ correctly\ formatted\ JSON.\n\ \ \ \ \ \ \ \ return\ \$value\n\ \ \ \ \}\ decoded\ \{\n\ \ \ \ \ \ \ \ #\ Nested\ decoded\ data.\n\ \ \ \ \ \ \ \ encode\ \$value\n\ \ \ \ \}\ default\ \{\n\ \ \ \ \ \ \ \ #\ Invalid\ type.\n\ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ type\ \\\"\$type\\\":\ must\ be\ array,\ object,\ string,\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ number,\ literal,\ encoded,\ decoded,\ or\ \{array|object\ ?...?\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subtype\},\ where\ subtype\ is\ recursively\ any\ valid\ JSON\ type\"\n\ \ \ \ \}\}\n\}\n======\n\n***\[\[json::decode\]\]***\n\n======none\n#\ ::json::decode\ --\n#\ Decodes\ data\ from\ the\ JSON\ format\ per\ https://tools.ietf.org/html/rfc7159.\n#\ The\ optional\ indexVar\ argument\ is\ the\ name\ of\ a\ variable\ that\ holds\ the\ index\n#\ at\ which\ decoding\ begins\ (defaults\ to\ 0\ if\ the\ variable\ doesn't\ exist)\ and\n#\ will\ hold\ the\ index\ immediately\ following\ the\ end\ of\ the\ decoded\ element.\ \ If\n#\ indexVar\ is\ not\ specified,\ the\ entire\ JSON\ input\ is\ decoded,\ and\ it\ is\ an\n#\ error\ for\ it\ to\ be\ followed\ by\ any\ non-whitespace\ characters.\nproc\ ::json::decode\ \{json\ \{indexVar\ \{\}\}\}\ \{\n\ \ \ \ #\ Link\ to\ the\ caller's\ index\ variable.\n\ \ \ \ if\ \{\$indexVar\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ upvar\ 1\ \$indexVar\ index\n\ \ \ \ \}\n\n\ \ \ \ #\ By\ default,\ start\ decoding\ at\ the\ start\ of\ the\ input.\n\ \ \ \ if\ \{!\[info\ exists\ index\]\}\ \{\n\ \ \ \ \ \ \ \ set\ index\ 0\n\ \ \ \ \}\n\n\ \ \ \ #\ Skip\ leading\ whitespace.\ \ Return\ empty\ at\ end\ of\ input.\n\ \ \ \ if\ \{!\[regexp\ -indices\ -start\ \$index\ \{\[^\\t\\n\\r\ \]\}\ \$json\ range\]\}\ \{\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\ \ \ \ set\ index\ \[lindex\ \$range\ 0\]\n\n\ \ \ \ #\ The\ first\ character\ determines\ the\ JSON\ element\ type.\n\ \ \ \ switch\ \[string\ index\ \$json\ \$index\]\ \{\n\ \ \ \ \\\"\ \{\n\ \ \ \ \ \ \ \ #\ JSON\ strings\ start\ with\ double\ quote.\n\ \ \ \ \ \ \ \ set\ type\ string\n\n\ \ \ \ \ \ \ \ #\ The\ value\ is\ the\ text\ between\ matching\ double\ quotes.\n\ \ \ \ \ \ \ \ if\ \{!\[regexp\ -indices\ -start\ \$index\ \{\\A\\\"((?:\[^\"\]|\\\\.)*)\\\"\}\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$json\ range\ sub\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ error\ \"invalid\ JSON\ string\ at\ index\ \$index:\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ must\ end\ with\ close\ quote\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ value\ \[string\ range\ \$json\ \{*\}\$sub\]\n\n\ \ \ \ \ \ \ \ #\ Process\ all\ backslash\ substitutions\ in\ the\ value.\n\ \ \ \ \ \ \ \ set\ start\ 0\n\ \ \ \ \ \ \ \ while\ \{\[regexp\ -indices\ -start\ \$start\ \{\\\\u\[\[:xdigit:\]\]\{4\}|\\\\\[^u\]\}\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$value\ sub\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ char\ \[string\ index\ \$value\ \[expr\ \{\[lindex\ \$sub\ 0\]\ +\ 1\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ switch\ \$char\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ u\ \{set\ char\ \[subst\ \[string\ range\ \$value\ \{*\}\$sub\]\]\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ b\ \{set\ char\ \\b\}\ f\ \{set\ char\ \\f\}\ n\ \{set\ char\ \\n\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ r\ \{set\ char\ \\r\}\ t\ \{set\ char\ \\t\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ value\ \[string\ replace\ \$value\ \{*\}\$sub\ \$char\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ start\ \[expr\ \{\[lindex\ \$sub\ 0\]\ +\ 1\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ \\\{\ -\ \\\[\ \{\n\ \ \ \ \ \ \ \ #\ JSON\ objects/arrays\ start\ with\ open\ brace/bracket.\n\ \ \ \ \ \ \ \ if\ \{\[string\ index\ \$json\ \$index\]\ eq\ \"\\\{\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ type\ object\n\ \ \ \ \ \ \ \ \ \ \ \ set\ endRe\ \{\\A\[\\t\\n\\r\ \]*\\\}\}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ charName\ brace\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ type\ array\n\ \ \ \ \ \ \ \ \ \ \ \ set\ endRe\ \{\\A\[\\t\\n\\r\ \]*\\\]\}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ charName\ bracket\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ value\ \{\}\n\ \ \ \ \ \ \ \ incr\ index\n\n\ \ \ \ \ \ \ \ #\ Loop\ until\ close\ brace/bracket\ is\ encountered.\n\ \ \ \ \ \ \ \ while\ \{!\[regexp\ -indices\ -start\ \$index\ \$endRe\ \$json\ range\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Each\ element\ other\ than\ the\ first\ is\ preceded\ by\ comma.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$value\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[regexp\ -indices\ -start\ \$index\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{\\A\[\\t\\n\\r\ \]*,\}\ \$json\ range\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ error\ \"invalid\ JSON\ \$type\ at\ index\ \$index:\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ element\ not\ followed\ by\ comma\ or\ close\ \$charName\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ index\ \[expr\ \{\[lindex\ \$range\ 1\]\ +\ 1\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ For\ objects,\ get\ key\ and\ confirm\ it\ is\ followed\ by\ colon.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$type\ eq\ \"object\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ key\ \[decode\ \$json\ index\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[llength\ \$key\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ error\ \"invalid\ JSON\ object\ at\ index\ \$index:\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ must\ end\ with\ close\ brace\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\[lindex\ \$key\ 0\]\ ne\ \"string\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ error\ \"invalid\ JSON\ object\ at\ index\ \$index:\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ key\ type\ is\ \\\"\[lindex\ \$key\ 0\]\\\",\ must\ be\ string\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{!\[regexp\ -indices\ -start\ \$index\ \{\\A\[\\t\\n\\r\ \]*:\}\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$json\ range\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ error\ \"invalid\ JSON\ object\ at\ index\ \$index:\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ key\ not\ followed\ by\ colon\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ index\ \[expr\ \{\[lindex\ \$range\ 1\]\ +\ 1\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ value\ \[lindex\ \$key\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Get\ element\ value.\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ value\ \[decode\ \$json\ index\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ t\ -\ f\ -\ n\ \{\n\ \ \ \ \ \ \ \ #\ JSON\ literals\ are\ true,\ false,\ or\ null.\n\ \ \ \ \ \ \ \ set\ type\ literal\n\ \ \ \ \ \ \ \ if\ \{!\[regexp\ -indices\ -start\ \$index\ \{(?:true|false|null)\\M\}\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$json\ range\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ error\ \"invalid\ JSON\ literal\ at\ index\ \$index\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ value\ \[string\ range\ \$json\ \{*\}\$range\]\n\ \ \ \ \}\ -\ -\ +\ -\ 0\ -\ 1\ -\ 2\ -\ 3\ -\ 4\ -\ 5\ -\ 6\ -\ 7\ -\ 8\ -\ 9\ -\ .\ \{\n\ \ \ \ \ \ \ \ #\ JSON\ numbers\ are\ integers\ or\ real\ numbers.\n\ \ \ \ \ \ \ \ set\ type\ number\n\ \ \ \ \ \ \ \ if\ \{!\[regexp\ -indices\ -start\ \$index\ --\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{-?(?:0|\[1-9\]\\d*)(?:\\.\\d+)?(?:\[eE\]\[-+\]?\\d+)?\\M\}\ \$json\ range\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ error\ \"invalid\ JSON\ number\ at\ index\ \$index\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ value\ \[string\ range\ \$json\ \{*\}\$range\]\n\ \ \ \ \}\ default\ \{\n\ \ \ \ \ \ \ \ #\ JSON\ allows\ only\ the\ above-listed\ types.\n\ \ \ \ \ \ \ \ return\ -code\ error\ \"invalid\ JSON\ data\ at\ index\ \$index\"\n\ \ \ \ \}\}\n\n\ \ \ \ #\ Continue\ decoding\ after\ the\ last\ character\ matched\ above.\n\ \ \ \ set\ index\ \[expr\ \{\[lindex\ \$range\ 1\]\ +\ 1\}\]\n\n\ \ \ \ #\ When\ performing\ a\ full\ decode,\ ensure\ only\ whitespace\ appears\ at\ end.\n\ \ \ \ if\ \{\$indexVar\ eq\ \{\}\ &&\ \[regexp\ -start\ \$index\ \{\[^\\t\\n\\r\\\ \]\}\ \$json\]\}\ \{\n\ \ \ \ \ \ \ \ return\ -code\ error\ \"junk\ at\ end\ of\ JSON\"\n\ \ \ \ \}\n\n\ \ \ \ #\ Return\ the\ type\ and\ value.\n\ \ \ \ list\ \$type\ \$value\n\}\n======\n\n***\[\[json::schema\]\]***\n\n======none\n#\ ::json::schema\ --\n#\ Extracts\ JSON\ type\ information\ from\ the\ output\ of\ \[json::decode\].\nproc\ ::json::schema\ \{data\}\ \{\n\ \ \ \ #\ Extract\ type\ and\ value\ from\ data\ argument.\n\ \ \ \ if\ \{\[llength\ \$data\]\ !=\ 2\}\ \{\n\ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ data:\ must\ be\ a\ two-element\ list\ consisting\ of\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ type\ and\ value\"\n\ \ \ \ \}\n\ \ \ \ lassign\ \$data\ type\ value\n\n\ \ \ \ #\ Extract\ top\ and\ subtype\ from\ type\ element.\n\ \ \ \ set\ toptype\ \[lindex\ \$type\ 0\]\n\ \ \ \ if\ \{\[llength\ \$type\]\ >=\ 2\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$type\]\ ==\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ subtype\ \[lindex\ \$type\ 1\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ subtype\ \[lrange\ \$type\ 1\ end\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\$toptype\ ni\ \{array\ object\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ toptype\ \{\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Perform\ type-specific\ JSON\ processing.\n\ \ \ \ switch\ \$toptype\ \{\n\ \ \ \ array\ \{\n\ \ \ \ \ \ \ \ list\ \$toptype\ \[lmap\ element\ \$value\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ subtype\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ schema\ \[list\ \$subtype\ \$element\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ schema\ \$element\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\ object\ \{\n\ \ \ \ \ \ \ \ list\ \$toptype\ \[dict\ map\ \{key\ element\}\ \$value\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ subtype\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ schema\ \[list\ \$subtype\ \$element\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ schema\ \$element\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\ string\ -\ number\ -\ literal\ \{\n\ \ \ \ \ \ \ \ return\ \$toptype\n\ \ \ \ \}\ encoded\ \{\n\ \ \ \ \ \ \ \ schema\ \[decode\ \$value\]\n\ \ \ \ \}\ decoded\ \{\n\ \ \ \ \ \ \ \ schema\ \$value\n\ \ \ \ \}\ default\ \{\n\ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ type\ \\\"\$type\\\":\ must\ be\ array,\ object,\ string,\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ number,\ literal,\ encoded,\ decoded,\ or\ \{array|object\ ?...?\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subtype\},\ where\ subtype\ is\ recursively\ any\ valid\ JSON\ type\"\n\ \ \ \ \}\}\n\}\n======\n\n***\[\[json::values\]\]***\n\n======none\n#\ ::json::values\ --\n#\ Extracts\ JSON\ value\ information\ from\ the\ output\ of\ \[json::decode\].\nproc\ ::json::values\ \{data\}\ \{\n\ \ \ \ #\ Extract\ type\ and\ value\ from\ data\ argument.\n\ \ \ \ if\ \{\[llength\ \$data\]\ !=\ 2\}\ \{\n\ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ data:\ must\ be\ a\ two-element\ list\ consisting\ of\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ type\ and\ value\"\n\ \ \ \ \}\n\ \ \ \ lassign\ \$data\ type\ value\n\n\ \ \ \ #\ Extract\ top\ and\ subtype\ from\ type\ element.\n\ \ \ \ set\ toptype\ \[lindex\ \$type\ 0\]\n\ \ \ \ if\ \{\[llength\ \$type\]\ >=\ 2\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$type\]\ ==\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ subtype\ \[lindex\ \$type\ 1\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ subtype\ \[lrange\ \$type\ 1\ end\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\$toptype\ ni\ \{array\ object\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ toptype\ \{\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Perform\ type-specific\ JSON\ processing.\n\ \ \ \ switch\ \$toptype\ \{\n\ \ \ \ array\ \{\n\ \ \ \ \ \ \ \ lmap\ element\ \$value\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ subtype\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ values\ \[list\ \$subtype\ \$element\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ values\ \$element\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ object\ \{\n\ \ \ \ \ \ \ \ dict\ map\ \{key\ element\}\ \$value\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ subtype\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ values\ \[list\ \$subtype\ \$element\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ values\ \$element\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ string\ -\ number\ -\ literal\ \{\n\ \ \ \ \ \ \ \ return\ \$value\n\ \ \ \ \}\ encoded\ \{\n\ \ \ \ \ \ \ \ values\ \[decode\ \$value\]\n\ \ \ \ \}\ decoded\ \{\n\ \ \ \ \ \ \ \ values\ \$value\n\ \ \ \ \}\ default\ \{\n\ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ type\ \\\"\$type\\\":\ must\ be\ array,\ object,\ string,\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ number,\ literal,\ encoded,\ decoded,\ or\ \{array|object\ ?...?\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subtype\},\ where\ subtype\ is\ recursively\ any\ valid\ JSON\ type\"\n\ \ \ \ \}\}\n\}\n\n***\[\[json::unite\]\]***\n\n======none\n#\ ::json::unite\ --\n#\ Combines\ the\ output\ of\ \[json::schema\]\ with\ the\ output\ of\ \[json::values\]\ to\n#\ produce\ a\ suitable\ input\ for\ \[json::encode\].\ \ The\ \[json::schema\]\ input\ format\n#\ is\ extended\ to\ allow\ variable-length\ arrays\ and\ objects\ with\ extra,\ missing,\n#\ or\ reordered\ keys.\ \ Repeated\ keys\ are\ not\ allowed.\ \ Variable-length\ arrays\ are\n#\ implemented\ by\ repeating\ the\ defined\ element\ types\ in\ a\ loop.\ \ The\ schema\ may\n#\ also\ contain\ encoded\ and\ decoded\ types,\ signifying\ that\ the\ corresponding\n#\ value\ is\ a\ raw\ JSON\ string\ or\ a\ decoded\ JSON\ document.\nproc\ ::json::unite\ \{schema\ values\}\ \{\n\ \ \ \ switch\ \[lindex\ \$schema\ 0\]\ \{\n\ \ \ \ array\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$schema\]\ !=\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ array:\ must\ be\ a\ two-element\ list\ with\ second\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ element\ being\ list\ of\ array\ element\ types\"\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Repeat\ and/or\ trim\ the\ subtype\ list\ to\ the\ value\ list\ length.\n\ \ \ \ \ \ \ \ set\ subtypes\ \[lindex\ \$schema\ 1\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$subtypes\]\ <\ \[llength\ \$values\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ subtypes\ \[lrepeat\ \[expr\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\[llength\ \$values\]\ +\ \[llength\ \$subtypes\]\ -\ 1)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ /\ \[llength\ \$subtypes\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \{*\}\$subtypes\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$subtypes\]\ >\ \[llength\ \$values\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ subtypes\ \[lreplace\ \$subtypes\ \[llength\ \$values\]\ end\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Process\ each\ element.\n\ \ \ \ \ \ \ \ list\ array\ \[lmap\ subtype\ \$subtypes\ value\ \$values\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ unite\ \$subtype\ \$value\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\ object\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$schema\]\ !=\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ array:\ must\ be\ a\ two-element\ list\ with\ second\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ element\ being\ dict\ of\ object\ element\ types\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ list\ object\ \[dict\ map\ \{key\ value\}\ \$values\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \[lindex\ \$schema\ 1\]\ \$key\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unite\ \[dict\ get\ \[lindex\ \$schema\ 1\]\ \$key\]\ \$value\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\[dict\ exists\ \[lindex\ \$schema\ 1\]\ \{\}\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unite\ \[dict\ get\ \[lindex\ \$schema\ 1\]\ \{\}\]\ \$value\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"key\ not\ defined\ in\ schema:\ \$key\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\ string\ -\ number\ -\ literal\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$schema\]\ !=\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ \[lindex\ \$schema\ 0\]:\ must\ be\ a\ one-element\ list\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ list\ \[lindex\ \$schema\ 0\]\ \$values\n\ \ \ \ \}\ encoded\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$schema\]\ !=\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"invalid\ encoded\ JSON:\ must\ be\ a\ one-element\ list\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ decode\ \[lindex\ \$values\ 0\]\n\ \ \ \ \}\ decoded\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$schema\]\ !=\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"invalid\ decoded\ JSON:\ must\ be\ a\ two-element\ list\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$values\n\ \ \ \ \}\ default\ \{\n\ \ \ \ \ \ \ \ error\ \"invalid\ JSON\ type\ \\\"\[lindex\ \$schema\ 0\]\\\":\ must\ be\ array,\ object,\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ string,\ number,\ literal,\ encoded,\ or\ decoded\"\n\ \ \ \ \}\}\n\}\n======\n\n**Testing**\n\nOld\ test\ suite:\n\n======none\npackage\ require\ tcltest\nforeach\ \{name\ json::encode\ json::decode\ description\ tcl\ json\}\ \{\n\ \ \ \ 1.1\ 1\ 1\ \"empty\ string\"\n\ \ \ \ \ \ \ \ \{string\ \{\}\}\n\ \ \ \ \ \ \ \ \{\"\"\}\n\ \ \ \ 1.2\ 1\ 1\ \"nonempty\ string\"\n\ \ \ \ \ \ \ \ \{string\ hello\}\n\ \ \ \ \ \ \ \ \{\"hello\"\}\n\ \ \ \ 1.3\ 1\ 0\ \"string\ with\ quoted\ characters\"\n\ \ \ \ \ \ \ \ \{string\ \\\"a\\nb\\\\c\\\"\}\n\ \ \ \ \ \ \ \ \{\"\\\"a\\u000ab\\\\c\\\"\"\}\n\ \ \ \ 1.4\ 1\ 1\ \"string\ with\ canonical\ quoted\ characters\"\n\ \ \ \ \ \ \ \ \"string\ \\\{\\\"a\\nb\\\\c\\\"\\\}\"\n\ \ \ \ \ \ \ \ \{\"\\\"a\\u000ab\\\\c\\\"\"\}\n\ \ \ \ 2.1\ 1\ 1\ integer\n\ \ \ \ \ \ \ \ \{number\ 42\}\n\ \ \ \ \ \ \ \ 42\n\ \ \ \ 2.2\ 1\ 1\ \"negative\ integer\"\n\ \ \ \ \ \ \ \ \{number\ -42\}\n\ \ \ \ \ \ \ \ -42\n\ \ \ \ 2.3\ 1\ 0\ \"positive\ integer\"\n\ \ \ \ \ \ \ \ \{number\ +42\}\n\ \ \ \ \ \ \ \ 42\n\ \ \ \ 2.4\ 1\ 0\ \"leading\ zeroes\"\n\ \ \ \ \ \ \ \ \{number\ 000\}\n\ \ \ \ \ \ \ \ 0\n\ \ \ \ 2.5\ 1\ 1\ zero\n\ \ \ \ \ \ \ \ \{number\ 0\}\n\ \ \ \ \ \ \ \ 0\n\ \ \ \ 2.6\ 1\ 1\ \"negative\ zero\"\n\ \ \ \ \ \ \ \ \{number\ -0\}\n\ \ \ \ \ \ \ \ -0\n\ \ \ \ 2.7\ 1\ 0\ \"negative\ zero\ with\ leading\ zeroes\"\n\ \ \ \ \ \ \ \ \{number\ -000\}\n\ \ \ \ \ \ \ \ -0\n\ \ \ \ 2.8\ 1\ 1\ \"real\ number\"\n\ \ \ \ \ \ \ \ \{number\ 1.23\}\n\ \ \ \ \ \ \ \ 1.23\n\ \ \ \ 2.9\ 1\ 1\ \"negative\ real\ number\"\n\ \ \ \ \ \ \ \ \{number\ -1.23\}\n\ \ \ \ \ \ \ \ -1.23\n\ \ \ \ 2.10\ 1\ 1\ \"negative\ real\ number\ with\ exponent\"\n\ \ \ \ \ \ \ \ \{number\ -1e5\}\n\ \ \ \ \ \ \ \ -1e5\n\ \ \ \ 2.11\ 1\ 1\ \"real\ number\ with\ capital\ exponent\"\n\ \ \ \ \ \ \ \ \{number\ 1E5\}\n\ \ \ \ \ \ \ \ 1E5\n\ \ \ \ 2.12\ 1\ 1\ \"real\ number\ with\ fraction\ and\ exponent\"\n\ \ \ \ \ \ \ \ \{number\ 1.23e4\}\n\ \ \ \ \ \ \ \ 1.23e4\n\ \ \ \ 2.13\ 1\ 0\ \"positive\ real\ number\ with\ fraction\ and\ positive\ exponent\"\n\ \ \ \ \ \ \ \ \{number\ +1.23e+4\}\n\ \ \ \ \ \ \ \ 1.23e+4\n\ \ \ \ 2.14\ 1\ 1\ \"real\ number\ with\ fraction\ and\ negative\ exponent\"\n\ \ \ \ \ \ \ \ \{number\ 1.23e-4\}\n\ \ \ \ \ \ \ \ 1.23e-4\n\ \ \ \ 2.15\ 1\ 0\ \"real\ number\ with\ dot\ and\ no\ fraction\"\n\ \ \ \ \ \ \ \ \{number\ 1.\}\n\ \ \ \ \ \ \ \ 1.0\n\ \ \ \ 2.16\ 1\ 0\ \"real\ number\ with\ dot\ and\ no\ integer\"\n\ \ \ \ \ \ \ \ \{number\ .1\}\n\ \ \ \ \ \ \ \ 0.1\n\ \ \ \ 2.17\ 1\ 0\ \"real\ number\ with\ dot,\ no\ fraction,\ and\ exponent\"\n\ \ \ \ \ \ \ \ \{number\ 1.E5\}\n\ \ \ \ \ \ \ \ 1.0E5\n\ \ \ \ 2.18\ 1\ 0\ \"real\ number\ with\ dot,\ no\ integer,\ and\ exponent\"\n\ \ \ \ \ \ \ \ \{number\ .1E-5\}\n\ \ \ \ \ \ \ \ 0.1E-5\n\ \ \ \ 2.19\ 1\ 0\ \"real\ number\ with\ leading\ zeroes\"\n\ \ \ \ \ \ \ \ \{number\ 00123.45\}\n\ \ \ \ \ \ \ \ 123.45\n\ \ \ \ 2.20\ 1\ 0\ \"small\ real\ number\ with\ leading\ zeroes\"\n\ \ \ \ \ \ \ \ \{number\ 00000.45\}\n\ \ \ \ \ \ \ \ 0.45\n\ \ \ \ 2.21\ 1\ 0\ \"zero\ real\ number\ with\ leading\ zeroes\ and\ exponent\"\n\ \ \ \ \ \ \ \ \{number\ 00000e9\}\n\ \ \ \ \ \ \ \ 0e9\n\ \ \ \ 3.1\ 1\ 1\ \"literal\ false\"\n\ \ \ \ \ \ \ \ \{literal\ false\}\n\ \ \ \ \ \ \ \ false\n\ \ \ \ 3.2\ 1\ 1\ \"literal\ null\"\n\ \ \ \ \ \ \ \ \{literal\ null\}\n\ \ \ \ \ \ \ \ null\n\ \ \ \ 3.3\ 1\ 1\ \"literal\ true\"\n\ \ \ \ \ \ \ \ \{literal\ true\}\n\ \ \ \ \ \ \ \ true\n\ \ \ \ 4.1\ 1\ 1\ \"array\ with\ variable\ type\"\n\ \ \ \ \ \ \ \ \{array\ \{\{string\ hello\}\ \{number\ 42\}\ \{literal\ null\}\}\}\n\ \ \ \ \ \ \ \ \{\[\"hello\",42,null\]\}\n\ \ \ \ 4.2\ 1\ 1\ \"array\ with\ constant\ but\ unshared\ type\"\n\ \ \ \ \ \ \ \ \{array\ \{\{array\ \{\{number\ 1\}\ \{number\ 2\}\}\}\ \{array\ \{\{number\ 3\}\ \{number\ 4\}\}\}\}\}\n\ \ \ \ \ \ \ \ \{\[\[1,2\],\[3,4\]\]\}\n\ \ \ \ 4.3\ 1\ 0\ \"array\ with\ shared\ type,\ nested\ syntax\"\n\ \ \ \ \ \ \ \ \{\{array\ \{array\ number\}\}\ \{\{1\ 2\}\ \{3\ 4\}\}\}\n\ \ \ \ \ \ \ \ \{\[\[1,2\],\[3,4\]\]\}\n\ \ \ \ 4.4\ 1\ 0\ \"array\ with\ shared\ type,\ flattened\ syntax\"\n\ \ \ \ \ \ \ \ \{\{array\ array\ number\}\ \{\{1\ 2\}\ \{3\ 4\}\}\}\n\ \ \ \ \ \ \ \ \{\[\[1,2\],\[3,4\]\]\}\n\ \ \ \ 4.5\ 1\ 0\ \"array\ of\ strings\"\n\ \ \ \ \ \ \ \ \{\{array\ array\ string\}\ \{\{1\ 2\}\ \{3\ 4\}\}\}\n\ \ \ \ \ \ \ \ \{\[\[\"1\",\"2\"\],\[\"3\",\"4\"\]\]\}\n\ \ \ \ 4.6\ 1\ 1\ \"empty\ array\"\n\ \ \ \ \ \ \ \ \{array\ \{\}\}\n\ \ \ \ \ \ \ \ \{\[\]\}\n\ \ \ \ 4.7\ 1\ 0\ \"empty\ array\ with\ unnecessary\ shared\ type\"\n\ \ \ \ \ \ \ \ \{\{array\ string\}\ \{\}\}\n\ \ \ \ \ \ \ \ \{\[\]\}\n\ \ \ \ 5.1\ 1\ 1\ \"object\ with\ variable\ type\"\n\ \ \ \ \ \ \ \ \{object\ \{foo\ \{string\ hello\}\ bar\ \{number\ 42\}\ quux\ \{literal\ null\}\}\}\n\ \ \ \ \ \ \ \ \{\{\"foo\":\"hello\",\"bar\":42,\"quux\":null\}\}\n\ \ \ \ 5.2\ 1\ 1\ \"object\ with\ constant\ but\ unshared\ type\"\n\ \ \ \ \ \ \ \ \{object\ \{name\ \{object\ \{first\ \{string\ Andy\}\ last\ \{string\ Goth\}\}\}\ address\ \{object\ \{web\ \{string\ http://tcl.tk/\}\}\}\}\}\n\ \ \ \ \ \ \ \ \{\{\"name\":\{\"first\":\"Andy\",\"last\":\"Goth\"\},\"address\":\{\"web\":\"http://tcl.tk/\"\}\}\}\n\ \ \ \ 5.3\ 1\ 0\ \"object\ with\ shared\ type,\ flattened\ syntax\"\n\ \ \ \ \ \ \ \ \{\{object\ object\ string\}\ \{name\ \{first\ Andy\ last\ Goth\}\ address\ \{web\ http://tcl.tk/\}\}\}\n\ \ \ \ \ \ \ \ \{\{\"name\":\{\"first\":\"Andy\",\"last\":\"Goth\"\},\"address\":\{\"web\":\"http://tcl.tk/\"\}\}\}\n\ \ \ \ 5.4\ 1\ 1\ \"empty\ object\"\n\ \ \ \ \ \ \ \ \{object\ \{\}\}\n\ \ \ \ \ \ \ \ \{\{\}\}\n\ \ \ \ 5.5\ 1\ 0\ \"empty\ object\ with\ unnecessary\ shared\ type\"\n\ \ \ \ \ \ \ \ \{\{object\ string\}\ \{\}\}\n\ \ \ \ \ \ \ \ \{\{\}\}\n\ \ \ \ 6.1\ 1\ 0\ \"empty\ raw\"\n\ \ \ \ \ \ \ \ \{raw\ \{\}\}\n\ \ \ \ \ \ \ \ \{\}\n\ \ \ \ 6.2\ 1\ 0\ \"nonempty\ raw\"\n\ \ \ \ \ \ \ \ \{raw\ \{\"foobar\"\}\}\n\ \ \ \ \ \ \ \ \{\"foobar\"\}\n\}\ \{\n\ \ \ \ if\ \{\$json::encode\}\ \{\n\ \ \ \ \ \ \ \ tcltest::test\ json::encode-\$name\ \$description\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -body\ \[list\ json::encode\ \$tcl\]\ -result\ \$json\n\ \ \ \ \}\n\ \ \ \ if\ \{\$json::decode\}\ \{\n\ \ \ \ \ \ \ \ tcltest::test\ json::decode-\$name\ \$description\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -body\ \[list\ json::decode\ \$json\]\ -result\ \$tcl\n\ \ \ \ \}\n\}\ntcltest::cleanupTests\n======\n\nNew\ test\ suite:\n\n======none\npackage\ require\ Tcl\ 8.5.7\npackage\ require\ json\npackage\ require\ tcltest\n\nforeach\ \{name\ description\ input\ output\}\ \{\n\ \ \ \ json-1.1\ \"encode\ array\ document\"\n\ \ \ \ \{array\ \{\{number\ 0\}\ \{number\ 1\}\ \{number\ 2\}\ \{number\ 3\}\}\}\ \{\[0,1,2,3\]\}\n\n\ \ \ \ json-1.2\ \"encode\ object\ document\"\n\ \ \ \ \{object\ \{foo\ \{number\ 0\}\ bar\ \{number\ 1\}\ quux\ \{number\ 2\}\}\}\n\ \ \ \ \{\{\"foo\":0,\"bar\":1,\"quux\":2\}\}\n\n\ \ \ \ json-1.3.1\ \"encode\ string\ document\"\n\ \ \ \ \{string\ \"hello\ world\"\}\ \{\"hello\ world\"\}\n\n\ \ \ \ json-1.3.2\ \"encode\ empty\ string\ document\"\n\ \ \ \ \{string\ \"\"\}\ \{\"\"\}\n\n\ \ \ \ json-1.3.3\ \"encode\ NUL\ string\ document\"\n\ \ \ \ \{string\ \"\\x00\"\}\ \{\"\\u0000\"\}\n\n\ \ \ \ json-1.3.4\ \"encode\ quoted\ string\ document\"\n\ \ \ \ \{string\ \"\\x1f\\\\x\\\"y\\\"z\"\}\ \{\"\\u001f\\\\x\\\"y\\\"z\"\}\n\n\ \ \ \ json-1.4.1\ \"encode\ integer\ number\ document\"\n\ \ \ \ \{number\ 42\}\ 42\n\n\ \ \ \ json-1.4.2\ \"encode\ negative\ integer\ number\ document\"\n\ \ \ \ \{number\ -42\}\ -42\n\n\ \ \ \ json-1.4.3\ \"encode\ positive\ integer\ number\ document\"\n\ \ \ \ \{number\ +42\}\ 42\n\n\ \ \ \ json-1.4.4\ \"encode\ spaced\ integer\ number\ document\"\n\ \ \ \ \{number\ \"\ +084\ \"\}\ 84\n\n\ \ \ \ json-1.4.5\ \"encode\ real\ number\ document\"\n\ \ \ \ \{number\ 4.2\}\ 4.2\n\n\ \ \ \ json-1.4.6\ \"encode\ negative\ real\ number\ document\"\n\ \ \ \ \{number\ -4.2\}\ -4.2\n\n\ \ \ \ json-1.4.6\ \"encode\ positive\ real\ number\ document\"\n\ \ \ \ \{number\ +4.2\}\ 4.2\n\n\ \ \ \ json-1.4.7\ \"encode\ spaced\ real\ number\ document\"\n\ \ \ \ \{number\ \"\ +04.20\ \"\}\ 4.2\n\n\ \ \ \ json-1.4.8\ \"encode\ real\ number\ document\ w/o\ leading\ zero\"\n\ \ \ \ \{number\ -.2\}\ -0.2\n\n\ \ \ \ json-1.4.9\ \"encode\ real\ number\ document\ w/o\ trailing\ zero\"\n\ \ \ \ \{number\ +2.\}\ 2.0\n\n\ \ \ \ json-1.4.10\ \"encode\ exponential\ number\ document\"\n\ \ \ \ \{number\ 2e5\}\ 2.0e+5\n\n\ \ \ \ json-1.5.1\ \"encode\ literal\ true\ document\"\n\ \ \ \ \{literal\ true\}\ true\n\n\ \ \ \ json-1.5.2\ \"encode\ literal\ false\ document\"\n\ \ \ \ \{literal\ false\}\ false\n\n\ \ \ \ json-1.5.3\ \"encode\ literal\ null\ document\"\n\ \ \ \ \{literal\ null\}\ null\n\n\ \ \ \ json-1.6\ \"encode\ pre-encoded\ document\"\n\ \ \ \ \{encoded\ \{\"hello\ world\"\}\}\ \{\"hello\ world\"\}\n\n\ \ \ \ json-1.7\ \"encode\ decoded\ document\"\n\ \ \ \ \{decoded\ \{string\ \"hello\ world\"\}\}\ \{\"hello\ world\"\}\n\n\ \ \ \ json-1.8.1\ \"encode\ array\ array\ document\"\n\ \ \ \ \{\{array\ array\}\ \{\{\{number\ 1\}\ \{number\ 2\}\}\ \{\{string\ 3\}\}\}\}\ \{\[\[1,2\],\[\"3\"\]\]\}\n\n\ \ \ \ json-1.8.2\ \"encode\ array\ array\ number\ document\"\n\ \ \ \ \{\{array\ array\ number\}\ \{\{1\ 2\}\ \{3\ 4\}\}\}\ \{\[\[1,2\],\[3,4\]\]\}\n\n\ \ \ \ json-1.8.3\ \"encode\ array\ object\ document\"\n\ \ \ \ \{\{array\ object\}\ \{\{a\ \{number\ 1\}\ b\ \{string\ 2\}\}\ \{a\ \{string\ 3\}\ b\ \{number\ 4\}\}\}\}\n\ \ \ \ \{\[\{\"a\":1,\"b\":\"2\"\},\{\"a\":\"3\",\"b\":4\}\]\}\n\n\ \ \ \ json-1.8.4\ \"encode\ array\ object\ number\ document\"\n\ \ \ \ \{\{array\ object\ number\}\ \{\{a\ 1\ b\ 2\}\ \{a\ 3\ b\ 4\}\}\}\n\ \ \ \ \{\[\{\"a\":1,\"b\":2\},\{\"a\":3,\"b\":4\}\]\}\n\n\ \ \ \ json-1.8.5\ \"encode\ array\ string\ document\"\n\ \ \ \ \{\{array\ string\}\ \{1\ 2\ 3\ 4\}\}\ \{\[\"1\",\"2\",\"3\",\"4\"\]\}\n\n\ \ \ \ json-1.8.6\ \"encode\ array\ number\ document\"\n\ \ \ \ \{\{array\ number\}\ \{1\ 2\ 3\ 4\}\}\ \{\[1,2,3,4\]\}\n\n\ \ \ \ json-1.8.7\ \"encode\ array\ literal\ document\"\n\ \ \ \ \{\{array\ literal\}\ \{true\ false\ null\}\}\ \{\[true,false,null\]\}\n\n\ \ \ \ json-1.8.8\ \"encode\ array\ encoded\ document\"\n\ \ \ \ \{\{array\ encoded\}\ \{\{\"x\"\}\ \[0,0\]\ null\}\}\ \{\[\"x\",\[0,0\],null\]\}\n\n\ \ \ \ json-1.8.9\ \"encode\ array\ decoded\ document\"\n\ \ \ \ \{\{array\ decoded\}\ \{\{literal\ true\}\ \{literal\ false\}\ \{literal\ null\}\}\}\n\ \ \ \ \{\[true,false,null\]\}\n\n\ \ \ \ json-1.9.1\ \"encode\ object\ array\ document\"\n\ \ \ \ \{\{object\ array\}\ \{a\ \{\{number\ 1\}\ \{number\ 2\}\}\ b\ \{\{string\ 3\}\}\}\}\n\ \ \ \ \{\{\"a\":\[1,2\],\"b\":\[\"3\"\]\}\}\n\n\ \ \ \ json-1.9.2\ \"encode\ object\ array\ number\ document\"\n\ \ \ \ \{\{object\ array\ number\}\ \{a\ \{1\ 2\}\ b\ \{3\ 4\}\}\}\ \{\{\"a\":\[1,2\],\"b\":\[3,4\]\}\}\n\n\ \ \ \ json-1.9.3\ \"encode\ object\ object\ document\"\n\ \ \ \ \{\{object\ object\}\ \{x\ \{a\ \{number\ 1\}\ b\ \{string\ 2\}\}\ y\ \{a\ \{string\ 3\}\}\}\}\n\ \ \ \ \{\{\"x\":\{\"a\":1,\"b\":\"2\"\},\"y\":\{\"a\":\"3\"\}\}\}\n\n\ \ \ \ json-1.9.4\ \"encode\ object\ object\ number\ document\"\n\ \ \ \ \{\{object\ object\ number\}\ \{x\ \{a\ 1\ b\ 2\}\ y\ \{a\ 3\ b\ 4\}\}\}\n\ \ \ \ \{\{\"x\":\{\"a\":1,\"b\":2\},\"y\":\{\"a\":3,\"b\":4\}\}\}\n\n\ \ \ \ json-1.9.5\ \"encode\ object\ string\ document\"\n\ \ \ \ \{\{object\ string\}\ \{1\ 2\ 3\ 4\}\}\ \{\{\"1\":\"2\",\"3\":\"4\"\}\}\n\n\ \ \ \ json-1.9.6\ \"encode\ object\ number\ document\"\n\ \ \ \ \{\{object\ number\}\ \{1\ 2\ 3\ 4\}\}\ \{\{\"1\":2,\"3\":4\}\}\n\n\ \ \ \ json-1.9.7\ \"encode\ object\ literal\ document\"\n\ \ \ \ \{\{object\ literal\}\ \{true\ true\ false\ false\ null\ null\}\}\n\ \ \ \ \{\{\"true\":true,\"false\":false,\"null\":null\}\}\n\n\ \ \ \ json-1.9.8\ \"encode\ object\ encoded\ document\"\n\ \ \ \ \{\{object\ encoded\}\ \{true\ \{\"x\"\}\ false\ \[0,0\]\ null\ null\}\}\n\ \ \ \ \{\{\"true\":\"x\",\"false\":\[0,0\],\"null\":null\}\}\n\n\ \ \ \ json-1.9.9\ \"encode\ object\ decoded\ document\"\n\ \ \ \ \{\{object\ decoded\}\ \{true\ \{string\ x\}\ false\ \{number\ -1.20\}\ null\ \{literal\ null\}\}\}\n\ \ \ \ \{\{\"true\":\"x\",\"false\":-1.2,\"null\":null\}\}\n\}\ \{\n\ \ \ \ tcltest::test\ \$name\ \$description\ -body\ \[list\ json::encode\ \$input\]\\\n\ \ \ \ \ \ \ \ \ \ \ \ -result\ \$output\n\}\n\n#\ TODO:\ more\ error\ cases?\ntcltest::test\ json-1.5.4\ \"encode\ literal\ invalid\ document\"\ -body\ \{\n\ \ \ \ json::encode\ \{literal\ invalid\}\n\}\ -returnCodes\ error\\\n-result\ \{invalid\ JSON\ literal\ \"invalid\":\ must\ be\ false,\ null,\ or\ true\}\n\nforeach\ \{name\ description\ input\ output\}\ \{\n\ \ \ \ json-2.1\ \"decode\ array\ document\"\n\ \ \ \ \{\[0,1,2,3\]\}\ \{array\ \{\{number\ 0\}\ \{number\ 1\}\ \{number\ 2\}\ \{number\ 3\}\}\}\n\n\ \ \ \ json-2.2\ \"decode\ object\ document\"\n\ \ \ \ \{\{\"foo\":0,\"bar\":1,\"quux\":2\}\}\n\ \ \ \ \{object\ \{foo\ \{number\ 0\}\ bar\ \{number\ 1\}\ quux\ \{number\ 2\}\}\}\n\n\ \ \ \ json-2.3.1\ \"decode\ string\ document\"\n\ \ \ \ \{\"hello\ world\"\}\ \{string\ \{hello\ world\}\}\n\n\ \ \ \ json-2.3.2\ \"decode\ empty\ string\ document\"\n\ \ \ \ \{\"\"\}\ \{string\ \{\}\}\n\n\ \ \ \ json-2.3.3\ \"decode\ NUL\ string\ document\"\n\ \ \ \ \{\"\\u0000\"\}\ \"string\ \\x00\"\n\n\ \ \ \ json-2.3.4\ \"decode\ quoted\ string\ document\"\n\ \ \ \ \{\"\\u001f\\\\x\\\"y\\\"z\"\}\ \"string\ \{\\x1f\\\\x\\\"y\\\"z\}\"\n\n\ \ \ \ json-2.4.1\ \"decode\ integer\ number\ document\"\n\ \ \ \ 42\ \{number\ 42\}\n\n\ \ \ \ json-2.4.2\ \"decode\ negative\ integer\ number\ document\"\n\ \ \ \ -42\ \{number\ -42\}\n\n\ \ \ \ json-2.4.3\ \"decode\ positive\ integer\ number\ document\"\n\ \ \ \ +42\ \{number\ 42\}\n\n\ \ \ \ json-2.4.5\ \"decode\ real\ number\ document\"\n\ \ \ \ 4.2\ \{number\ 4.2\}\n\n\ \ \ \ json-2.4.6\ \"decode\ negative\ real\ number\ document\"\n\ \ \ \ -4.2\ \{number\ -4.2\}\n\n\ \ \ \ json-2.4.6\ \"decode\ positive\ real\ number\ document\"\n\ \ \ \ +4.2\ \{number\ 4.2\}\n\n\ \ \ \ json-2.5.1\ \"decode\ literal\ true\ document\"\n\ \ \ \ true\ \{literal\ true\}\n\n\ \ \ \ json-2.5.2\ \"decode\ literal\ false\ document\"\n\ \ \ \ false\ \{literal\ false\}\n\n\ \ \ \ json-2.5.3\ \"decode\ literal\ null\ document\"\n\ \ \ \ null\ \{literal\ null\}\n\n\ \ \ \ json-2.6.1\ \"decode\ array\ array\ document\"\n\ \ \ \ \{\[\[1\],\[\"3\"\]\]\}\ \{array\ \{\{array\ \{\{number\ 1\}\}\}\ \{array\ \{\{string\ 3\}\}\}\}\}\n\n\ \ \ \ json-2.6.2\ \"decode\ array\ array\ number\ document\"\n\ \ \ \ \{\[\[1,2\],\[3,4\]\]\}\n\ \ \ \ \{array\ \{\{array\ \{\{number\ 1\}\ \{number\ 2\}\}\}\ \{array\ \{\{number\ 3\}\ \{number\ 4\}\}\}\}\}\n\n\ \ \ \ json-2.6.3\ \"decode\ array\ object\ document\"\n\ \ \ \ \{\[\{\"a\":1,\"b\":\"2\"\},\{\"a\":\"3\"\}\]\}\n\ \ \ \ \{array\ \{\{object\ \{a\ \{number\ 1\}\ b\ \{string\ 2\}\}\}\ \{object\ \{a\ \{string\ 3\}\}\}\}\}\n\n\ \ \ \ json-2.6.4\ \"encode\ array\ string\ document\"\n\ \ \ \ \{\[\"1\",\"2\",\"3\",\"4\"\]\}\ \{array\ \{\{string\ 1\}\ \{string\ 2\}\ \{string\ 3\}\ \{string\ 4\}\}\}\n\n\ \ \ \ json-2.6.5\ \"decode\ array\ number\ document\"\n\ \ \ \ \{\[1,2,3,4\]\}\ \{array\ \{\{number\ 1\}\ \{number\ 2\}\ \{number\ 3\}\ \{number\ 4\}\}\}\n\n\ \ \ \ json-2.6.6\ \"decode\ array\ literal\ document\"\n\ \ \ \ \{\[true,false,null\]\}\ \{array\ \{\{literal\ true\}\ \{literal\ false\}\ \{literal\ null\}\}\}\n\n\ \ \ \ json-2.7.1\ \"decode\ object\ array\ document\"\n\ \ \ \ \{\{\"a\":\[1,2\],\"b\":\[\"3\"\]\}\}\n\ \ \ \ \{object\ \{a\ \{array\ \{\{number\ 1\}\ \{number\ 2\}\}\}\ b\ \{array\ \{\{string\ 3\}\}\}\}\}\n\n\ \ \ \ json-2.7.2\ \"decode\ object\ object\ document\"\n\ \ \ \ \{\{\"x\":\{\"a\":1,\"b\":\"2\"\},\"y\":\{\"a\":\"3\"\}\}\}\n\ \ \ \ \{object\ \{x\ \{object\ \{a\ \{number\ 1\}\ b\ \{string\ 2\}\}\}\ y\ \{object\ \{a\ \{string\ 3\}\}\}\}\}\n\n\ \ \ \ json-2.7.3\ \"decode\ object\ string\ document\"\n\ \ \ \ \{\{\"1\":\"2\",\"3\":\"4\"\}\}\ \{object\ \{1\ \{string\ 2\}\ 3\ \{string\ 4\}\}\}\n\n\ \ \ \ json-2.7.4\ \"encode\ object\ number\ document\"\n\ \ \ \ \{\{\"1\":2,\"3\":4\}\}\ \{object\ \{1\ \{number\ 2\}\ 3\ \{number\ 4\}\}\}\n\n\ \ \ \ json-2.7.5\ \"decode\ object\ literal\ document\"\n\ \ \ \ \{\{\"true\":true,\"false\":false,\"null\":null\}\}\n\ \ \ \ \{object\ \{true\ \{literal\ true\}\ false\ \{literal\ false\}\ null\ \{literal\ null\}\}\}\n\}\ \{\n\ \ \ \ tcltest::test\ \$name\ \$description\ -body\ \[list\ json::decode\ \$input\]\\\n\ \ \ \ \ \ \ \ \ \ \ \ -result\ \$output\n\}\n\nforeach\ \{name\ description\ input\ output\}\ \{\n\ \ \ \ json-3.1\ \"array\ schema\"\n\ \ \ \ \{array\ \{\{number\ 0\}\ \{number\ 1\}\ \{number\ 2\}\ \{number\ 3\}\}\}\n\ \ \ \ \{array\ \{number\ number\ number\ number\}\}\n\n\ \ \ \ json-3.2\ \"object\ schema\"\n\ \ \ \ \{object\ \{foo\ \{number\ 0\}\ bar\ \{number\ 1\}\ quux\ \{number\ 2\}\}\}\n\ \ \ \ \{object\ \{foo\ number\ bar\ number\ quux\ number\}\}\n\n\ \ \ \ json-3.3\ \"string\ schema\"\n\ \ \ \ \{string\ \{hello\ world\}\}\ string\n\n\ \ \ \ json-3.4\ \"number\ schema\"\n\ \ \ \ \{number\ 42\}\ number\n\n\ \ \ \ json-3.5\ \"literal\ schema\"\n\ \ \ \ \{literal\ true\}\ literal\n\n\ \ \ \ json-3.6.1\ \"array\ array\ schema\"\n\ \ \ \ \{array\ \{\{array\ \{\{number\ 1\}\}\}\ \{array\ \{\{string\ 3\}\ \{literal\ false\}\}\}\}\}\n\ \ \ \ \{array\ \{\{array\ number\}\ \{array\ \{string\ literal\}\}\}\}\n\n\ \ \ \ json-3.6.2\ \"array\ array\ number\ schema\"\n\ \ \ \ \{array\ \{\{array\ \{\{number\ 1\}\ \{number\ 2\}\}\}\ \{array\ \{\{number\ 3\}\ \{number\ 4\}\}\}\}\}\n\ \ \ \ \{array\ \{\{array\ \{number\ number\}\}\ \{array\ \{number\ number\}\}\}\}\n\n\ \ \ \ json-3.6.3\ \"array\ object\ schema\"\n\ \ \ \ \{array\ \{\{object\ \{a\ \{number\ 1\}\ b\ \{string\ 2\}\}\}\ \{object\ \{a\ \{string\ 3\}\}\}\}\}\n\ \ \ \ \{array\ \{\{object\ \{a\ number\ b\ string\}\}\ \{object\ \{a\ string\}\}\}\}\n\n\ \ \ \ json-3.6.4\ \"array\ string\ schema\"\n\ \ \ \ \{array\ \{\{string\ 1\}\ \{string\ 2\}\ \{string\ 3\}\ \{string\ 4\}\}\}\n\ \ \ \ \{array\ \{string\ string\ string\ string\}\}\n\n\ \ \ \ json-3.6.5\ \"array\ number\ schema\"\n\ \ \ \ \{array\ \{\{number\ 1\}\ \{number\ 2\}\ \{number\ 3\}\ \{number\ 4\}\}\}\n\ \ \ \ \{array\ \{number\ number\ number\ number\}\}\n\n\ \ \ \ json-3.6.6\ \"array\ literal\ schema\"\n\ \ \ \ \{array\ \{\{literal\ true\}\ \{literal\ false\}\ \{literal\ null\}\}\}\n\ \ \ \ \{array\ \{literal\ literal\ literal\}\}\n\n\ \ \ \ json-3.7.1\ \"object\ array\ schema\"\n\ \ \ \ \{object\ \{a\ \{array\ \{\{number\ 1\}\ \{number\ 2\}\}\}\ b\ \{array\ \{\{string\ 3\}\}\}\}\}\n\ \ \ \ \{object\ \{a\ \{array\ \{number\ number\}\}\ b\ \{array\ string\}\}\}\n\n\ \ \ \ json-3.7.2\ \"object\ object\ schema\"\n\ \ \ \ \{object\ \{x\ \{object\ \{a\ \{number\ 1\}\ b\ \{string\ 2\}\}\}\ y\ \{object\ \{a\ \{string\ 3\}\}\}\}\}\n\ \ \ \ \{object\ \{x\ \{object\ \{a\ number\ b\ string\}\}\ y\ \{object\ \{a\ string\}\}\}\}\n\n\ \ \ \ json-3.7.3\ \"object\ string\ schema\"\n\ \ \ \ \{object\ \{1\ \{string\ 2\}\ 3\ \{string\ 4\}\}\}\n\ \ \ \ \{object\ \{1\ string\ 3\ string\}\}\n\n\ \ \ \ json-3.7.4\ \"object\ number\ schema\"\n\ \ \ \ \{object\ \{1\ \{number\ 2\}\ 3\ \{number\ 4\}\}\}\n\ \ \ \ \{object\ \{1\ number\ 3\ number\}\}\n\n\ \ \ \ json-3.7.5\ \"object\ literal\ schema\"\n\ \ \ \ \{object\ \{true\ \{literal\ true\}\ false\ \{literal\ false\}\ null\ \{literal\ null\}\}\}\n\ \ \ \ \{object\ \{true\ literal\ false\ literal\ null\ literal\}\}\n\}\ \{\n\ \ \ \ tcltest::test\ \$name\ \$description\ -body\ \[list\ json::schema\ \$input\]\\\n\ \ \ \ \ \ \ \ \ \ \ \ -result\ \$output\n\}\n\nforeach\ \{name\ description\ input\ output\}\ \{\n\ \ \ \ json-4.1\ \"array\ values\"\n\ \ \ \ \{array\ \{\{number\ 0\}\ \{number\ 1\}\ \{number\ 2\}\ \{number\ 3\}\}\}\ \{0\ 1\ 2\ 3\}\n\n\ \ \ \ json-4.2\ \"object\ values\"\n\ \ \ \ \{object\ \{foo\ \{number\ 0\}\ bar\ \{number\ 1\}\ quux\ \{number\ 2\}\}\}\n\ \ \ \ \{foo\ 0\ bar\ 1\ quux\ 2\}\n\n\ \ \ \ json-4.3\ \"string\ values\"\n\ \ \ \ \{string\ \{hello\ world\}\}\ \{hello\ world\}\n\n\ \ \ \ json-4.4\ \"number\ values\"\n\ \ \ \ \{number\ 42\}\ 42\n\n\ \ \ \ json-4.5\ \"literal\ values\"\n\ \ \ \ \{literal\ true\}\ true\n\n\ \ \ \ json-4.6.1\ \"array\ array\ values\"\n\ \ \ \ \{array\ \{\{array\ \{\{number\ 1\}\}\}\ \{array\ \{\{string\ 3\}\ \{literal\ false\}\}\}\}\}\n\ \ \ \ \{1\ \{3\ false\}\}\n\n\ \ \ \ json-4.6.2\ \"array\ array\ number\ values\"\n\ \ \ \ \{array\ \{\{array\ \{\{number\ 1\}\ \{number\ 2\}\}\}\ \{array\ \{\{number\ 3\}\ \{number\ 4\}\}\}\}\}\n\ \ \ \ \{\{1\ 2\}\ \{3\ 4\}\}\n\n\ \ \ \ json-4.6.3\ \"array\ object\ values\"\n\ \ \ \ \{array\ \{\{object\ \{a\ \{number\ 1\}\ b\ \{string\ 2\}\}\}\ \{object\ \{a\ \{string\ 3\}\}\}\}\}\n\ \ \ \ \{\{a\ 1\ b\ 2\}\ \{a\ 3\}\}\n\n\ \ \ \ json-4.6.4\ \"array\ string\ values\"\n\ \ \ \ \{array\ \{\{string\ 1\}\ \{string\ 2\}\ \{string\ 3\}\ \{string\ 4\}\}\}\ \{1\ 2\ 3\ 4\}\n\n\ \ \ \ json-4.6.5\ \"array\ number\ values\"\n\ \ \ \ \{array\ \{\{number\ 1\}\ \{number\ 2\}\ \{number\ 3\}\ \{number\ 4\}\}\}\ \{1\ 2\ 3\ 4\}\n\n\ \ \ \ json-4.6.6\ \"array\ literal\ values\"\n\ \ \ \ \{array\ \{\{literal\ true\}\ \{literal\ false\}\ \{literal\ null\}\}\}\ \{true\ false\ null\}\n\n\ \ \ \ json-4.7.1\ \"object\ array\ values\"\n\ \ \ \ \{object\ \{a\ \{array\ \{\{number\ 1\}\ \{number\ 2\}\}\}\ b\ \{array\ \{\{string\ 3\}\}\}\}\}\n\ \ \ \ \{a\ \{1\ 2\}\ b\ 3\}\n\n\ \ \ \ json-4.7.2\ \"object\ object\ values\"\n\ \ \ \ \{object\ \{x\ \{object\ \{a\ \{number\ 1\}\ b\ \{string\ 2\}\}\}\ y\ \{object\ \{a\ \{string\ 3\}\}\}\}\}\n\ \ \ \ \{x\ \{a\ 1\ b\ 2\}\ y\ \{a\ 3\}\}\n\n\ \ \ \ json-4.7.3\ \"object\ string\ values\"\n\ \ \ \ \{object\ \{1\ \{string\ 2\}\ 3\ \{string\ 4\}\}\}\ \{1\ 2\ 3\ 4\}\n\n\ \ \ \ json-4.7.4\ \"object\ number\ values\"\n\ \ \ \ \{object\ \{1\ \{number\ 2\}\ 3\ \{number\ 4\}\}\}\ \{1\ 2\ 3\ 4\}\n\n\ \ \ \ json-4.7.5\ \"object\ literal\ values\"\n\ \ \ \ \{object\ \{true\ \{literal\ true\}\ false\ \{literal\ false\}\ null\ \{literal\ null\}\}\}\n\ \ \ \ \{true\ true\ false\ false\ null\ null\}\n\}\ \{\n\ \ \ \ tcltest::test\ \$name\ \$description\ -body\ \[list\ json::values\ \$input\]\\\n\ \ \ \ \ \ \ \ \ \ \ \ -result\ \$output\n\}\n\nforeach\ \{name\ description\ schema\ values\ output\}\ \{\n\ \ \ \ json-5.1\ \"unite\ array\"\n\ \ \ \ \{array\ \{number\ number\ number\ number\}\}\ \{0\ 1\ 2\ 3\}\n\ \ \ \ \{array\ \{\{number\ 0\}\ \{number\ 1\}\ \{number\ 2\}\ \{number\ 3\}\}\}\n\n\ \ \ \ json-5.2\ \"unite\ object\"\n\ \ \ \ \{object\ \{foo\ number\ bar\ number\ quux\ number\}\}\ \{foo\ 0\ bar\ 1\ quux\ 2\}\n\ \ \ \ \{object\ \{foo\ \{number\ 0\}\ bar\ \{number\ 1\}\ quux\ \{number\ 2\}\}\}\n\n\ \ \ \ json-5.3\ \"unite\ string\"\n\ \ \ \ string\ \{hello\ world\}\ \{string\ \{hello\ world\}\}\n\n\ \ \ \ json-5.4\ \"unite\ number\"\n\ \ \ \ number\ 42\ \{number\ 42\}\n\n\ \ \ \ json-5.5\ \"unite\ literal\"\n\ \ \ \ literal\ true\ \{literal\ true\}\n\n\ \ \ \ json-5.6.1\ \"unite\ array\ array\"\n\ \ \ \ \{array\ \{\{array\ number\}\ \{array\ \{string\ literal\}\}\}\}\ \{1\ \{3\ false\}\}\n\ \ \ \ \{array\ \{\{array\ \{\{number\ 1\}\}\}\ \{array\ \{\{string\ 3\}\ \{literal\ false\}\}\}\}\}\n\n\ \ \ \ json-5.6.2\ \"unite\ array\ array\ number\"\n\ \ \ \ \{array\ \{\{array\ \{number\ number\}\}\ \{array\ \{number\ number\}\}\}\}\ \{\{1\ 2\}\ \{3\ 4\}\}\n\ \ \ \ \{array\ \{\{array\ \{\{number\ 1\}\ \{number\ 2\}\}\}\ \{array\ \{\{number\ 3\}\ \{number\ 4\}\}\}\}\}\n\n\ \ \ \ json-5.6.3\ \"unite\ array\ object\"\n\ \ \ \ \{array\ \{\{object\ \{a\ number\ b\ string\}\}\ \{object\ \{a\ string\}\}\}\}\ \{\{a\ 1\ b\ 2\}\ \{a\ 3\}\}\n\ \ \ \ \{array\ \{\{object\ \{a\ \{number\ 1\}\ b\ \{string\ 2\}\}\}\ \{object\ \{a\ \{string\ 3\}\}\}\}\}\n\n\ \ \ \ json-5.6.4\ \"unite\ array\ string\"\n\ \ \ \ \{array\ \{string\ string\ string\ string\}\}\ \{1\ 2\ 3\ 4\}\n\ \ \ \ \{array\ \{\{string\ 1\}\ \{string\ 2\}\ \{string\ 3\}\ \{string\ 4\}\}\}\n\n\ \ \ \ json-5.6.5\ \"unite\ array\ number\"\n\ \ \ \ \{array\ \{number\ number\ number\ number\}\}\ \{1\ 2\ 3\ 4\}\n\ \ \ \ \{array\ \{\{number\ 1\}\ \{number\ 2\}\ \{number\ 3\}\ \{number\ 4\}\}\}\n\n\ \ \ \ json-5.6.6\ \"unite\ array\ literal\"\n\ \ \ \ \{array\ \{literal\ literal\ literal\}\}\ \{true\ false\ null\}\n\ \ \ \ \{array\ \{\{literal\ true\}\ \{literal\ false\}\ \{literal\ null\}\}\}\n\n\ \ \ \ json-5.7.1\ \"unite\ object\ array\"\n\ \ \ \ \{object\ \{a\ \{array\ \{number\ number\}\}\ b\ \{array\ string\}\}\}\ \{a\ \{1\ 2\}\ b\ 3\}\n\ \ \ \ \{object\ \{a\ \{array\ \{\{number\ 1\}\ \{number\ 2\}\}\}\ b\ \{array\ \{\{string\ 3\}\}\}\}\}\n\n\ \ \ \ json-5.7.2\ \"unite\ object\ object\"\n\ \ \ \ \{object\ \{x\ \{object\ \{a\ number\ b\ string\}\}\ y\ \{object\ \{a\ string\}\}\}\}\n\ \ \ \ \{x\ \{a\ 1\ b\ 2\}\ y\ \{a\ 3\}\}\n\ \ \ \ \{object\ \{x\ \{object\ \{a\ \{number\ 1\}\ b\ \{string\ 2\}\}\}\ y\ \{object\ \{a\ \{string\ 3\}\}\}\}\}\n\n\ \ \ \ json-5.7.3\ \"unite\ object\ string\"\n\ \ \ \ \{object\ \{1\ string\ 3\ string\}\}\ \{1\ 2\ 3\ 4\}\ \{object\ \{1\ \{string\ 2\}\ 3\ \{string\ 4\}\}\}\n\n\ \ \ \ json-5.7.4\ \"unite\ object\ number\"\n\ \ \ \ \{object\ \{1\ number\ 3\ number\}\}\ \{1\ 2\ 3\ 4\}\ \{object\ \{1\ \{number\ 2\}\ 3\ \{number\ 4\}\}\}\n\n\ \ \ \ json-5.7.5\ \"unite\ object\ literal\"\n\ \ \ \ \{object\ \{true\ literal\ false\ literal\ null\ literal\}\}\n\ \ \ \ \{true\ true\ false\ false\ null\ null\}\n\ \ \ \ \{object\ \{true\ \{literal\ true\}\ false\ \{literal\ false\}\ null\ \{literal\ null\}\}\}\n\}\ \{\n\ \ \ \ tcltest::test\ \$name\ \$description\ -body\ \[list\ json::unite\ \$schema\ \$values\]\\\n\ \ \ \ \ \ \ \ \ \ \ \ -result\ \$output\n\}\n\ntcltest::cleanupTests\n======\n\n**TODO**\n\n\ \ \ *\ \[\[json::encode\]\]\ pretty\ print\ options\n\ \ \ *\ \[\[json::decode\]\]\ type\ compression\ option\n\ \ \ *\ \[\[json::decode\]\]\ type\ suppression\ option\n\ \ \ *\ Tests\ for\ \[\[json::decode\]\]\ whitespace\ tolerance\n\ \ \ *\ Tests\ for\ error\ detection\n\ \ \ *\ Submit\ to\ \[tcllib\],\ or\ too\ much\ overlap\ with\ \[huddle\]\ and\ \[Tcllib\ JSON\]?\n\n<<categories>>\ Internet\ |\ JSON} CALL {my revision {Alternative JSON}} CALL {::oo::Obj2868673 process revision/Alternative+JSON} CALL {::oo::Obj2868671 process}

-errorcode

NONE

-errorinfo

Unknow state transition: LINE -> END
    while executing
"error $msg"
    (class "::Wiki" method "render_wikit" line 6)
    invoked from within
"my render_$default_markup $N $C $mkup_rendering_engine"
    (class "::Wiki" method "render" line 8)
    invoked from within
"my render $name $C"
    (class "::Wiki" method "revision" line 31)
    invoked from within
"my revision $page"
    (class "::Wiki" method "process" line 56)
    invoked from within
"$server process [string trim $uri /]"

-errorline

4