From 0b99005561b518cf224f5d2511d728bd713af5c9 Mon Sep 17 00:00:00 2001 From: Francesco Bonazzi Date: Sun, 16 Dec 2018 23:44:39 +0100 Subject: [PATCH 1/3] Fixing the code generator --- matchpy/matching/code_generation.py | 46 ++++++++++++++--------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/matchpy/matching/code_generation.py b/matchpy/matching/code_generation.py index 9d31fb6..baf4be8 100644 --- a/matchpy/matching/code_generation.py +++ b/matchpy/matching/code_generation.py @@ -20,7 +20,7 @@ class CodeGenerator: def __init__(self, matcher): self._matcher = matcher self._var_number = 0 - self._indentation = '\t' + self._indentation = ' ' self._level = 0 self._code = '' self._subjects = ['subjects'] @@ -82,28 +82,28 @@ def generate_state_code(self, state): self._global_code.append( ''' class CommutativeMatcher{0}(CommutativeMatcher): -\t_instance = None -\tpatterns = {1} -\tsubjects = {2} -\tsubjects_by_id = {7} -\tbipartite = BipartiteGraph() -\tassociative = {3} -\tmax_optional_count = {4} -\tanonymous_patterns = {5} - -\tdef __init__(self): -\t\tself.add_subject(None) - -\t@staticmethod -\tdef get(): -\t\tif CommutativeMatcher{0}._instance is None: -\t\t\tCommutativeMatcher{0}._instance = CommutativeMatcher{0}() -\t\treturn CommutativeMatcher{0}._instance - -\t@staticmethod +{8}_instance = None +{8}patterns = {1} +{8}subjects = {2} +{8}subjects_by_id = {7} +{8}bipartite = BipartiteGraph() +{8}associative = {3} +{8}max_optional_count = {4} +{8}anonymous_patterns = {5} + +{8}def __init__(self): +{8}{8}self.add_subject(None) + +{8}@staticmethod +{8}def get(): +{8}{8}if CommutativeMatcher{0}._instance is None: +{8}{8}{8}CommutativeMatcher{0}._instance = CommutativeMatcher{0}() +{8}{8}return CommutativeMatcher{0}._instance + +{8}@staticmethod {6}'''.strip().format( state.number, patterns, subjects, associative, max_optional_count, anonymous_patterns, code, - subjects_by_id + subjects_by_id, self._indentation ) ) self.add_line('matcher = CommutativeMatcher{}.get()'.format(state.number)) @@ -451,9 +451,9 @@ def generate_constraints(self, constraints, transitions): checked_patterns = self._patterns & patterns checked_transitions = [t for t in transitions if t.patterns & checked_patterns] if checked_patterns and checked_transitions: - cvars = ' and '.join('{!r} in subst{}'.format(v, self._substs) for v in constraint.variables) + cvars = ' or '.join('{!r} not in subst{}'.format(v, self._substs) for v in constraint.variables) if cvars: - cvars += ' and ' + cvars += ' or ' cexpr, call = self.constraint_repr(constraint) if call: self.add_line('if {}{}(subst{}):'.format(cvars, cexpr, self._substs)) From a7821d11b3b6f3d37eabf3c9d80344b9479bbd58 Mon Sep 17 00:00:00 2001 From: Francesco Bonazzi Date: Fri, 22 Mar 2019 12:28:10 +0100 Subject: [PATCH 2/3] add tests --- tests/conftest.py | 9 +++++---- tests/test_matching.py | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index c1a8c6d..db63736 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -19,8 +19,9 @@ def pytest_generate_tests(metafunc): metafunc.parametrize('match_syntactic', ['one-to-one', 'many-to-one', 'syntactic', 'generated'], indirect=True) -def match_many_to_one(expression, pattern): +def match_many_to_one(expression, *patterns): try: + pattern = patterns[0] commutative = next( p for p in preorder_iter(pattern.expression) if isinstance(p, CommutativeOperation) ) @@ -29,7 +30,7 @@ def match_many_to_one(expression, pattern): pass else: pytest.xfail('Matcher does not support fixed wildcards with length != 1 in commutative operations') - matcher = ManyToOneMatcher(pattern) + matcher = ManyToOneMatcher(*patterns) for _, substitution in matcher.match(expression): yield substitution @@ -46,8 +47,8 @@ def match_many_to_one(expression, pattern): '''.strip() -def match_generated(expression, pattern): - matcher = ManyToOneMatcher(pattern) +def match_generated(expression, *patterns): + matcher = ManyToOneMatcher(*patterns) generator = CodeGenerator(matcher) gc, code = generator.generate_code() code = GENERATED_TEMPLATE.format(gc, code) diff --git a/tests/test_matching.py b/tests/test_matching.py index 285525c..8415c1e 100644 --- a/tests/test_matching.py +++ b/tests/test_matching.py @@ -815,6 +815,27 @@ def test_selective_constraint(self, match): assert {'x': Symbol('aa')} in result assert {'x': Symbol('bb')} in result + def test_double_custom_constraint(self, match): + constraint1 = CustomConstraint(lambda x, y: (x > 0) and (y > 0)) + constraint2 = CustomConstraint(lambda x, y: (x > 0) or (y > 0)) + + pattern1 = Pattern(f(x_, a, y_), constraint1) + pattern2 = Pattern(f(x_, b, y_), constraint2) + + subject1 = f(3, a, 4) + try: + result = list(match(subject1, pattern1, pattern2)) + except TypeError: + # Some tests do not support multiple patterns, skip: + return + assert len(result) == 1 + assert {'x': 3, 'y': 4} in result + + subject2 = f(3, b, 4) + result = list(match(subject2, pattern1, pattern2)) + assert len(result) == 1 + assert {'x': 3, 'y': 4} in result + def func_wrap_strategy(args, func): min_size = func.arity[0] From 8cdfa44b2b4756528d5114b1b69cc8aecbdff395 Mon Sep 17 00:00:00 2001 From: Francesco Bonazzi Date: Sat, 23 Mar 2019 21:24:43 +0100 Subject: [PATCH 3/3] new test fixture match_many --- tests/conftest.py | 13 +++++++++++++ tests/test_matching.py | 10 +++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index db63736..1704264 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -17,6 +17,8 @@ def pytest_generate_tests(metafunc): metafunc.parametrize('match', ['one-to-one', 'many-to-one', 'generated'], indirect=True) if 'match_syntactic' in metafunc.fixturenames: metafunc.parametrize('match_syntactic', ['one-to-one', 'many-to-one', 'syntactic', 'generated'], indirect=True) + if 'match_many' in metafunc.fixturenames: + metafunc.parametrize('match_many', ['many-to-one', 'generated'], indirect=True) def match_many_to_one(expression, *patterns): @@ -94,3 +96,14 @@ def match_syntactic(request): return match_generated else: raise ValueError("Invalid internal test config") + + +@pytest.fixture +def match_many(request): + pytest.matcher = request.param + if request.param == 'many-to-one': + return match_many_to_one + elif request.param == 'generated': + return match_generated + else: + raise ValueError("Invalid internal test config") diff --git a/tests/test_matching.py b/tests/test_matching.py index 8415c1e..7d3733a 100644 --- a/tests/test_matching.py +++ b/tests/test_matching.py @@ -815,7 +815,7 @@ def test_selective_constraint(self, match): assert {'x': Symbol('aa')} in result assert {'x': Symbol('bb')} in result - def test_double_custom_constraint(self, match): + def test_double_custom_constraint(self, match_many): constraint1 = CustomConstraint(lambda x, y: (x > 0) and (y > 0)) constraint2 = CustomConstraint(lambda x, y: (x > 0) or (y > 0)) @@ -823,16 +823,12 @@ def test_double_custom_constraint(self, match): pattern2 = Pattern(f(x_, b, y_), constraint2) subject1 = f(3, a, 4) - try: - result = list(match(subject1, pattern1, pattern2)) - except TypeError: - # Some tests do not support multiple patterns, skip: - return + result = list(match_many(subject1, pattern1, pattern2)) assert len(result) == 1 assert {'x': 3, 'y': 4} in result subject2 = f(3, b, 4) - result = list(match(subject2, pattern1, pattern2)) + result = list(match_many(subject2, pattern1, pattern2)) assert len(result) == 1 assert {'x': 3, 'y': 4} in result