1 # Implements 'json::encode'
3 # (c) 2019 Steve Bennett <steveb@workware.net.au>
5 # See LICENCE in this directory for licensing.
7 # Encode Tcl objects as JSON
13 # The schema provides the type information for the value.
15 # num = numeric (or null)
17 # obj ... = object. parameters are 'name' 'subschema' where the name matches the dict.
18 # list ... = array. parameters are 'subschema' for the elements of the list/array.
19 # mixed ... = array of mixed types. parameters are types for each element of the list/array.
21 # Top level JSON encoder which encodes the given
22 # value based on the schema
23 proc json
::encode {value
{schema str
}} {
24 json
::encode.
[lindex $schema 0] $value [lrange $schema 1 end
]
28 proc json
::encode.str
{value
{dummy
{}}} {
29 # Strictly we should be converting \x00 through \x1F to unicode escapes
30 # And anything outside the BMP to a UTF-16 surrogate pair
31 return \"[string map
[list \\ \\\\ \" \\" \f \\f \n \\n / \\/ \b \\b \r \\r \t \\t] $value]\"
34 # If no type is given, also encode as a string
35 proc json::encode. {args} {
36 tailcall json::encode.str {*}$args
40 proc json::encode.num {value {dummy {}}} {
41 if {$value in {Inf -Inf}} {
48 proc json::encode.bool {value {dummy {}}} {
55 # Encode an object (dictionary)
56 proc json::encode.obj {obj {schema {}}} {
59 foreach k [lsort [dict keys $obj]] {
60 if {[dict exists $schema $k]} {
61 set type [dict get $schema $k]
62 } elseif {[dict exists $schema *]} {
63 set type [dict get $schema *]
67 append result $sep\"$k\":
69 append result [json::encode.[lindex $type 0] [dict get $obj $k] [lrange $type 1 end]]
75 # Encode an array (list)
76 proc json::encode.list {list {type str}} {
81 append result [json::encode.[lindex $type 0] $l [lrange $type 1 end]]
87 # Encode a mixed-type array (list)
88 # Must be as many types as there are elements of the list
89 proc json::encode.mixed {list types} {
92 foreach l $list type $types {
94 append result [json::encode.[lindex $type 0] $l [lrange $type 1 end]]