Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing the code generator #50

Merged
merged 4 commits into from
Mar 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 23 additions & 23 deletions matchpy/matching/code_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -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']
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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))
Expand Down
22 changes: 18 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@ 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, 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)
)
Expand All @@ -29,7 +32,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

Expand All @@ -46,8 +49,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)
Expand Down Expand Up @@ -93,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")
17 changes: 17 additions & 0 deletions tests/test_matching.py
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,23 @@ 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_many):
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)
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_many(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]
Expand Down