+ return integer_parser
+
+_BINARY_MATCHER = re.compile(r'"([\da-f]*)"b')
+
+@_consume_leading_whitespace
+def _binary_parser(s):
+ match = _BINARY_MATCHER.match(s)
+
+ if match:
+ return _shared.ParseResult(
+ success = True,
+ value = binascii.unhexlify(match.group(1)),
+ remaining = s[match.end():],
+ )
+
+ return _shared._FAILED_PARSE_RESULT
+
+def _make_utf_parser(encoding):
+ matcher = re.compile(r'"(.*?)"' + encoding)
+
+ @_consume_leading_whitespace
+ def utf_parser(s):
+ match = matcher.match(s)
+
+ if match:
+ return _shared.ParseResult(
+ success = True,
+ value = match.group(1),
+ remaining = s[match.end():],
+ )
+
+ return _shared._FAILED_PARSE_RESULT
+
+ return utf_parser
+
+def _make_consume_constant_parser(constant):
+ @_consume_leading_whitespace
+ def consume_character_parser(s):
+ if s.startswith(constant):
+ return _shared.ParseResult(
+ success = True,
+ value = None,
+ remaining = s[len(constant):],
+ )
+ return _shared._FAILED_PARSE_RESULT
+
+ return consume_character_parser
+
+_consume_comma_parser = _make_consume_constant_parser(',')
+
+def _prefix_with_comma(parser):
+ def wrapped(s):
+ result = _consume_comma_parser(s)
+ if result.success:
+ s = result.remaining
+ else:
+ return _shared._FAILED_PARSE_RESULT
+
+ result = parser(s)
+ if not result.success:
+ raise Exception('Trailing comma before "{}"'.format(s))
+
+ return result
+
+ return wrapped
+
+def _comma_separate_and_wrap(wrapped_parser, start_wrap, end_wrap, typecaster):
+ parser_prefixed_with_comma = _prefix_with_comma(wrapped_parser)
+ start_wrap_parser = _make_consume_constant_parser(start_wrap)
+ end_wrap_parser = _make_consume_constant_parser(end_wrap)
+
+ def parser(s):
+ result = start_wrap_parser(s)
+ if result.success:
+ s = result.remaining
+ 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)
+
+ result = end_wrap_parser(s)
+ if result.success:
+ s = result.remaining
+ else:
+ return _shared._FAILED_PARSE_RESULT
+
+ return _shared.ParseResult(
+ success = True,
+ value = typecaster(value),
+ remaining = s,
+ )
+