| 73 | |
| 74 | |
| 75 | class Ruler(Generic[RuleFuncTv]): |
| 76 | def __init__(self) -> None: |
| 77 | # List of added rules. |
| 78 | self.__rules__: list[Rule[RuleFuncTv]] = [] |
| 79 | # Cached rule chains. |
| 80 | # First level - chain name, '' for default. |
| 81 | # Second level - diginal anchor for fast filtering by charcodes. |
| 82 | self.__cache__: dict[str, list[RuleFuncTv]] | None = None |
| 83 | |
| 84 | def __find__(self, name: str) -> int: |
| 85 | """Find rule index by name""" |
| 86 | for i, rule in enumerate(self.__rules__): |
| 87 | if rule.name == name: |
| 88 | return i |
| 89 | return -1 |
| 90 | |
| 91 | def __compile__(self) -> None: |
| 92 | """Build rules lookup cache""" |
| 93 | chains = {""} |
| 94 | # collect unique names |
| 95 | for rule in self.__rules__: |
| 96 | if not rule.enabled: |
| 97 | continue |
| 98 | for name in rule.alt: |
| 99 | chains.add(name) |
| 100 | self.__cache__ = {} |
| 101 | for chain in chains: |
| 102 | self.__cache__[chain] = [] |
| 103 | for rule in self.__rules__: |
| 104 | if not rule.enabled: |
| 105 | continue |
| 106 | if chain and (chain not in rule.alt): |
| 107 | continue |
| 108 | self.__cache__[chain].append(rule.fn) |
| 109 | |
| 110 | def at( |
| 111 | self, ruleName: str, fn: RuleFuncTv, options: RuleOptionsType | None = None |
| 112 | ) -> None: |
| 113 | """Replace rule by name with new function & options. |
| 114 | |
| 115 | :param ruleName: rule name to replace. |
| 116 | :param fn: new rule function. |
| 117 | :param options: new rule options (not mandatory). |
| 118 | :raises: KeyError if name not found |
| 119 | """ |
| 120 | index = self.__find__(ruleName) |
| 121 | options = options or {} |
| 122 | if index == -1: |
| 123 | raise KeyError(f"Parser rule not found: {ruleName}") |
| 124 | self.__rules__[index].fn = fn |
| 125 | self.__rules__[index].alt = options.get("alt", []) |
| 126 | self.__cache__ = None |
| 127 | |
| 128 | def before( |
| 129 | self, |
| 130 | beforeName: str, |
| 131 | ruleName: str, |
| 132 | fn: RuleFuncTv, |
nothing calls this directly
no outgoing calls
no test coverage detected
searching dependent graphs…