def _create_parser():
    expr = forward_ref()
    parens_expr = seq(txt("("), expr, txt(")"), pick=1)

    def flatten(*objs):
        objs = collections.deque(objs)
        while objs:
            obj = objs.popleft()
            try:
                obj = iter(obj)
            except TypeError:
                yield obj
            else:
                objs.extendleft(obj)

    @parser_singleton
    def ws((string, start, end), chars=frozenset(" \t\n\r")):
        if not start < end or string[start] not in chars:
            yield None, None
        start += 1

        while start < end and string[start] in chars:
            start += 1
        yield None, (None, (string, start, end))

    match_tail = union(
        seq(maybe(ws), txt("="), maybe(txt("=")), maybe(ws), union(star_parser, regexp_parser, string_parser), pick=-1),
        seq(ws, txt("in", ignore_case=True), ws, union(ip_parser, domainname_parser), pick=-1),
    )

    non_match_tail = union(
        seq(maybe(ws), txt("!="), maybe(ws), union(star_parser, regexp_parser, string_parser), pick=-1),
        seq(ws, txt("not", ignore_case=True), ws, txt("in", ignore_case=True), ws, union(ip_parser, domainname_parser), pick=-1),
    )

    basic = union(
        step(
            star_parser,
            (match_tail, rules.Match),
            (non_match_tail, rules.NonMatch),
            step_default(lambda x: rules.Anything())
        ),

        transform(
            rules.Fuzzy,
            union(regexp_parser, ip_parser, domainname_parser)
        ),

        step(
            string_parser,
            (match_tail, rules.Match),
            (non_match_tail, rules.NonMatch),
            step_default(rules.Fuzzy)
        )
    )

    no_parser = forward_ref()
    no_parser.set(transform(
        rules.No,
        seq(
            txt("no", ignore_case=True),
            union(
                seq(maybe(ws), parens_expr, pick=1),
                seq(ws, union(no_parser, basic), pick=1)
            ),
            pick=1
        )
    ))

    and_tail = forward_ref()
    or_tail = forward_ref()

    def binary_rule_tail(name):
        result = forward_ref()
        result.set(
            seq(
                txt(name, ignore_case=True),
                union(
                    step(
                        seq(maybe(ws), parens_expr, pick=1),
                        (seq(maybe(ws), result, pick=1), lambda x, y: (x, y)),
                        (seq(maybe(ws), and_tail, pick=1), lambda x, y: rules.And(*flatten(x, y))),
                        (seq(maybe(ws), or_tail, pick=1), lambda x, y: rules.Or(*flatten(x, y))),
                        step_default()
                    ),
                    step(
                        seq(ws, union(no_parser, basic), pick=1),
                        (seq(ws, result, pick=1), lambda x, y: (x, y)),
                        (seq(ws, and_tail, pick=1), lambda x, y: rules.And(*flatten(x, y))),
                        (seq(ws, or_tail, pick=1), lambda x, y: rules.Or(*flatten(x, y))),
                        step_default()
                    )
                ),
                pick=1
            )
        )
        return result
    and_tail.set(binary_rule_tail("and"))
    or_tail.set(binary_rule_tail("or"))

    expr.set(
        seq(
            maybe(ws),
            union(
                step(
                    parens_expr,
                    (seq(maybe(ws), and_tail, pick=1), lambda x, y: rules.And(*flatten(x, y))),
                    (seq(maybe(ws), or_tail, pick=1), lambda x, y: rules.Or(*flatten(x, y))),
                    step_default()
                ),
                step(
                    union(no_parser, basic),
                    (seq(ws, and_tail, pick=1), lambda x, y: rules.And(*flatten(x, y))),
                    (seq(ws, or_tail, pick=1), lambda x, y: rules.Or(*flatten(x, y))),
                    step_default()
                )
            ),
            maybe(ws),
            pick=1
        )
    )
    return expr
dataset/ETHPy150Open abusesa/abusehelper/abusehelper/core/rules/rulelang.py/_create_parser/original