blob: a9013b91ccfc33b1ff1b760e0d4764bc12dbeec8 [file] [log] [blame]
# This was imported into gdb from:
# https://github.com/jorge-leon/ton
# This software is copyrighted by Georg Lehner <jorge@at.anteris.net>.
# The following terms apply to all files associated with the software
# unless explicitly disclaimed in individual files.
# The authors hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose,
# provided that existing copyright notices are retained in all copies
# and that this notice is included verbatim in any distributions. No
# written agreement, license, or royalty fee is required for any of the
# authorized uses. Modifications to this software may be copyrighted by
# their authors and need not follow the licensing terms described here,
# provided that the new terms are clearly indicated on the first page of
# each file where they apply.
# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
# NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND
# THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
# MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
# GOVERNMENT USE: If you are acquiring this software on behalf of the
# U.S. government, the Government shall have only "Restricted Rights" in
# the software and related documentation as defined in the Federal
# Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
# are acquiring the software on behalf of the Department of Defense, the
# software shall be classified as "Commercial Computer Software" and the
# Government shall have only "Restricted Rights" as defined in Clause
# 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the
# authors grant the U.S. Government and others acting in its behalf
# permission to use and distribute the software in accordance with the
# terms specified in this license.
# leg20180331: ton / TON - Tcl Object Notation
#
# This package provides manipulation functionality for TON - a data
# serialization format with a direct mapping to JSON.
#
# In its essence, a JSON parser is provided, which can convert a JSON
# string into a Tcllib json style dictionary (dicts and arrays mixed),
# into a jimhttp style dictionary (only dicts) or into a nested, typed
# Tcl list.
#
# Finally, TON can be converted into (unformatted) JSON.
namespace eval ton {
namespace export json2ton
variable version 0.4
}
proc ton::json2ton json {
# Parse JSON string json
#
# return: TON
set i [trr $json [string length $json]]
if {!$i} {return ""}
lassign [jscan $json $i] i ton
if {[set i [trr $json $i]]} {
error "json string invalid:[incr i -1]: left over characters."
}
return $ton
}
proc ton::trr {s i} {
# Trim righthand whitespace on the first i characters of s.
# return: number of remaining characters in s
while {[set j $i] &&
([string is space [set c [string index $s [incr i -1]]]]
|| $c eq "\n")} {}
return $j
}
proc ton::jscan {json i {d :}} {
# Scan JSON in first i characters of string json.
# d is the default delimiter list for the next token.
#
# return list of
# - remaining characters in json
# - TON
#
# The string must already be whitespace trimmed from the right.
incr i -1
if {[set c [string index $json $i]] eq "\""} {
str $json [incr i -1]
} elseif {$c eq "\}"} {
obj $json $i
} elseif {$c eq "\]"} {
arr $json $i
} elseif {$c in {e l}} {
lit $json $i
} elseif {[string match {[0-9.]} $c]} {
num $json $i $c $d
} else {
error "json string end invalid:$i: ..[string range $json $i-10 $i].."
}
}
proc ton::num {json i c d} {
# Parse number from position i in string json to the left.
# c .. character at position i
# d .. delimiter on which to stop
#
# return list:
# - remaining string length
# - TON of number
set float [expr {$c eq "."}]
for {set j $i} {$i} {incr i -1} {
if {[string match $d [set c [string index $json $i-1]]]} break
set float [expr {$float || [string match "\[eE.]" $c]}]
}
set num [string trimleft [string range $json $i $j]]
if {!$float && [string is entier $num]} {
list $i "i $num"
} elseif {$float && [string is double $num]} {
list $i "d $num"
} else {
error "number invalid:$i: $num."
}
}
proc ton::lit {json i} {
# Parse literal from position i in string json to the left
# return list:
# - remaining string length
# - TON of literal
if {[set c [string index $json $i-1]] eq "u"} {
list [incr i -3] "l true"
} elseif {$c eq "s"} {
list [incr i -4] "l false"
} elseif {$c eq "l"} {
list [incr i -3] "l null"
} else {
set e [string range $json $i-3 $i]
error "literal invalid:[incr i -1]: ..$e."
}
}
proc ton::str {json i} {
# Parse string from position i in string json to the left
# return list:
# - remaining string length
# - TON of string
for {set j $i} {$i} {incr i -1} {
set i [string last \" $json $i]
if {[string index $json $i-1] ne "\\"} break
}
if {$i==-1} {
error "json string start invalid:$i: exhausted while parsing string."
}
list $i "s [list [string range $json $i+1 $j]]"
}
proc ton::arr {json i} {
# Parse array from i characters in string json
# return list:
# - remaining string length
# - TON of array
set i [trr $json $i]
if {!$i} {
error "json string invalid:0: exhausted while parsing array."
}
if {[string index $json $i-1] eq "\["} {
return [list [incr i -1] a]
}
set r {}
while {$i} {
lassign [jscan $json $i "\[,\[]"] i v
lappend r \[$v\]
set i [trr $json $i]
incr i -1
if {[set c [string index $json $i]] eq ","} {
set i [trr $json $i]
continue
} elseif {$c eq "\["} break
error "json string invalid:$i: parsing array."
}
lappend r a
return [list $i [join [lreverse $r]]]
}
proc ton::obj {json i} {
# Parse array from i character in string json
# return list:
# - remaining string length
# - TON of object
set i [trr $json $i]
if {!$i} {
error "json string invalid:0: exhausted while parsing object."
}
if {[string index $json $i-1] eq "\{"} {
return [list [incr i -1] o]
}
set r {}
while {$i} {
lassign [jscan $json $i] i v
set i [trr $json $i]
incr i -1
if {[string index $json $i] ne ":"} {
error "json string invalid:$i: parsing key in object."
}
set i [trr $json $i]
lassign [jscan $json $i] i k
lassign $k type k
if {$type ne "s"} {
error "json string invalid:[incr i -1]: key not a string."
}
lappend r \[$v\] [list $k]
set i [trr $json $i]
incr i -1
if {[set c [string index $json $i]] eq ","} {
set i [trr $json $i]
continue
} elseif {$c eq "\{"} break
error "json string invalid:$i: parsing object."
}
lappend r o
return [list $i [join [lreverse $r]]]
}
# TON decoders
namespace eval ton::2list {
proc atom {type v} {list $type $v}
foreach type {i d s l} {
interp alias {} $type {} [namespace current]::atom $type
}
proc a args {
set r a
foreach v $args {lappend r $v}
return $r
}
proc o args {
set r o
foreach {k v} $args {lappend r $k $v}
return $r
}
# There is plenty of room for validation in get
# array index bounds
# object key existence
proc get {l args} {
foreach k $args {
switch [lindex $l 0] {
o {set l [dict get [lrange $l 1 end] $k]}
a {set l [lindex $l [incr k]]}
default {
error "error: key $k to long, or wrong data: [lindex $l 0]"
}
}
}
return $l
}
}
namespace eval ton::2dict {
proc atom v {return $v}
foreach type {i d l s} {
interp alias {} $type {} [namespace current]::atom
}
proc a args {return $args}
proc o args {return $args}
}
namespace eval ton::a2dict {
proc atom v {return $v}
foreach type {i d l s} {
interp alias {} $type {} [namespace current]::atom
}
proc a args {
set i -1
set r {}
foreach v $args {
lappend r [incr i] $v
}
return $r
}
proc o args {return $args}
}
namespace eval ton::2json {
proc atom v {return $v}
foreach type {i d l} {
interp alias {} $type {} [namespace current]::atom
}
proc a args {
return "\[[join $args {, }]]"
}
proc o args {
set r {}
foreach {k v} $args {lappend r "\"$k\": $v"}
return "{[join $r {, }]}"
}
proc s s {return "\"$s\""}
}
package provide ton $ton::version