jpayne@68: """JSON token scanner jpayne@68: """ jpayne@68: import re jpayne@68: try: jpayne@68: from _json import make_scanner as c_make_scanner jpayne@68: except ImportError: jpayne@68: c_make_scanner = None jpayne@68: jpayne@68: __all__ = ['make_scanner'] jpayne@68: jpayne@68: NUMBER_RE = re.compile( jpayne@68: r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?', jpayne@68: (re.VERBOSE | re.MULTILINE | re.DOTALL)) jpayne@68: jpayne@68: def py_make_scanner(context): jpayne@68: parse_object = context.parse_object jpayne@68: parse_array = context.parse_array jpayne@68: parse_string = context.parse_string jpayne@68: match_number = NUMBER_RE.match jpayne@68: strict = context.strict jpayne@68: parse_float = context.parse_float jpayne@68: parse_int = context.parse_int jpayne@68: parse_constant = context.parse_constant jpayne@68: object_hook = context.object_hook jpayne@68: object_pairs_hook = context.object_pairs_hook jpayne@68: memo = context.memo jpayne@68: jpayne@68: def _scan_once(string, idx): jpayne@68: try: jpayne@68: nextchar = string[idx] jpayne@68: except IndexError: jpayne@68: raise StopIteration(idx) from None jpayne@68: jpayne@68: if nextchar == '"': jpayne@68: return parse_string(string, idx + 1, strict) jpayne@68: elif nextchar == '{': jpayne@68: return parse_object((string, idx + 1), strict, jpayne@68: _scan_once, object_hook, object_pairs_hook, memo) jpayne@68: elif nextchar == '[': jpayne@68: return parse_array((string, idx + 1), _scan_once) jpayne@68: elif nextchar == 'n' and string[idx:idx + 4] == 'null': jpayne@68: return None, idx + 4 jpayne@68: elif nextchar == 't' and string[idx:idx + 4] == 'true': jpayne@68: return True, idx + 4 jpayne@68: elif nextchar == 'f' and string[idx:idx + 5] == 'false': jpayne@68: return False, idx + 5 jpayne@68: jpayne@68: m = match_number(string, idx) jpayne@68: if m is not None: jpayne@68: integer, frac, exp = m.groups() jpayne@68: if frac or exp: jpayne@68: res = parse_float(integer + (frac or '') + (exp or '')) jpayne@68: else: jpayne@68: res = parse_int(integer) jpayne@68: return res, m.end() jpayne@68: elif nextchar == 'N' and string[idx:idx + 3] == 'NaN': jpayne@68: return parse_constant('NaN'), idx + 3 jpayne@68: elif nextchar == 'I' and string[idx:idx + 8] == 'Infinity': jpayne@68: return parse_constant('Infinity'), idx + 8 jpayne@68: elif nextchar == '-' and string[idx:idx + 9] == '-Infinity': jpayne@68: return parse_constant('-Infinity'), idx + 9 jpayne@68: else: jpayne@68: raise StopIteration(idx) jpayne@68: jpayne@68: def scan_once(string, idx): jpayne@68: try: jpayne@68: return _scan_once(string, idx) jpayne@68: finally: jpayne@68: memo.clear() jpayne@68: jpayne@68: return scan_once jpayne@68: jpayne@68: make_scanner = c_make_scanner or py_make_scanner