# 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)