~swift-coresec/ubuntu/lucid/sphinx/backport

« back to all changes in this revision

Viewing changes to sphinx/util/jsdump.py

  • Committer: Monty Taylor
  • Author(s): Jakub Wilk
  • Date: 2010-08-08 01:34:29 UTC
  • Revision ID: mordred@inaugust.com-20100808013429-7gmsyypn99gkepfd
Tags: upstream-1.0.1
ImportĀ upstreamĀ versionĀ 1.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
"""
 
3
    sphinx.util.jsdump
 
4
    ~~~~~~~~~~~~~~~~~~
 
5
 
 
6
    This module implements a simple JavaScript serializer.
 
7
    Uses the basestring encode function from simplejson by Bob Ippolito.
 
8
 
 
9
    :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
 
10
    :license: BSD, see LICENSE for details.
 
11
"""
 
12
 
 
13
import re
 
14
 
 
15
_str_re  = re.compile(r'"(\\\\|\\"|[^"])*"')
 
16
_int_re  = re.compile(r'\d+')
 
17
_name_re = re.compile(r'[a-zA-Z]\w*')
 
18
_nameonly_re = re.compile(r'[a-zA-Z]\w*$')
 
19
 
 
20
# escape \, ", control characters and everything outside ASCII
 
21
ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])')
 
22
ESCAPE_DICT = {
 
23
    '\\': '\\\\',
 
24
    '"': '\\"',
 
25
    '\b': '\\b',
 
26
    '\f': '\\f',
 
27
    '\n': '\\n',
 
28
    '\r': '\\r',
 
29
    '\t': '\\t',
 
30
}
 
31
 
 
32
ESCAPED = re.compile(r'\\u.{4}|\\.')
 
33
 
 
34
 
 
35
def encode_string(s):
 
36
    def replace(match):
 
37
        s = match.group(0)
 
38
        try:
 
39
            return ESCAPE_DICT[s]
 
40
        except KeyError:
 
41
            n = ord(s)
 
42
            if n < 0x10000:
 
43
                return '\\u%04x' % (n,)
 
44
            else:
 
45
                # surrogate pair
 
46
                n -= 0x10000
 
47
                s1 = 0xd800 | ((n >> 10) & 0x3ff)
 
48
                s2 = 0xdc00 | (n & 0x3ff)
 
49
                return '\\u%04x\\u%04x' % (s1, s2)
 
50
    return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"'
 
51
 
 
52
def decode_string(s):
 
53
    return ESCAPED.sub(lambda m: eval('u"'+m.group()+'"'), s)
 
54
 
 
55
 
 
56
reswords = set("""\
 
57
abstract   else   instanceof   switch
 
58
boolean   enum   int   synchronized
 
59
break   export   interface   this
 
60
byte   extends   long   throw
 
61
case   false   native   throws
 
62
catch   final   new   transient
 
63
char   finally   null   true
 
64
class   float   package   try
 
65
const   for   private   typeof
 
66
continue   function   protected   var
 
67
debugger   goto   public   void
 
68
default   if   return   volatile
 
69
delete   implements   short   while
 
70
do   import   static   with
 
71
double   in   super""".split())
 
72
 
 
73
def dumps(obj, key=False):
 
74
    if key:
 
75
        if not isinstance(obj, basestring):
 
76
            obj = str(obj)
 
77
        if _nameonly_re.match(obj) and obj not in reswords:
 
78
            return obj  # return it as a bare word
 
79
        else:
 
80
            return encode_string(obj)
 
81
    if obj is None:
 
82
        return 'null'
 
83
    elif obj is True or obj is False:
 
84
        return obj and 'true' or 'false'
 
85
    elif isinstance(obj, (int, long, float)):
 
86
        return str(obj)
 
87
    elif isinstance(obj, dict):
 
88
        return '{%s}' % ','.join('%s:%s' % (
 
89
            dumps(key, True),
 
90
            dumps(value)
 
91
        ) for key, value in obj.iteritems())
 
92
    elif isinstance(obj, (tuple, list, set)):
 
93
        return '[%s]' % ','.join(dumps(x) for x in obj)
 
94
    elif isinstance(obj, basestring):
 
95
        return encode_string(obj)
 
96
    raise TypeError(type(obj))
 
97
 
 
98
def dump(obj, f):
 
99
    f.write(dumps(obj))
 
100
 
 
101
 
 
102
def loads(x):
 
103
    """Loader that can read the JS subset the indexer produces."""
 
104
    nothing = object()
 
105
    i = 0
 
106
    n = len(x)
 
107
    stack = []
 
108
    obj = nothing
 
109
    key = False
 
110
    keys = []
 
111
    while i < n:
 
112
        c = x[i]
 
113
        if c == '{':
 
114
            obj = {}
 
115
            stack.append(obj)
 
116
            key = True
 
117
            keys.append(nothing)
 
118
            i += 1
 
119
        elif c == '[':
 
120
            obj = []
 
121
            stack.append(obj)
 
122
            key = False
 
123
            keys.append(nothing)
 
124
            i += 1
 
125
        elif c in '}]':
 
126
            if key:
 
127
                if keys[-1] is not nothing:
 
128
                    raise ValueError("unfinished dict")
 
129
                # empty dict
 
130
                key = False
 
131
            oldobj = stack.pop()
 
132
            keys.pop()
 
133
            if stack:
 
134
                obj = stack[-1]
 
135
                if isinstance(obj, dict):
 
136
                    if keys[-1] is nothing:
 
137
                        raise ValueError("invalid key object", oldobj)
 
138
                    obj[keys[-1]] = oldobj
 
139
                else:
 
140
                    obj.append(oldobj)
 
141
            else:
 
142
                break
 
143
            i += 1
 
144
        elif c == ',':
 
145
            if key:
 
146
                raise ValueError("multiple keys")
 
147
            if isinstance(obj, dict):
 
148
                key = True
 
149
            i += 1
 
150
        elif c == ':':
 
151
            if not isinstance(obj, dict):
 
152
                raise ValueError("colon in list")
 
153
            i += 1
 
154
            if not key:
 
155
                raise ValueError("multiple values")
 
156
            key = False
 
157
        else:
 
158
            m = _str_re.match(x, i)
 
159
            if m:
 
160
                y = decode_string(m.group()[1:-1])
 
161
            else:
 
162
                m = _int_re.match(x, i)
 
163
                if m:
 
164
                    y = int(m.group())
 
165
                else:
 
166
                    m = _name_re.match(x, i)
 
167
                    if m:
 
168
                        y = m.group()
 
169
                        if y == 'true':
 
170
                            y = True
 
171
                        elif y == 'false':
 
172
                            y = False
 
173
                        elif y == 'null':
 
174
                            y = None
 
175
                        elif not key:
 
176
                            raise ValueError("bareword as value")
 
177
                    else:
 
178
                        raise ValueError("read error at pos %d" % i)
 
179
            i = m.end()
 
180
            if isinstance(obj, dict):
 
181
                if key:
 
182
                    keys[-1] = y
 
183
                else:
 
184
                    obj[keys[-1]] = y
 
185
                    key = False
 
186
            else:
 
187
                obj.append(y)
 
188
    if obj is nothing:
 
189
        raise ValueError("nothing loaded from string")
 
190
    return obj
 
191
 
 
192
def load(f):
 
193
    return loads(f.read())