beanmachine.ppl.compiler.rules module
A rules engine for tree transformation
- class beanmachine.ppl.compiler.rules.AllChildren(rule: beanmachine.ppl.compiler.rules.Rule, get_children: Callable[[Any], Dict[str, Any]], construct: Callable[[type, Dict[str, Any]], Any], name: str = 'all_children')
Bases:
beanmachine.ppl.compiler.rules.Rule
Apply a rule to all children or list members.
- always_succeeds() bool
- apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- combined_rule: beanmachine.ppl.compiler.rules.Rule
- class beanmachine.ppl.compiler.rules.AllListEditMembers(rule: beanmachine.ppl.compiler.rules.Rule, name: str = 'all_list_edit_members')
Bases:
beanmachine.ppl.compiler.rules.Rule
Rules which are intended to modify a parent list by adding or removing items return a ListEdit([…]) object, but in cases where a rule then recursese upon children – like top_down – we’ll potentially need to rewrite the elements in edit list. This combinator implements that.
- always_succeeds() bool
- apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- class beanmachine.ppl.compiler.rules.AllListMembers(rule: beanmachine.ppl.compiler.rules.Rule, name: str = 'all_list_members')
Bases:
beanmachine.ppl.compiler.rules.Rule
Apply a rule to all members. Succeeds if the rule succeeds for all members, and returns a list with the members replaced with the new values. Otherwise, fails.
- always_succeeds() bool
- apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- class beanmachine.ppl.compiler.rules.AllOf(rules: List[beanmachine.ppl.compiler.rules.Rule], name: str = 'all_of')
Bases:
beanmachine.ppl.compiler.rules.Rule
Takes a list of rules and composes together all of them. All must succeed, otherwise the rule fails.
- always_succeeds() bool
- apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- rules: List[beanmachine.ppl.compiler.rules.Rule]
- class beanmachine.ppl.compiler.rules.AllTermChildren(rule: beanmachine.ppl.compiler.rules.Rule, get_children: Callable[[Any], Dict[str, Any]], construct: Callable[[type, Dict[str, Any]], Any], name: str = 'all_children')
Bases:
beanmachine.ppl.compiler.rules.Rule
Apply a rule to all children. Succeeds if the rule succeeds for all children, and returns a constructed object with the children replaced with the new values. Otherwise, fails.
- always_succeeds() bool
- apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- construct: Callable[[type, Dict[str, Any]], Any]
- get_children: Callable[[Any], Dict[str, Any]]
- class beanmachine.ppl.compiler.rules.Check(rule: beanmachine.ppl.compiler.rules.Rule, name: str = 'check')
Bases:
beanmachine.ppl.compiler.rules.Rule
Apply the given rule; if it fails, fail. If it succeeds, the result is the original test value, not the transformed value. This is useful for scenarios where we wish to know if a particular thing is true of a node before we apply an expensive rule to it.
- always_succeeds() bool
- apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- class beanmachine.ppl.compiler.rules.Choose(condition: beanmachine.ppl.compiler.rules.Rule, consequence: beanmachine.ppl.compiler.rules.Rule, alternative: beanmachine.ppl.compiler.rules.Rule, name: str = 'choose')
Bases:
beanmachine.ppl.compiler.rules.Rule
Apply the condition rule to the test. If it succeeds, apply the rule in the consequence to its output. If it fails, apply the rule in the alternative to the test. That is, Choose(a, b, c)(test) has the semantics of if a(test) then b(a(test)) else c(test)
- alternative: beanmachine.ppl.compiler.rules.Rule
- always_succeeds() bool
- apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- condition: beanmachine.ppl.compiler.rules.Rule
- consequence: beanmachine.ppl.compiler.rules.Rule
- class beanmachine.ppl.compiler.rules.Compose(first: beanmachine.ppl.compiler.rules.Rule, second: beanmachine.ppl.compiler.rules.Rule, name: str = 'compose')
Bases:
beanmachine.ppl.compiler.rules.Rule
Apply the first rule to the test. If it succeeds, apply the second rule to its output. That is, Compose(a, b)(test) has the semantics of if a(test) then b(a(test)) else fail
- always_succeeds() bool
- apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- class beanmachine.ppl.compiler.rules.Fail(test: Optional[Any] = None)
Bases:
beanmachine.ppl.compiler.rules.RuleResult
- expect_success() Any
- is_fail() bool
- is_success() bool
- test: Any
- class beanmachine.ppl.compiler.rules.FirstMatch(rules: Iterable[beanmachine.ppl.compiler.rules.Rule], name: str = 'first_match')
Bases:
beanmachine.ppl.compiler.rules.Rule
Apply each rule to the test until one succeeds; if none succeed, then fail.
- always_succeeds() bool
- apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- rules: List[beanmachine.ppl.compiler.rules.Rule]
- class beanmachine.ppl.compiler.rules.IgnoreException(rule: beanmachine.ppl.compiler.rules.Rule, expected: List[type] = [<class 'Exception'>], name: str = 'handle')
Bases:
beanmachine.ppl.compiler.rules.Rule
Apply the given rule; if it throws an exception, the rule fails.
- always_succeeds() bool
- apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- expected: List[type]
- class beanmachine.ppl.compiler.rules.ListEdit(edits: List[Any])
Bases:
object
Consider a rule which descends through an AST looking for a particular statement to replace. If the rule replaces a particular statement with another statement, we can express that with a straightforward rule that succeeds and produces the new statement. But how can we represent rules that either delete a statement (that is, replace it with nothing) or replace it with more than one statement? To express this concept, a rule should succeed and return a ListEdit([s1, s2…]) where the list contains the replacements; if the list is empty then the element is deleted.
- edits: List[Any]
- class beanmachine.ppl.compiler.rules.OneChild(rule: beanmachine.ppl.compiler.rules.Rule, get_children: Callable[[Any], Dict[str, Any]], construct: Callable[[type, Dict[str, Any]], Any], name: str = 'one_child')
Bases:
beanmachine.ppl.compiler.rules.Rule
Apply a rule to all children until the first success. Succeeds if it finds one success and returns a constructed object with the child replaced with the new value. Otherwise, fails.
- always_succeeds() bool
- apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- construct: Callable[[type, Dict[str, Any]], Any]
- get_children: Callable[[Any], Dict[str, Any]]
- class beanmachine.ppl.compiler.rules.OneListMember(rule: beanmachine.ppl.compiler.rules.Rule, name: str = 'one_child')
Bases:
beanmachine.ppl.compiler.rules.Rule
Apply a rule to all members until the first success. Succeeds if it finds one success and returns a list with the child replaced with the new value. Otherwise, fails.
- always_succeeds() bool
- apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- class beanmachine.ppl.compiler.rules.OrElse(first: beanmachine.ppl.compiler.rules.Rule, second: beanmachine.ppl.compiler.rules.Rule, name: str = 'or_else')
Bases:
beanmachine.ppl.compiler.rules.Rule
Apply the first rule to the test. If it succeeds, use that result. If it fails, apply the second rule to the test and return that.
- always_succeeds() bool
- apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- class beanmachine.ppl.compiler.rules.PatternRule(pattern: Optional[Union[beanmachine.ppl.compiler.patterns.PatternBase, int, str, float, type, list]], projection: Callable[[Any], Any] = <function _identity>, name: str = 'pattern')
Bases:
beanmachine.ppl.compiler.rules.Rule
If the test value matches the pattern, then the test value is passed to the projection and the rule succeeds. Otherwise, the rule fails.
- always_succeeds() bool
- apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- pattern: Optional[Union[beanmachine.ppl.compiler.patterns.PatternBase, int, str, float, type, list]]
- projection: Callable[[Any], Any]
- class beanmachine.ppl.compiler.rules.Recursive(rule_maker: Callable[[], beanmachine.ppl.compiler.rules.Rule], name: str = 'recursive')
Bases:
beanmachine.ppl.compiler.rules.Rule
Delay construction of a rule until we need it, so as to avoid recursion.
- always_succeeds() bool
- apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- rule_maker: Callable[[], beanmachine.ppl.compiler.rules.Rule]
- class beanmachine.ppl.compiler.rules.Rule(name: str = '')
Bases:
abc.ABC
A rule represents a partial function that transforms a value.
- abstract always_succeeds() bool
- abstract apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- name: str
- class beanmachine.ppl.compiler.rules.RuleDomain(get_children: Callable[[Any], Dict[str, Any]], construct: Callable[[type, Dict[str, Any]], Any])
Bases:
object
- all_children(rule: beanmachine.ppl.compiler.rules.Rule, name: str = 'all_children') beanmachine.ppl.compiler.rules.Rule
- bottom_up(rule: beanmachine.ppl.compiler.rules.Rule, name: str = 'bottom_up') beanmachine.ppl.compiler.rules.Rule
The bottom-up combinator applies a rule to all leaves, then to the rewritten parent, and so on up to the root.
- construct: Callable[[type, Dict[str, Any]], Any]
- descend_until(test: beanmachine.ppl.compiler.rules.Rule, rule: beanmachine.ppl.compiler.rules.Rule, name: str = 'descend_until') beanmachine.ppl.compiler.rules.Rule
descend_until starts at the top of the tree and descends down it checking every node to see if “test” succeeds. If it does, it stops descending and runs “rule” on that node. It does this on every node that meets the test starting from the root.
- down_then_up(pre_rule: beanmachine.ppl.compiler.rules.Rule, post_rule: beanmachine.ppl.compiler.rules.Rule, name: str = 'down_then_up') beanmachine.ppl.compiler.rules.Rule
The down-then-up combinator is a combination of the bottom-up and top-down combinators; it applies the ‘pre’ rule in a top-down traversal and then the ‘post’ rule on the way back up.
- get_children: Callable[[Any], Dict[str, Any]]
- one_child(rule: beanmachine.ppl.compiler.rules.Rule, name: str = 'one_child') beanmachine.ppl.compiler.rules.Rule
- some_bottom_up(rule: beanmachine.ppl.compiler.rules.Rule, name: str = 'some_bottom_up') beanmachine.ppl.compiler.rules.Rule
The some-bottom-up combinator is like bottom_up, in that it applies a rule to every node in the tree starting from the leaves. However, bottom_up requires that the rule succeed for all nodes in the tree; some_bottom_up applies the rule to as many nodes in the tree as possible, leaves alone nodes for which it fails, and fails only if the rule applied to no node.
- some_children(rule: beanmachine.ppl.compiler.rules.Rule, name: str = 'some_children') beanmachine.ppl.compiler.rules.Rule
- some_top_down(rule: beanmachine.ppl.compiler.rules.Rule, name: str = 'some_top_down') beanmachine.ppl.compiler.rules.Rule
The some-top-down combinator is like top_down, in that it applies a rule to every node in the tree starting from the top. However, top_down requires that the rule succeed for all nodes in the tree; some_top_down applies the rule to as many nodes in the tree as possible, leaves alone nodes for which it fails (aside from possibly rewriting the children), and fails only if the rule applied to no node.
- specific_child(child: str, rule: beanmachine.ppl.compiler.rules.Rule, name: str = 'specific_child') beanmachine.ppl.compiler.rules.Rule
Apply a rule to a specific child. If it succeeds, replace the child with the new value; otherwise, fail. The child is required to exist.
- top_down(rule: beanmachine.ppl.compiler.rules.Rule, name: str = 'top_down') beanmachine.ppl.compiler.rules.Rule
The top-down combinator applies a rule to the root, then to the new root’s children, and so on down to the leaves. It succeeds iff the rule succeeds on every node.
- class beanmachine.ppl.compiler.rules.RuleResult(test: Any)
Bases:
abc.ABC
- abstract expect_success() Any
- abstract is_fail() bool
- abstract is_success() bool
- test: Any
- class beanmachine.ppl.compiler.rules.SomeChildren(rule: beanmachine.ppl.compiler.rules.Rule, get_children: Callable[[Any], Dict[str, Any]], construct: Callable[[type, Dict[str, Any]], Any], name: str = 'some_children')
Bases:
beanmachine.ppl.compiler.rules.Rule
Apply a rule to all children. Succeeds if the rule succeeds for one or more children, and returns a constructed object with the children replaced with the new values. Otherwise, fails.
- always_succeeds() bool
- apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- construct: Callable[[type, Dict[str, Any]], Any]
- get_children: Callable[[Any], Dict[str, Any]]
- class beanmachine.ppl.compiler.rules.SomeListMembers(rule: beanmachine.ppl.compiler.rules.Rule, name: str = 'some_list_members')
Bases:
beanmachine.ppl.compiler.rules.Rule
Apply a rule to all members. Succeeds if the rule succeeds for one or more members, and returns a list with the children replaced with the new values. Otherwise, fails.
- always_succeeds() bool
- apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- class beanmachine.ppl.compiler.rules.SomeOf(rules: List[beanmachine.ppl.compiler.rules.Rule], name: str = 'some_of')
Bases:
beanmachine.ppl.compiler.rules.Rule
Takes a list of rules and composes together as many of them as succeed. At least one must succeed, otherwise the rule fails.
- always_succeeds() bool
- apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- rules: List[beanmachine.ppl.compiler.rules.Rule]
- class beanmachine.ppl.compiler.rules.SpecificChild(child: str, rule: beanmachine.ppl.compiler.rules.Rule, get_children: Callable[[Any], Dict[str, Any]], construct: Callable[[type, Dict[str, Any]], Any], name: str = 'specific_child')
Bases:
beanmachine.ppl.compiler.rules.Rule
Apply a rule to a specific child. If it succeeds, replace the child with the new value; otherwise, fail. The child is required to exist.
- always_succeeds() bool
- apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- child: str
- construct: Callable[[type, Dict[str, Any]], Any]
- get_children: Callable[[Any], Dict[str, Any]]
- class beanmachine.ppl.compiler.rules.Success(test: Any, result: Any)
Bases:
beanmachine.ppl.compiler.rules.RuleResult
- expect_success() Any
- is_fail() bool
- is_success() bool
- result: Any
- class beanmachine.ppl.compiler.rules.Trace(rule: beanmachine.ppl.compiler.rules.Rule, logger: Callable[[beanmachine.ppl.compiler.rules.Rule, Any], None])
Bases:
beanmachine.ppl.compiler.rules.Rule
This combinator introduces a side effect to be executed every time the child rule is executed, and when it succeeds or fails. It is useful for debugging.
- always_succeeds() bool
- apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- logger: Callable[[beanmachine.ppl.compiler.rules.Rule, Any], None]
- class beanmachine.ppl.compiler.rules.TryMany(rule: beanmachine.ppl.compiler.rules.Rule, name: str = 'try_many')
Bases:
beanmachine.ppl.compiler.rules.Rule
Repeatedly apply a rule; the result is that of the last application that succeeded, or the original test if none succeeded. This rule always succeeds.
- always_succeeds() bool
- apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- class beanmachine.ppl.compiler.rules.TryOnce(rule: beanmachine.ppl.compiler.rules.Rule, name: str = 'try_once')
Bases:
beanmachine.ppl.compiler.rules.Rule
Apply the rule to the test. If it succeeds, use that result. If it fails, use the test as the result and succeed. This rule always succeeds.
- always_succeeds() bool
- apply(test: Any) beanmachine.ppl.compiler.rules.RuleResult
- beanmachine.ppl.compiler.rules.always_replace(value: Any, name: str = 'always_replace') beanmachine.ppl.compiler.rules.Rule
always_replace(value) produces a rule that replaces anything with the given value. It always succeeds.
- beanmachine.ppl.compiler.rules.at_least_once(rule: beanmachine.ppl.compiler.rules.Rule) beanmachine.ppl.compiler.rules.Rule
Try a rule once; if it fails, fail. If it succeeds, try it again as many times as it keeps succeeding.
- beanmachine.ppl.compiler.rules.either_or_both(first: beanmachine.ppl.compiler.rules.Rule, second: beanmachine.ppl.compiler.rules.Rule, name: str = 'either_or_both') beanmachine.ppl.compiler.rules.Rule
Do the first rule; if it succeeds, try doing the second rule, but do not worry if it fails. If the first rule fails, do the second rule. The net effect is, either first, or second, or first-then-second happens, or both fail.
- beanmachine.ppl.compiler.rules.if_then(condition: beanmachine.ppl.compiler.rules.Rule, consequence: beanmachine.ppl.compiler.rules.Rule, alternative: beanmachine.ppl.compiler.rules.Rule = <beanmachine.ppl.compiler.rules.PatternRule object>) beanmachine.ppl.compiler.rules.Rule
Apply the condition rule, then apply the original test to either the consequence or the alternative, depending on whether the condition succeeded or failed. Note that this is different than Choose. Choose applies the condition to the result of the condition, not to the original test.
- beanmachine.ppl.compiler.rules.ignore_div_zero(rule: beanmachine.ppl.compiler.rules.Rule) beanmachine.ppl.compiler.rules.Rule
- beanmachine.ppl.compiler.rules.ignore_runtime_error(rule: beanmachine.ppl.compiler.rules.Rule) beanmachine.ppl.compiler.rules.Rule
- beanmachine.ppl.compiler.rules.ignore_value_error(rule: beanmachine.ppl.compiler.rules.Rule) beanmachine.ppl.compiler.rules.Rule
- beanmachine.ppl.compiler.rules.list_member_children(rule: beanmachine.ppl.compiler.rules.Rule) beanmachine.ppl.compiler.rules.Rule
- beanmachine.ppl.compiler.rules.make_logger(log: List[str]) Callable[[beanmachine.ppl.compiler.rules.Rule], beanmachine.ppl.compiler.rules.Rule]
- beanmachine.ppl.compiler.rules.pattern_rules(pairs: List[Tuple[Optional[Union[beanmachine.ppl.compiler.patterns.PatternBase, int, str, float, type, list]], Callable[[Any], Any]]], name: str = 'pattern_rules') beanmachine.ppl.compiler.rules.Rule
Constructs a rule from a sequence of pairs of patterns and projections. Patterns are checked in order, and the first one that matches is used for the projection; if none match then the rule fails.
- beanmachine.ppl.compiler.rules.projection_rule(projection: Callable[[Any], Any], name: str = 'projection') beanmachine.ppl.compiler.rules.Rule