Author: Antonio Cuni <[email protected]>
Branch: fastjson
Changeset: r64774:0c2d7c11a454
Date: 2013-06-04 17:40 +0200
http://bitbucket.org/pypy/pypy/changeset/0c2d7c11a454/

Log:    implement decoding of objects

diff --git a/pypy/module/_fastjson/interp_decoder.py 
b/pypy/module/_fastjson/interp_decoder.py
--- a/pypy/module/_fastjson/interp_decoder.py
+++ b/pypy/module/_fastjson/interp_decoder.py
@@ -6,15 +6,15 @@
 def is_whitespace(ch):
     return ch == ' ' or ch == '\t' or ch == '\r' or ch == '\n'
 
-TYPE_INVALID = 0
-TYPE_STRING = 0
+TYPE_UNKNOWN = 0
+TYPE_STRING = 1
 
 class JSONDecoder(object):
     def __init__(self, space, s):
         self.space = space
         self.s = s
         self.i = 0
-        self.last_type = TYPE_INVALID
+        self.last_type = TYPE_UNKNOWN
 
     def eof(self):
         return self.i == len(self.s)
@@ -30,6 +30,10 @@
     def unget(self):
         self.i -= 1
 
+    def getslice(self, start, end):
+        assert end > 0
+        return self.s[start:end]
+
     def skip_whitespace(self):
         while not self.eof():
             ch = self.peek()
@@ -37,21 +41,56 @@
                 self.next()
             else:
                 break
+            
+    def _raise(self, msg, *args):
+        raise operationerrfmt(self.w_ValueError, msg, *args)
 
     def decode_any(self):
         self.skip_whitespace()
-        ch = self.peek()
+        ch = self.next()
         if ch == '"':
             return self.decode_string()
+        elif ch == '{':
+            return self.decode_object()
         else:
             assert False, 'Unkown char: %s' % ch
 
-    def getslice(self, start, end):
-        assert end > 0
-        return self.s[start:end]
+    def decode_object(self):
+        start = self.i
+        w_dict = self.space.newdict()
+        while not self.eof():
+            ch = self.peek()
+            if ch == '}':
+                self.next()
+                return w_dict
+            #
+            # parse a key: value
+            self.last_type = TYPE_UNKNOWN
+            w_name = self.decode_any()
+            if self.last_type != TYPE_STRING:
+                self._raise("Key name must be string")
+            self.skip_whitespace()
+            ch = self.next()
+            if ch != ':':
+                self._raise("No ':' found at char %d", self.i)
+            self.skip_whitespace()
+            #
+            w_value = self.decode_any()
+            self.space.setitem(w_dict, w_name, w_value)
+            self.skip_whitespace()
+            ch = self.next()
+            if ch == '}':
+                return w_dict
+            elif ch == ',':
+                pass
+            else:
+                self._raise("Unexpected '%s' when decoding object (char %d)",
+                            ch, self.i)
+        self._raise("Unterminated object starting at char %d", start)
+
+
 
     def decode_string(self):
-        self.next()
         start = self.i
         while not self.eof():
             # this loop is a fast path for strings which do not contain escape
@@ -66,8 +105,7 @@
                 content_so_far = self.getslice(start, self.i-1)
                 self.unget()
                 return self.decode_string_escaped(start, content_so_far)
-        raise operationerrfmt(self.space.w_ValueError,
-                              "Unterminated string starting at char %d", start)
+        self._raise("Unterminated string starting at char %d", start)
 
 
     def decode_string_escaped(self, start, content_so_far):
@@ -84,9 +122,8 @@
                 self.decode_escape_sequence(builder)
             else:
                 builder.append_multiple_char(ch, 1) # we should implement 
append_char
-            
-        raise operationerrfmt(self.space.w_ValueError,
-                              "Unterminated string starting at char %d", start)
+        #
+        self._raise("Unterminated string starting at char %d", start)
 
     def decode_escape_sequence(self, builder):
         put = builder.append_multiple_char
@@ -102,8 +139,7 @@
         elif ch == 'u':
             return self.decode_escape_sequence_unicode(builder)
         else:
-            raise operationerrfmt(self.space.w_ValueError,
-                                  "Invalid \\escape: %s (char %d)", ch, 
self.i-1)
+            self._raise("Invalid \\escape: %s (char %d)", ch, self.i-1)
 
     def decode_escape_sequence_unicode(self, builder):
         # at this point we are just after the 'u' of the \u1234 sequence.
@@ -112,8 +148,7 @@
         try:
             uchr = unichr(int(hexdigits, 16))
         except ValueError:
-            raise operationerrfmt(self.space.w_ValueError,
-                                  "Invalid \uXXXX escape (char %d)", self.i-1)
+            self._raise("Invalid \uXXXX escape (char %d)", self.i-1)
         #
         utf8_ch = unicodehelper.encode_utf8(self.space, uchr)
         builder.append(utf8_ch)
diff --git a/pypy/module/_fastjson/test/test__fastjson.py 
b/pypy/module/_fastjson/test/test__fastjson.py
--- a/pypy/module/_fastjson/test/test__fastjson.py
+++ b/pypy/module/_fastjson/test/test__fastjson.py
@@ -68,3 +68,15 @@
         import _fastjson
         s = r'"\u1234"'
         assert _fastjson.loads(s) == u'\u1234'
+
+    def test_decode_object(self):
+        import _fastjson
+        assert _fastjson.loads('{}') == {}
+        #
+        s = '{"hello": "world", "aaa": "bbb"}'
+        assert _fastjson.loads(s) == {'hello': 'world',
+                                      'aaa': 'bbb'}
+
+    def test_decode_object_nonstring_key(self):
+        pass # write me when we have numbers
+    
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to