[pypy-svn] r44087 - in pypy/branch/prolog-bytecode/pypy/lang/prolog: builtin interpreter interpreter/test

cfbolz at codespeak.net cfbolz at codespeak.net
Thu Jun 7 13:54:45 CEST 2007


Author: cfbolz
Date: Thu Jun  7 13:54:44 2007
New Revision: 44087

Modified:
   pypy/branch/prolog-bytecode/pypy/lang/prolog/builtin/control.py
   pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/compiler.py
   pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/interpreter.py
   pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/prologopcode.py
   pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/test/test_compiler.py
Log:
mostly implement the cut - corner case with call(!) seems not to work yet.


Modified: pypy/branch/prolog-bytecode/pypy/lang/prolog/builtin/control.py
==============================================================================
--- pypy/branch/prolog-bytecode/pypy/lang/prolog/builtin/control.py	(original)
+++ pypy/branch/prolog-bytecode/pypy/lang/prolog/builtin/control.py	Thu Jun  7 13:54:44 2007
@@ -23,7 +23,6 @@
 expose_builtin(impl_repeat, "repeat", unwrap_spec=[], handles_continuation=True)
 
 def impl_cut(engine, continuation):
-    py.test.skip("the cut is not working right now")
     raise error.CutException(continuation)
 expose_builtin(impl_cut, "!", unwrap_spec=[],
                handles_continuation=True)

Modified: pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/compiler.py
==============================================================================
--- pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/compiler.py	(original)
+++ pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/compiler.py	Thu Jun  7 13:54:44 2007
@@ -44,6 +44,7 @@
         self.functionmap = {}
         self.maxlocalvar = 0
         self.varmap = {}
+        self.can_contain_cut = False
         result = Code()
         self.compile_termbuilding(head)
         result.opcode_head = self.getbytecode()
@@ -54,6 +55,7 @@
         result.term_info = self.term_info
         result.functions = self.functions
         result.maxlocalvar = len(self.varmap)
+        result.can_contain_cut = self.can_contain_cut
         return result
 
     def compile_termbuilding(self, term):
@@ -75,6 +77,7 @@
 
         body = body.dereference(self.engine.heap)
         if isinstance(body, Var):
+            self.can_contain_cut = True
             self.compile_termbuilding(body)
             self.emit_opcode(opcodedesc.DYNAMIC_CALL)
             return
@@ -90,6 +93,9 @@
             self.emit_opcode(opcodedesc.UNIFY)
         elif body.signature == "call/1": #XXX interactions with cuts correct?
             self.compile_body(body.args[0])
+        elif body.signature == "!/0":
+            self.can_contain_cut = True
+            self.emit_opcode(opcodedesc.CUT)
         elif body.signature in builtins_index:
             i = builtins_index[body.signature]
             self.compile_termbuilding(body)

Modified: pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/interpreter.py
==============================================================================
--- pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/interpreter.py	(original)
+++ pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/interpreter.py	Thu Jun  7 13:54:44 2007
@@ -1,7 +1,8 @@
 from pypy.lang.prolog.interpreter import helper
 from pypy.lang.prolog.interpreter import error
 from pypy.lang.prolog.interpreter.term import Term, Atom, Var, Callable
-from pypy.lang.prolog.interpreter.engine import Continuation
+from pypy.lang.prolog.interpreter.engine import Continuation, \
+    LimitedScopeContinuation
 from pypy.lang.prolog.interpreter.prologopcode import unrolling_opcode_descs, \
     HAVE_ARGUMENT
 
@@ -72,11 +73,12 @@
         self.stack = None
 
     def run_directly(self, continuation, choice_point=True):
-        cont = self.run(self.code.opcode, 0, continuation)
+        if self.code.opcode:
+            continuation = self.run(self.code.opcode, 0, continuation)
         if not choice_point:
-            return cont
-        while cont is not None:
-            cont = cont._call(self.engine)
+            return continuation
+        while continuation is not None:
+            continuation = continuation._call(self.engine)
 
     def run(self, bytecode, pc, continuation):
         stack = []
@@ -133,7 +135,7 @@
             result = self.localvarcache[number] = self.engine.heap.newvar()
         stack.append(result)
 
-    def MAKETERM(self, stack, number, *ignored):
+    def MAKETERM(self, stack, number):
         name, numargs, signature = self.code.term_info[number]
         args = [None] * numargs
         i = numargs - 1
@@ -142,17 +144,20 @@
             i -= 1
         stack.append(Term(name, args, signature))
 
-    def CALL_BUILTIN(self, stack, number, continuation, *ignored):
+    def CALL_BUILTIN(self, stack, number, continuation):
         from pypy.lang.prolog.builtin import builtins_list
         return builtins_list[number][1].call(self.engine, stack.pop(),
                                              continuation)
+
+    def CUT(self, stack, continuation):
+        raise error.CutException(continuation)
     
     def STATIC_CALL(self, stack, number, continuation):
         query = stack.pop()
         function = self.code.functions[number]
         return self.user_call(function, query, continuation)
 
-    def DYNAMIC_CALL(self, stack, continuation, *ignored):
+    def DYNAMIC_CALL(self, stack, continuation):
         query = stack.pop()
         assert isinstance(query, Callable)
         signature = query.signature
@@ -163,6 +168,12 @@
         function = self.engine.lookup_userfunction(signature)
         return self.user_call(function, query, continuation)
 
+    def CLEAR_LOCAL(self, stack, number):
+        self.localvarcache[number] = None
+
+    def UNIFY(self, stack):
+        stack.pop().unify(stack.pop(), self.engine.heap)
+
     def user_call(self, function, query, continuation):
         rulechain = function.rulechain
         if rulechain is None:
@@ -171,20 +182,27 @@
         oldstate = self.engine.heap.branch()
         while rulechain is not None:
             rule = rulechain.rule
-            try:
-                frame = rule.make_frame(query)
-                frame.run_directly(continuation)
-                return
-            except error.UnificationFailed:
-                self.engine.heap.revert(oldstate)
+            if rule.code.can_contain_cut:
+                continuation = LimitedScopeContinuation(continuation)
+                try:
+                    frame = rule.make_frame(query)
+                    frame.run_directly(continuation)
+                    return
+                except error.UnificationFailed:
+                    self.engine.heap.revert(oldstate)
+                except error.CutException, e:
+                    if continuation.scope_active:
+                        return self.engine.continue_after_cut(e.continuation,
+                                                              continuation)
+                    raise
+            else:
+                try:
+                    frame = rule.make_frame(query)
+                    frame.run_directly(continuation)
+                    return
+                except error.UnificationFailed:
+                    self.engine.heap.revert(oldstate)
             rule = rulechain.rule
             rulechain = rulechain.next
         raise error.UnificationFailed
 
-    def CLEAR_LOCAL(self, stack, number, *ignored):
-        self.localvarcache[number] = None
-
-    def UNIFY(self, stack, *ignored):
-        stack.pop().unify(stack.pop(), self.engine.heap)
-
-

Modified: pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/prologopcode.py
==============================================================================
--- pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/prologopcode.py	(original)
+++ pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/prologopcode.py	Thu Jun  7 13:54:44 2007
@@ -37,6 +37,7 @@
 def_op("CONTINUE", 'O')
 def_op("DYNAMIC_CALL", 'D', True)
 argument_op("STATIC_CALL", 's', True)
+def_op("CUT", 'C', True)
 
 class OpcodeDesc(object):
     def __init__(self, name, index):

Modified: pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/test/test_compiler.py
==============================================================================
--- pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/test/test_compiler.py	(original)
+++ pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/test/test_compiler.py	Thu Jun  7 13:54:44 2007
@@ -9,6 +9,7 @@
     assert not code.opcode
     assert code.opcode_head == "c\x00\x00"
     assert code.constants == [foo]
+    assert not code.can_contain_cut
 
 def test_simple_withbody():
     e = get_engine("")
@@ -18,6 +19,7 @@
     assert code.opcode_head == "c\x00\x00"
     assert code.opcode == "c\x00\x01s\x00\x00"
     assert code.constants == [foo, bar]
+    assert not code.can_contain_cut
 
 def test_simple_withargs():
     e = get_engine("")
@@ -27,6 +29,7 @@
     assert code.opcode == "l\x00\x00t\x00\x01s\x00\x00"
     assert code.constants == []
     assert code.term_info == [("f", 1, "f/1"), ("g", 1, "g/1")]
+    assert not code.can_contain_cut
 
 def test_simple_and():
     e = get_engine("")
@@ -36,6 +39,7 @@
     assert code.opcode == "l\x00\x00t\x00\x01s\x00\x00l\x00\x01t\x00\x02s\x00\x01"
     assert code.constants == []
     assert code.term_info == [("f", 2, "f/2"), ("g", 1, "g/1"), ("h", 1, "h/1")]
+    assert not code.can_contain_cut
 
 def test_nested_term():
     e = get_engine("")
@@ -44,6 +48,7 @@
     assert code.opcode_head == "l\x00\x00t\x00\x00c\x00\x00t\x00\x01"
     assert code.term_info == [("g", 1, "g/1"), ("f", 2, "f/2")]
     assert code.constants == [Atom("a")]
+    assert not code.can_contain_cut
 
 def test_unify():
     e = get_engine("")
@@ -53,6 +58,7 @@
     assert code.opcode == "l\x00\x00t\x00\x01l\x00\x01t\x00\x01U"
     assert code.constants == []
     assert code.term_info == [("f", 2, "f/2"), ("g", 1, "g/1")]
+    assert not code.can_contain_cut
 
 def test_dynamic_call():
     e = get_engine("")
@@ -61,5 +67,15 @@
     assert code.opcode_head == "l\x00\x00l\x00\x01t\x00\x00"
     assert code.opcode == "l\x00\x00Dl\x00\x01D"
     assert code.term_info == [("f", 2, "f/2")]
+    assert code.can_contain_cut
+
+def test_cut():
+    e = get_engine("")
+    head, body = get_query_and_vars("f(X, Y) :- !.")[0].args
+    code = compile(head, body, e)
+    assert code.opcode_head == "l\x00\x00l\x00\x01t\x00\x00"
+    assert code.opcode == "C"
+    assert code.term_info == [("f", 2, "f/2")]
+    assert code.can_contain_cut
 
 



More information about the Pypy-commit mailing list