scanner.py 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. """JSON token scanner
  2. """
  3. import re
  4. try:
  5. from _json import make_scanner as c_make_scanner
  6. except ImportError:
  7. c_make_scanner = None
  8. __all__ = ['make_scanner']
  9. NUMBER_RE = re.compile(
  10. r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?',
  11. (re.VERBOSE | re.MULTILINE | re.DOTALL))
  12. def py_make_scanner(context):
  13. parse_object = context.parse_object
  14. parse_array = context.parse_array
  15. parse_string = context.parse_string
  16. match_number = NUMBER_RE.match
  17. strict = context.strict
  18. parse_float = context.parse_float
  19. parse_int = context.parse_int
  20. parse_constant = context.parse_constant
  21. object_hook = context.object_hook
  22. object_pairs_hook = context.object_pairs_hook
  23. memo = context.memo
  24. def _scan_once(string, idx):
  25. try:
  26. nextchar = string[idx]
  27. except IndexError:
  28. raise StopIteration(idx) from None
  29. if nextchar == '"':
  30. return parse_string(string, idx + 1, strict)
  31. elif nextchar == '{':
  32. return parse_object((string, idx + 1), strict,
  33. _scan_once, object_hook, object_pairs_hook, memo)
  34. elif nextchar == '[':
  35. return parse_array((string, idx + 1), _scan_once)
  36. elif nextchar == 'n' and string[idx:idx + 4] == 'null':
  37. return None, idx + 4
  38. elif nextchar == 't' and string[idx:idx + 4] == 'true':
  39. return True, idx + 4
  40. elif nextchar == 'f' and string[idx:idx + 5] == 'false':
  41. return False, idx + 5
  42. m = match_number(string, idx)
  43. if m is not None:
  44. integer, frac, exp = m.groups()
  45. if frac or exp:
  46. res = parse_float(integer + (frac or '') + (exp or ''))
  47. else:
  48. res = parse_int(integer)
  49. return res, m.end()
  50. elif nextchar == 'N' and string[idx:idx + 3] == 'NaN':
  51. return parse_constant('NaN'), idx + 3
  52. elif nextchar == 'I' and string[idx:idx + 8] == 'Infinity':
  53. return parse_constant('Infinity'), idx + 8
  54. elif nextchar == '-' and string[idx:idx + 9] == '-Infinity':
  55. return parse_constant('-Infinity'), idx + 9
  56. else:
  57. raise StopIteration(idx)
  58. def scan_once(string, idx):
  59. try:
  60. return _scan_once(string, idx)
  61. finally:
  62. memo.clear()
  63. return scan_once
  64. make_scanner = c_make_scanner or py_make_scanner