[pypy-svn] pypy default: implement non-greedy partial matching with the "..." operator

antocuni commits-noreply at bitbucket.org
Thu Feb 24 18:25:48 CET 2011


Author: Antonio Cuni <anto.cuni at gmail.com>
Branch: 
Changeset: r42268:41520d1f66c3
Date: 2011-02-24 17:56 +0100
http://bitbucket.org/pypy/pypy/changeset/41520d1f66c3/

Log:	implement non-greedy partial matching with the "..." operator

diff --git a/pypy/module/pypyjit/test_pypy_c/model.py b/pypy/module/pypyjit/test_pypy_c/model.py
--- a/pypy/module/pypyjit/test_pypy_c/model.py
+++ b/pypy/module/pypyjit/test_pypy_c/model.py
@@ -239,25 +239,51 @@
         for arg, exp_arg in zip(op.args, exp_args):
             self._assert(self.match_var(arg, exp_arg), "variable mismatch")
 
-    def _next_op(self, iter_ops, message, assert_raises=False):
+    def _next_op(self, iter_ops, assert_raises=False):
         try:
             op = iter_ops.next()
         except StopIteration:
-            self._assert(assert_raises, message)
+            self._assert(assert_raises, "not enough operations")
             return
         else:
-            self._assert(not assert_raises, message)
+            self._assert(not assert_raises, "operation list too long")
             return op
 
+    def match_until(self, until_op, iter_ops):
+        while True:
+            op = self._next_op(iter_ops)
+            try:
+                # try to match the op, but be sure not to modify the
+                # alpha-renaming map in case the match does not work
+                alpha_map = self.alpha_map.copy()
+                self.match_op(op, until_op)
+            except InvalidMatch:
+                # it did not match: rollback the alpha_map, and just skip this
+                # operation
+                self.alpha_map = alpha_map
+            else:
+                # it matched! The '...' operator ends here
+                return op
+
     def match_loop(self, expected_ops):
+        """
+        A note about partial matching: the '...' operator is non-greedy,
+        i.e. it matches all the operations until it finds one that matches
+        what is after the '...'
+        """
         iter_exp_ops = iter(expected_ops)
         iter_ops = iter(self.ops)
         for exp_op in iter_exp_ops:
-            op = self._next_op(iter_ops, "not enough operations")
+            if exp_op == '...':
+                # loop until we find an operation which matches
+                exp_op = iter_exp_ops.next()
+                op = self.match_until(exp_op, iter_ops)
+            else:
+                op = self._next_op(iter_ops)
             self.match_op(op, exp_op)
         #
         # make sure we exhausted iter_ops
-        self._next_op(iter_ops, "operation list too long", assert_raises=True)
+        self._next_op(iter_ops, assert_raises=True)
 
     def match(self, expected_src):
         expected_src = self.preprocess_expected_src(expected_src)

diff --git a/pypy/module/pypyjit/test_pypy_c/test_model.py b/pypy/module/pypyjit/test_pypy_c/test_model.py
--- a/pypy/module/pypyjit/test_pypy_c/test_model.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_model.py
@@ -149,19 +149,19 @@
 
 
     def test_partial_match(self):
-        py.test.skip('in-progress')
         loop = """
             [i0]
             i1 = int_add(i0, 1)
             i2 = int_sub(i1, 10)
             i3 = int_floordiv(i2, 100)
             i4 = int_mul(i1, 1000)
-            jump(i3)
+            jump(i4)
         """
         expected = """
             i1 = int_add(0, 1)
             ...
             i4 = int_mul(i1, 1000)
+            jump(i4)
         """
         assert self.match(loop, expected)
 


More information about the Pypy-commit mailing list