4 from don import tags, _shared
6 def _integer_size_to_string_serializer(integer_size):
7 minimum = -(2 ** (integer_size - 1))
8 maximum = 2 ** (integer_size - 1) - 1
10 def serializer(integer):
11 assert minimum <= integer and integer <= maximum
12 return '{}i{}'.format(integer, integer_size)
16 def _serialize_float(f):
17 return '{}f'.format(f)
19 def _serialize_double(d):
20 return '{}d'.format(d)
22 def _serialize_binary(b):
23 return '"{}"b'.format(binascii.hexlify(b).decode('ascii'))
25 def _utf_encoding_to_serializer(utf_encoding):
27 return '"{}"{}'.format(s, utf_encoding)
31 def _string_serialize_list(l):
32 return '[{}]'.format(', '.join(map(serialize, l)))
34 def _string_serialize_dictionary(d):
35 def serialize_kvp(kvp):
36 return serialize(kvp[0]) + ': ' + serialize(kvp[1])
37 return '{ ' + ', '.join(map(serialize_kvp, d.items())) + ' }'
39 _STRING_SERIALIZERS = {
40 tags.VOID: lambda o: 'null',
41 tags.TRUE: lambda o: 'true',
42 tags.FALSE: lambda o: 'false',
43 tags.INT8: _integer_size_to_string_serializer(8),
44 tags.INT16: _integer_size_to_string_serializer(16),
45 tags.INT32: _integer_size_to_string_serializer(32),
46 tags.INT64: _integer_size_to_string_serializer(64),
47 tags.FLOAT: _serialize_float,
48 tags.DOUBLE: _serialize_double,
49 tags.BINARY: _serialize_binary,
50 tags.UTF8: _utf_encoding_to_serializer('utf8'),
51 tags.UTF16: _utf_encoding_to_serializer('utf16'),
52 tags.UTF32: _utf_encoding_to_serializer('utf32'),
53 tags.LIST: _string_serialize_list,
54 tags.DICTIONARY: _string_serialize_dictionary,
60 return _STRING_SERIALIZERS[o.tag](o.value)
62 def _make_constant_parser(constant, value):
64 if s.startswith(constant):
65 result = _shared.ParseResult(
68 remaining = s[len(constant):],
72 return _shared._FAILED_PARSE_RESULT
76 def _make_integer_parser(width):
77 matcher = re.compile(r'(-?\d+)i' + str(width))
80 match = matcher.match(s)
83 # TODO Validate that the integer is in range
84 return _shared.ParseResult(
86 value = int(match.group(1)),
87 remaining = s[match.end():],
90 return _shared._FAILED_PARSE_RESULT
94 _BINARY32_MATCHER = re.compile(r'(-?\d+\.\d+)f')
95 _BINARY64_MATCHER = re.compile(r'(-?\d+\.\d+)d')
97 def _binary32_parser(s):
98 match = _BINARY32_MATCHER.match(s)
101 # TODO Validate that the double is in range
102 return _shared.ParseResult(
104 value = float(match.group(1)),
105 remaining = s[match.end():],
108 return _shared._FAILED_PARSE_RESULT
110 def _binary64_parser(s):
111 match = _BINARY64_MATCHER.match(s)
114 # TODO Validate that the double is in range
115 return _shared.ParseResult(
117 value = float(match.group(1)),
118 remaining = s[match.end():],
121 return _shared._FAILED_PARSE_RESULT
123 _BINARY_MATCHER = re.compile(r'"([\da-f]*)"b')
125 def _binary_parser(s):
126 match = _BINARY_MATCHER.match(s)
129 # TODO Validate that the double is in range
130 return _shared.ParseResult(
132 value = binascii.unhexlify(match.group(1)),
133 remaining = s[match.end():],
136 return _shared._FAILED_PARSE_RESULT
141 _make_constant_parser('null', None),
142 _make_constant_parser('true', True),
143 _make_constant_parser('false', False),
144 _make_integer_parser(8),
145 _make_integer_parser(16),
146 _make_integer_parser(32),
147 _make_integer_parser(64),
153 def _object_parser(source):
154 for parser in _PARSERS:
155 result = parser(source)
160 return _shared._FAILED_PARSE_RESULT
162 def _parse(parser, source):
163 result = parser(source)
166 if result.remaining.strip() == '':
169 raise Exception('Unparsed trailing characters: "{}"'.format(result.remaining))
171 raise Exception('Unable to parse: "{}"'.format(source))
174 return _parse(_object_parser, s)