basic parsing
[scpubgit/TenDotTcl.git] / json.tcl
index 9d382e6..bb7a155 100644 (file)
--- a/json.tcl
+++ b/json.tcl
@@ -60,8 +60,8 @@ namespace eval ten::json {
 
     proc deparse {data} {
       switch -regexp [lindex $data 0] {
-        ^true|false|null$  { lindex $data 0 }
-        ^num|str|obj|list$ { eval $data }
+        ^(true|false|null)$  { lindex $data 0 }
+        ^(num|str|obj|list)$ { eval $data }
         default { error [ concat "Invalid JSON type " [lindex $data 0 0] ] }
       }
     }
@@ -90,8 +90,8 @@ namespace eval ten::json {
 
     proc tclify {data} {
       switch -regexp [lindex $data 0] {
-        ^true|false|null$ { uplevel 1 return [lindex $data 0] }
-        ^num|str|obj|list$ {}
+        ^(true|false|null)$ { uplevel 1 return [lindex $data 0] }
+        ^(num|str|obj|list)$ {}
         default { error [ concat "Invalid JSON type " [lindex $data 0 0] ] }
       }
       eval $data
@@ -106,30 +106,57 @@ namespace eval ten::json {
 
     variable json
 
-    proc eat_comma {} {
+    proc eat_spaces {} {
       variable json
       set json [string trimleft $json]
-      if {[string index $json 0] eq ","} {
-        set json [string range $json 1 end]
+    }
+
+    proc eat_char {char} {
+      variable json
+      eat_spaces
+      if {[string index $json 0] eq "$char"} {
+        eat_any
       }
     }
 
-    proc eat_char {} {
+    proc eat_any {} {
       variable json
       set json [ string range $json 1 end ]
     }
 
     proc parse_list {} {
       variable json
-      eat_char
+      eat_any
       set tcl {list}
       while {"$json" ne ""} {
+        eat_spaces
         if {[string index $json 0] eq "]"} {
-          eat_char
+          eat_any
           return $tcl
         }
         lappend tcl [ parse ]
-        eat_comma
+        eat_char ,
+      }
+      error "Ran out of JSON. Confused now."
+    }
+
+    proc parse_obj {} {
+      variable json
+      eat_any
+      set tcl {obj}
+      while {"$json" ne ""} {
+        eat_spaces
+        if {[string index $json 0] eq "\}"} {
+          eat_any
+          return $tcl
+        }
+        eat_spaces
+        lappend tcl [ parse_str ]
+        eat_spaces
+        eat_char :
+        eat_spaces
+        lappend tcl [ parse ]
+        eat_char ,
       }
       error "Ran out of JSON. Confused now."
     }
@@ -139,7 +166,7 @@ namespace eval ten::json {
       # like Text::Balanced except ugly (borrowed from tcvJSON's code)
       set reStr {(?:(?:\")(?:[^\\\"]*(?:\\.[^\\\"]*)*)(?:\"))}
       if {![regexp $reStr $json string]} {
-        error [ concat "Invalid string: " [string range $json 0 32]
+        error "Invalid string: $json"
       }
       set json [string range $json [string length $string] end]
       # chop off outer ""s and substitute backslashes
@@ -159,9 +186,19 @@ namespace eval ten::json {
       list num $num
     }
 
+    proc parse_bare {} {
+      variable json
+      if [regexp {^(true|false|null)} $json matched] {
+        set json [ string range $json [ string length $matched ] end ]
+        return $matched
+      } else {
+        error "Out of ideas parsing: $json"
+      }
+    }
+
     proc parse {} {
       variable json
-      set json [string trimleft $json]
+      eat_spaces
       if {$json eq ""} {
         return
       }
@@ -172,7 +209,7 @@ namespace eval ten::json {
 
         {[-0-9]} { parse_num }
 
-        default { error "argh" }
+        default { parse_bare }
       }
     }
   }
@@ -180,7 +217,8 @@ namespace eval ten::json {
   proc parse_json {json} {
     set parse::json [ string trim $json ]
     set result [ parse::parse ]
-    if {[string trimleft $parse::json] ne ""} {
+    parse::eat_spaces
+    if {$parse::json ne ""} {
       error "Had JSON left over: $parse::json"
     }
     return $result
@@ -206,6 +244,6 @@ dict for {k v} [ ten::json::tclify_json [
   lindex [ ten::json::tclify_json $ex_json ] 2
 ] ] { puts "$k: $v" }
 
-#puts [ ten::json::parse_json $jtext ]
+puts [ ten::json::parse_json $jtext ]
 
 puts [ ten::json::parse_json {["foo",2345,["bar"]]} ]