1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
# this should really be in the stdlib imo
from dataclasses import dataclass
from typing import List as ListT, Union, ClassVar
from .parse_utils import ParseResult, Parser, take_while1, tag, delimited, take_n, alt, map_parser, separated_many0, separated_triple, all_consuming
__all__ = [
'List',
]
atom: Parser[str] = take_while1(lambda c: c.isalnum() or c in r'\/')
number: Parser[int] = map_parser(take_while1(str.isnumeric), int)
def literal_string(text: str) -> ParseResult[str]:
delimited_result = delimited(tag('{'), number, tag('}\r\n'))(text)
if delimited_result is None:
return None
count, text = delimited_result
return take_n(count)(text)
quoted_string: Parser[str] = delimited(tag('"'), take_while1(lambda c: c not in '\r\n"'), tag('"'))
string: Parser[str] = alt(literal_string, quoted_string)
astring: Parser[str] = alt(atom, string)
data_item: Parser[Union[int, str]] = alt(number, atom, string)
ParensList = ListT[Union[int, str, 'ParensList']]
def parens_list(text: str) -> ParseResult[ParensList]:
return delimited(tag('('), separated_many0(alt(data_item, parens_list), tag(' ')), tag(')'))(text)
@dataclass
class List:
attributes: ListT[str]
delimiter: str
name: str
@staticmethod
def parse(response: bytes) -> 'List':
response = response.decode('ASCII')
print(response)
parser = all_consuming(separated_triple(parens_list, tag(' '), string, tag(' '), astring), debug=True)
(attributes, delimiter, name), _ = parser(response)
return List(attributes, delimiter, name)
|