from muppet.parser_combinator import ( MatchObject, ParseDirective, ParseError, ParserCombinator, all_, char, complement, count, digit, hexdig, line_comment, many, many1, name, nop, not_, optional, s, tag, ws, delimited, discard, space, ) def test_partial(): data = "123 Hello" parser = ParserCombinator(data) assert ["123"] == parser.get(many(digit)) assert " Hello" == parser.remaining() def test_char(): parser = ParserCombinator("Hello!") assert ['H'] == parser.get(char) assert ['e'] == parser.get(char) assert "llo!" == parser.remaining() def test_nop(): parser = ParserCombinator("Hello!") assert [] == parser.get(nop) assert "Hello!" == parser.remaining() def test_digit(): p1 = ParserCombinator("123") assert ['1'] == p1.get(digit) p2 = ParserCombinator("Hello") try: p2.get(digit) assert False, "Parser should have failed, but didn't" except ParseError: assert "Hello" == p2.remaining() def test_consume(): p = ParserCombinator("Hello") try: p.get([char, digit]) assert False, "Parser should have failed, but didn't" except ParseError: assert "ello" == p.remaining() def test_hexdig(): pass def test_space(): pass # -------------------------------------------------- def test_many(): p1 = ParserCombinator("Hello, World!") assert ["Hello, World!"] == p1.get(many(char)) p2 = ParserCombinator("") assert [] == p2.get(many(char)) def test_many1(): p1 = ParserCombinator("Hello, World!") assert ["Hello, World!"] == p1.get(many1(char)) p2 = ParserCombinator("") try: p2.get(many1(char)) assert False, "Parser should have failed, but didn't" except ParseError: assert True def test_count(): p1 = ParserCombinator("ABCDE") assert ["A"] == p1.get(count(s("A"), 1, 3)) p2 = ParserCombinator("AAAAA") assert ["AAA"] == p2.get(count(s("A"), 1, 3)) p3 = ParserCombinator("BBBBB") assert [] == p3.get(count(s("A"), 3)) p4 = ParserCombinator("AAAAA") assert ["AAA"] == p4.get(count(s("A"), 3)) def test_optional(): p1 = ParserCombinator("ABC") assert ["A"] == p1.get(optional(s("A"))) assert "BC" == p1.remaining() p2 = ParserCombinator("ABC") assert [] == p2.get(optional(s("B"))) assert "ABC" == p2.remaining() def test_ws(): p1 = ParserCombinator("Hello") assert [] == p1.get(ws) p2 = ParserCombinator("\t \n\r Hello") assert ["\t \n\r "] == p2.get(ws) def test_discard(): p1 = ParserCombinator("Hello") assert [] == p1.get(discard(s("He"))) assert "llo" == p1.remaining() p2 = ParserCombinator("Hello!") assert ["ll"] == p2.get(discard(s("He")) & s("ll") & discard(s("o"))) assert "!" == p2.remaining() def handle_int(xs: list[str]) -> list[int]: """Convert matched to an integer.""" return [int(xs[0])] def test_delimited(): number = many(digit) @ handle_int p1 = ParserCombinator("1,20,2") assert [1, ",", 20, ",", 2] == p1.get(delimited(s(","), number)) p2 = ParserCombinator("1,20,2") assert [1, 20, 2] == p2.get(delimited(discard(s(",")), number)) def test_all(): p1 = ParserCombinator("123") assert ["1"] == p1.get(all_(char, digit)) def test_complement_1(): p1 = ParserCombinator("Hello, World!") assert ["H"] == p1.get(all_(~ space, char)) def test_complement_2(): p1 = ParserCombinator("Hello, World!") assert ["Hello,"] == p1.get(many(all_(~ space, char))) def test_complement(): p1 = ParserCombinator("Hello") assert ["H"] == p1.get(complement('e')) p2 = ParserCombinator("Hello") assert ["He"] == p2.get(many(complement("l"))) def test_stringifiers(): assert "'a'" == str(s("a")) assert "~ 'a'" == repr(~ s("a")) assert "x" == str(name("x", space & space)) assert "('a' & 'b')" == str(s('a') & s('b')) assert "('a' | 'b')" == str(s('a') | s('b')) assert "char" == str(char) assert "nop" == str(nop)