summaryrefslogtreecommitdiff
path: root/tactic_utils.py
diff options
context:
space:
mode:
authorMatthew Sotoudeh <matthewsot@outlook.com>2020-11-10 14:06:35 -0800
committerMatthew Sotoudeh <matthewsot@outlook.com>2020-11-10 14:06:35 -0800
commit904094281b062aff3445ca41fec57e4cfd0f563d (patch)
treeed49271ab1ff8448a433921533159f6a8e450c8b /tactic_utils.py
parentdb99b3af36fa4687c734e1c74d83157d2f10c9ed (diff)
Initial code release
Diffstat (limited to 'tactic_utils.py')
-rw-r--r--tactic_utils.py76
1 files changed, 76 insertions, 0 deletions
diff --git a/tactic_utils.py b/tactic_utils.py
new file mode 100644
index 0000000..82244ba
--- /dev/null
+++ b/tactic_utils.py
@@ -0,0 +1,76 @@
+"""Collection of macros for writing Tactics.
+
+Matthew considers this to be written "in the DSL," although it's somewhat on
+the border.
+"""
+from runtime.matcher import Matcher, OneOffMatcher
+
+def SearchRules(rt, search_term):
+ """Returns all rules with @search_term in their name.
+
+ Used, for example, to quickly mark all successor pairs in a structure
+ (since currently "X is A, Y is B -> Successor(X, Y)" is a separate rule for
+ each A, B).
+ """
+ return [rule.name for rule in rt.rules if search_term in rule.name]
+
+def Fix(function, *args, **kwargs):
+ """Applies @function repeatedly until it returns False.
+
+ Many tactic functions return True if they made a change. This method allows
+ you to apply those tactics until fixedpoint is reached.
+ """
+ while function(*args, **kwargs):
+ pass
+
+def ApplyRulesMatching(rt, search_term, partial=None):
+ """Calls RuleFixedpoint for every rule containing @search_term.
+
+ Note that this is *all* it does --- it does not, e.g., ever repeat the 1st
+ rule after applying the 3rd. If you want the fixedpoint for all of the
+ rules together, you need to wrap this call in a Fix(...).
+ """
+ rules = SearchRules(rt, search_term)
+ did_anything = False
+ for rule in rules:
+ did_anything = RuleFixedpoint(rt, rule, partial) or did_anything
+ return did_anything
+
+MATCHERS = dict()
+def GetMatcher(rt, rule, partial, one_off=False):
+ """Returns a Matcher keeping track of applications to @rule."""
+ rule = rt.rules_by_name[rule]
+ if one_off:
+ return OneOffMatcher(rt, rule, partial)
+ key = (id(rt), rule, tuple(sorted(partial.items())))
+ if key not in MATCHERS:
+ MATCHERS[key] = Matcher(rt, rule, partial)
+ return MATCHERS[key]
+
+def RuleFixedpoint(rt, rule, partial=None):
+ """Given a rule, applies it repeatedly until fixedpoint is reached.
+ """
+ matcher = GetMatcher(rt, rule, partial or dict({}))
+
+ did_anything = False
+ while True:
+ matcher.sync()
+ # NOTE: for correctness, rt.matcher_propose assumes you only ever use
+ # exactly one of the things it yields.
+ try:
+ _ = next(rt.matcher_propose(matcher))
+ except StopIteration:
+ break
+ did_anything = True
+ return did_anything
+
+def RuleAny(rt, rule, partial, one_off=True):
+ """True iff @rule has any matches extending @partial in the structure."""
+ matcher = GetMatcher(rt, rule, partial, one_off=one_off)
+ matcher.sync()
+ try:
+ _ = next(matcher.assignments())
+ return True
+ except StopIteration:
+ pass
+ return False
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback