import binascii
+import collections
+import functools
import re
from don import tags, _shared
return _STRING_SERIALIZERS[o.tag](o.value)
-def _make_constant_parser(constant, value):
+def _consume_leading_whitespace(wrapped_parser):
+ @functools.wraps(wrapped_parser)
def parser(s):
+ s = s.lstrip()
+ return wrapped_parser(s)
+
+ return parser
+
+def _make_constant_parser(constant, value):
+ @_consume_leading_whitespace
+ def constant_parser(s):
if s.startswith(constant):
result = _shared.ParseResult(
success = True,
return _shared._FAILED_PARSE_RESULT
- return parser
+ return constant_parser
def _make_integer_parser(width):
matcher = re.compile(r'(-?\d+)i' + str(width))
- def parser(s):
+ @_consume_leading_whitespace
+ def integer_parser(s):
match = matcher.match(s)
if match:
return _shared._FAILED_PARSE_RESULT
- return parser
+ return integer_parser
_BINARY32_MATCHER = re.compile(r'(-?\d+\.\d+)f')
_BINARY64_MATCHER = re.compile(r'(-?\d+\.\d+)d')
return wrapped
-def _list_parser(s):
- # TODO Assert they are all the same type
- if not s.startswith('['):
- return _shared._FAILED_PARSE_RESULT
- s = s[1:]
+def _comma_separate_and_wrap(wrapped_parser, start_wrap, end_wrap, typecaster):
+ parser_prefixed_with_comma = _prefix_with_comma(wrapped_parser)
+
+ def parser(s):
+ if s.startswith(start_wrap):
+ s = s[1:]
+ else:
+ return _shared._FAILED_PARSE_RESULT
+
+ value = []
+ first = True
+
+ parse_result = wrapped_parser(s)
+
+ while parse_result.success:
+ value.append(parse_result.value)
+ s = parse_result.remaining
+ parse_result = parser_prefixed_with_comma(s)
+
+ if s.startswith(end_wrap):
+ s = s[1:]
+ else:
+ return _shared._FAILED_PARSE_RESULT
+
+ return _shared.ParseResult(
+ success = True,
+ value = typecaster(value),
+ remaining = s,
+ )
+
+ return parser
- value = []
+# This uses _PARSERS which has not been defined yet, but is defined here so it can be used in
+# the definition of _list_parser
+def _object_parser(source):
+ for parser in _PARSERS:
+ result = parser(source)
+
+ if result.success:
+ return result
- first = True
- parse_result = _object_parser(s)
+ return _shared._FAILED_PARSE_RESULT
+
+_list_parser = _comma_separate_and_wrap(_object_parser, '[', ']', list)
+
+def _kvp_parser(s):
+ key_parse_result = _object_parser(s)
+ if key_parse_result.success:
+ s = key_parse_result.remaining
+ else:
+ return _shared._FAILED_PARSE_RESULT
- while parse_result.success:
- value.append(parse_result.value)
- s = parse_result.remaining
- parse_result = _prefix_with_comma(_object_parser)(s)
+ if s.startswith(':'):
+ s = s[1:]
+ else:
+ return _shared._FAILED_PARSE_RESULT
- if not s.startswith(']'):
+ value_parse_result = _object_parser(s)
+ if value_parse_result.success:
+ s = value_parse_result.remaining
+ else:
return _shared._FAILED_PARSE_RESULT
return _shared.ParseResult(
success = True,
- value = value,
- remaining = s[1:],
+ value = (key_parse_result.value, value_parse_result.value),
+ remaining = s,
)
-
-
-def _dictionary_parser(s):
- return _shared._FAILED_PARSE_RESULT
+_dictionary_parser = _comma_separate_and_wrap(_kvp_parser, '{', '}', collections.OrderedDict)
_PARSERS = [
_dictionary_parser,
]
-def _object_parser(source):
- for parser in _PARSERS:
- result = parser(source)
-
- if result.success:
- return result
-
- return _shared._FAILED_PARSE_RESULT
-
def _parse(parser, source):
result = parser(source)