gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / simplejson / scanner.py @ 545
History | View | Annotate | Download (4.54 KB)
1 |
"""JSON token scanner
|
---|---|
2 |
"""
|
3 |
import re |
4 |
def _import_c_make_scanner(): |
5 |
try:
|
6 |
from simplejson._speedups import make_scanner |
7 |
return make_scanner
|
8 |
except ImportError: |
9 |
return None |
10 |
c_make_scanner = _import_c_make_scanner() |
11 |
|
12 |
__all__ = ['make_scanner', 'JSONDecodeError'] |
13 |
|
14 |
NUMBER_RE = re.compile( |
15 |
r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?',
|
16 |
(re.VERBOSE | re.MULTILINE | re.DOTALL)) |
17 |
|
18 |
class JSONDecodeError(ValueError): |
19 |
"""Subclass of ValueError with the following additional properties:
|
20 |
|
21 |
msg: The unformatted error message
|
22 |
doc: The JSON document being parsed
|
23 |
pos: The start index of doc where parsing failed
|
24 |
end: The end index of doc where parsing failed (may be None)
|
25 |
lineno: The line corresponding to pos
|
26 |
colno: The column corresponding to pos
|
27 |
endlineno: The line corresponding to end (may be None)
|
28 |
endcolno: The column corresponding to end (may be None)
|
29 |
|
30 |
"""
|
31 |
# Note that this exception is used from _speedups
|
32 |
def __init__(self, msg, doc, pos, end=None): |
33 |
ValueError.__init__(self, errmsg(msg, doc, pos, end=end)) |
34 |
self.msg = msg
|
35 |
self.doc = doc
|
36 |
self.pos = pos
|
37 |
self.end = end
|
38 |
self.lineno, self.colno = linecol(doc, pos) |
39 |
if end is not None: |
40 |
self.endlineno, self.endcolno = linecol(doc, end) |
41 |
else:
|
42 |
self.endlineno, self.endcolno = None, None |
43 |
|
44 |
def __reduce__(self): |
45 |
return self.__class__, (self.msg, self.doc, self.pos, self.end) |
46 |
|
47 |
|
48 |
def linecol(doc, pos): |
49 |
lineno = doc.count('\n', 0, pos) + 1 |
50 |
if lineno == 1: |
51 |
colno = pos + 1
|
52 |
else:
|
53 |
colno = pos - doc.rindex('\n', 0, pos) |
54 |
return lineno, colno
|
55 |
|
56 |
|
57 |
def errmsg(msg, doc, pos, end=None): |
58 |
lineno, colno = linecol(doc, pos) |
59 |
msg = msg.replace('%r', repr(doc[pos:pos + 1])) |
60 |
if end is None: |
61 |
fmt = '%s: line %d column %d (char %d)'
|
62 |
return fmt % (msg, lineno, colno, pos)
|
63 |
endlineno, endcolno = linecol(doc, end) |
64 |
fmt = '%s: line %d column %d - line %d column %d (char %d - %d)'
|
65 |
return fmt % (msg, lineno, colno, endlineno, endcolno, pos, end)
|
66 |
|
67 |
|
68 |
def py_make_scanner(context): |
69 |
parse_object = context.parse_object |
70 |
parse_array = context.parse_array |
71 |
parse_string = context.parse_string |
72 |
match_number = NUMBER_RE.match |
73 |
encoding = context.encoding |
74 |
strict = context.strict |
75 |
parse_float = context.parse_float |
76 |
parse_int = context.parse_int |
77 |
parse_constant = context.parse_constant |
78 |
object_hook = context.object_hook |
79 |
object_pairs_hook = context.object_pairs_hook |
80 |
memo = context.memo |
81 |
|
82 |
def _scan_once(string, idx): |
83 |
errmsg = 'Expecting value'
|
84 |
try:
|
85 |
nextchar = string[idx] |
86 |
except IndexError: |
87 |
raise JSONDecodeError(errmsg, string, idx)
|
88 |
|
89 |
if nextchar == '"': |
90 |
return parse_string(string, idx + 1, encoding, strict) |
91 |
elif nextchar == '{': |
92 |
return parse_object((string, idx + 1), encoding, strict, |
93 |
_scan_once, object_hook, object_pairs_hook, memo) |
94 |
elif nextchar == '[': |
95 |
return parse_array((string, idx + 1), _scan_once) |
96 |
elif nextchar == 'n' and string[idx:idx + 4] == 'null': |
97 |
return None, idx + 4 |
98 |
elif nextchar == 't' and string[idx:idx + 4] == 'true': |
99 |
return True, idx + 4 |
100 |
elif nextchar == 'f' and string[idx:idx + 5] == 'false': |
101 |
return False, idx + 5 |
102 |
|
103 |
m = match_number(string, idx) |
104 |
if m is not None: |
105 |
integer, frac, exp = m.groups() |
106 |
if frac or exp: |
107 |
res = parse_float(integer + (frac or '') + (exp or '')) |
108 |
else:
|
109 |
res = parse_int(integer) |
110 |
return res, m.end()
|
111 |
elif nextchar == 'N' and string[idx:idx + 3] == 'NaN': |
112 |
return parse_constant('NaN'), idx + 3 |
113 |
elif nextchar == 'I' and string[idx:idx + 8] == 'Infinity': |
114 |
return parse_constant('Infinity'), idx + 8 |
115 |
elif nextchar == '-' and string[idx:idx + 9] == '-Infinity': |
116 |
return parse_constant('-Infinity'), idx + 9 |
117 |
else:
|
118 |
raise JSONDecodeError(errmsg, string, idx)
|
119 |
|
120 |
def scan_once(string, idx): |
121 |
if idx < 0: |
122 |
# Ensure the same behavior as the C speedup, otherwise
|
123 |
# this would work for *some* negative string indices due
|
124 |
# to the behavior of __getitem__ for strings. #98
|
125 |
raise JSONDecodeError('Expecting value', string, idx) |
126 |
try:
|
127 |
return _scan_once(string, idx)
|
128 |
finally:
|
129 |
memo.clear() |
130 |
|
131 |
return scan_once
|
132 |
|
133 |
make_scanner = c_make_scanner or py_make_scanner
|