| 596 | |
| 597 | |
| 598 | def _make(): |
| 599 | # Order is important - multi-char expressions need to come before narrow |
| 600 | # ones. |
| 601 | parts = [] |
| 602 | for cls in filter_unary: |
| 603 | f = pp.Literal(f"~{cls.code}") + pp.WordEnd() |
| 604 | f.setParseAction(cls.make) |
| 605 | parts.append(f) |
| 606 | |
| 607 | # This is a bit of a hack to simulate Word(pyparsing_unicode.printables), |
| 608 | # which has a horrible performance with len(pyparsing.pyparsing_unicode.printables) == 1114060 |
| 609 | unicode_words = pp.CharsNotIn("()~'\"" + pp.ParserElement.DEFAULT_WHITE_CHARS) |
| 610 | unicode_words.skipWhitespace = True |
| 611 | regex = ( |
| 612 | unicode_words |
| 613 | | pp.QuotedString('"', escChar="\\") |
| 614 | | pp.QuotedString("'", escChar="\\") |
| 615 | ) |
| 616 | for cls in filter_rex: |
| 617 | f = pp.Literal(f"~{cls.code}") + pp.WordEnd() + regex.copy() |
| 618 | f.setParseAction(cls.make) |
| 619 | parts.append(f) |
| 620 | |
| 621 | for cls in filter_int: |
| 622 | f = pp.Literal(f"~{cls.code}") + pp.WordEnd() + pp.Word(pp.nums) |
| 623 | f.setParseAction(cls.make) |
| 624 | parts.append(f) |
| 625 | |
| 626 | # A naked rex is a URL rex: |
| 627 | f = regex.copy() |
| 628 | f.setParseAction(FUrl.make) |
| 629 | parts.append(f) |
| 630 | |
| 631 | atom = pp.MatchFirst(parts) |
| 632 | expr = pp.OneOrMore( |
| 633 | pp.infixNotation( |
| 634 | atom, |
| 635 | [ |
| 636 | (pp.Literal("!").suppress(), 1, pp.opAssoc.RIGHT, lambda x: FNot(*x)), |
| 637 | (pp.Literal("&").suppress(), 2, pp.opAssoc.LEFT, lambda x: FAnd(*x)), |
| 638 | (pp.Literal("|").suppress(), 2, pp.opAssoc.LEFT, lambda x: FOr(*x)), |
| 639 | ], |
| 640 | ) |
| 641 | ) |
| 642 | return expr.setParseAction(lambda x: FAnd(x) if len(x) != 1 else x) |
| 643 | |
| 644 | |
| 645 | bnf = _make() |