[pypy-svn] r44073 - in pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter: . test
cfbolz at codespeak.net
cfbolz at codespeak.net
Thu Jun 7 10:33:48 CEST 2007
Author: cfbolz
Date: Thu Jun 7 10:33:47 2007
New Revision: 44073
Modified:
pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/compiler.py
pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/engine.py
pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/interpreter.py
pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/term.py
pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/test/test_compiler.py
pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/test/test_engine.py
pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/test/test_unification.py
pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/test/tool.py
Log:
start rewriting things to use the bytecode interpreter. lots of failing tests
right now, but slowly getting there.
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 10:33:47 2007
@@ -1,10 +1,11 @@
-from pypy.lang.prolog.interpreter.term import NonVar, Term, Var
+from pypy.lang.prolog.interpreter.term import NonVar, Term, Var, Atom
from pypy.lang.prolog.interpreter.engine import Continuation
from pypy.lang.prolog.interpreter import helper, error
from pypy.lang.prolog.interpreter.prologopcode import opcodedesc
from pypy.rlib.objectmodel import we_are_translated
from pypy.rlib.jit import hint, we_are_jitted
+queryatom = Atom.newatom("<dummy>")
class Code(object):
_immutable_ = True
@@ -20,9 +21,15 @@
comp = Compiler(engine)
return comp.compile(head, body)
+def compile_query(body, engine):
+ comp = Compiler(engine, True)
+ return comp.compile(queryatom, body)
+
+
class Compiler(object):
- def __init__(self, engine):
+ def __init__(self, engine, query=False):
self.engine = engine
+ self.query = query
def compile(self, head, body):
self.term_info = [] # tuples of (functor, numargs, signature)
@@ -34,7 +41,6 @@
self.varmap = {}
result = Code()
self.compile_termbuilding(head)
- self.emit_opcode(opcodedesc.UNIFY)
result.opcode_head = self.getbytecode()
if body is not None:
self.compile_body(body)
@@ -49,8 +55,12 @@
num = self.getconstnum(term)
self.emit_opcode(opcodedesc.PUTCONSTANT, num)
elif isinstance(term, Var):
- num = self.getvarnum(term)
- self.emit_opcode(opcodedesc.PUTLOCALVAR, num)
+ if self.query:
+ num = self.getconstnum(term)
+ self.emit_opcode(opcodedesc.PUTCONSTANT, num)
+ else:
+ num = self.getvarnum(term)
+ self.emit_opcode(opcodedesc.PUTLOCALVAR, num)
else:
assert isinstance(term, Term)
for arg in term.args:
Modified: pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/engine.py
==============================================================================
--- pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/engine.py (original)
+++ pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/engine.py Thu Jun 7 10:33:47 2007
@@ -1,7 +1,8 @@
-from pypy.lang.prolog.interpreter.term import Var, Term, Rule, Atom, debug_print, \
+import py
+from pypy.lang.prolog.interpreter.term import Var, Term, Atom, debug_print, \
Callable
-from pypy.lang.prolog.interpreter.error import UnificationFailed, FunctionNotFound, \
- CutException
+from pypy.lang.prolog.interpreter.error import UnificationFailed, \
+ FunctionNotFound, CutException
from pypy.lang.prolog.interpreter import error
from pypy.rlib.jit import hint, we_are_jitted, _is_early_constant, purefunction
from pypy.rlib.objectmodel import specialize
@@ -19,6 +20,7 @@
class Continuation(object):
def call(self, engine, choice_point=True):
+ py.test.skip("can't do a call like this right now")
if choice_point:
return engine.main_loop(CONTINUATION, None, self, None)
return (CONTINUATION, None, self, None)
@@ -140,6 +142,7 @@
def add_rule(self, rule, end=True):
from pypy.lang.prolog import builtin
+ from pypy.lang.prolog.interpreter.interpreter import Rule
if DEBUG:
debug_print("add_rule", rule)
if isinstance(rule, Term):
@@ -147,13 +150,12 @@
rule = Rule(rule.args[0], rule.args[1], self)
else:
rule = Rule(rule, None, self)
- signature = rule.signature
elif isinstance(rule, Atom):
rule = Rule(rule, None, self)
- signature = rule.signature
else:
error.throw_type_error("callable", rule)
assert 0, "unreachable" # make annotator happy
+ signature = rule.signature
if signature in builtin.builtins:
error.throw_permission_error(
"modify", "static_procedure", rule.head.get_prolog_signature())
@@ -164,10 +166,15 @@
self.signature2function[signature] = Function(rule)
def run(self, query, continuation=DONOTHING):
+ from pypy.lang.prolog.interpreter.interpreter import Query
if not isinstance(query, Callable):
error.throw_type_error("callable", query)
+ rule = Query(query, self)
+ frame = rule.make_frame()
try:
- return self.call(query, continuation, choice_point=True)
+ where, _, cont, _ = frame.run_directly(continuation)
+ while where == CONTINUATION:
+ where, _, cont, _ = cont._call(self)
except CutException, e:
return self.continue_after_cut(e.continuation)
@@ -186,12 +193,14 @@
trees = parse_file(s, self.parser, Engine._build_and_run, self)
def call(self, query, continuation=DONOTHING, choice_point=True):
+ py.test.skip("can't do a call like this right now")
assert isinstance(query, Callable)
if not choice_point:
return (CALL, query, continuation, None)
return self.main_loop(CALL, query, continuation)
def _call(self, query, continuation):
+ py.test.skip("can't do a call like this right now")
signature = query.signature
from pypy.lang.prolog.builtin import builtins
builtins = hint(builtins, deepfreeze=True)
@@ -201,41 +210,6 @@
return builtin.call(self, query, continuation)
return self.user_call(query, continuation, choice_point=False)
- def _opaque_call(self, query, continuation):
- from pypy.lang.prolog.builtin import builtins
- signature = query.signature
- builtin = builtins.get(signature, None)
- if builtin is not None:
- return builtin.call(self, query, continuation)
- # do a real call
- return self.user_call(query, continuation, choice_point=False)
-
- def main_loop(self, where, query, continuation, rule=None):
- next = (DONE, None, None, None)
- hint(where, concrete=True)
- hint(rule, concrete=True)
- while 1:
- if where == DONE:
- return next
- next = self.dispatch_bytecode(where, query, continuation, rule)
- where, query, continuation, rule = next
- where = hint(where, promote=True)
-
- def dispatch_bytecode(self, where, query, continuation, rule):
- if where == CALL:
- next = self._call(query, continuation)
- elif where == TRY_RULE:
- rule = hint(rule, promote=True)
- next = self._try_rule(rule, query, continuation)
- elif where == USER_CALL:
- next = self._user_call(query, continuation)
- elif where == CONTINUATION:
- hint(continuation.__class__, promote=True)
- next = continuation._call(self)
- else:
- raise Exception("unknown bytecode")
- return next
-
@purefunction
def _jit_lookup(self, signature):
signature2function = self.signature2function
@@ -244,116 +218,6 @@
signature2function[signature] = function = Function()
return function
- def user_call(self, query, continuation, choice_point=True):
- if not choice_point:
- return (USER_CALL, query, continuation, None)
- return self.main_loop(USER_CALL, query, continuation)
-
- def _user_call(self, query, continuation):
- signature = hint(query.signature, promote=True)
- function = self._jit_lookup(signature)
- startrulechain = function.rulechain
- startrulechain = hint(startrulechain, promote=True)
- if startrulechain is None:
- error.throw_existence_error(
- "procedure", query.get_prolog_signature())
-
- unify_hash = query.unify_hash_of_children(self.heap)
- rulechain = startrulechain.find_applicable_rule(unify_hash)
- if rulechain is None:
- # none of the rules apply
- raise UnificationFailed()
- rule = rulechain.rule
- rulechain = rulechain.next
- oldstate = self.heap.branch()
- while 1:
- if rulechain is not None:
- rulechain = rulechain.find_applicable_rule(unify_hash)
- choice_point = rulechain is not None
- else:
- choice_point = False
- hint(rule, concrete=True)
- if rule.contains_cut:
- continuation = LimitedScopeContinuation(continuation)
- try:
- result = self.try_rule(rule, query, continuation)
- self.heap.discard(oldstate)
- return result
- except UnificationFailed:
- self.heap.revert(oldstate)
- except CutException, e:
- if continuation.scope_active:
- return self.continue_after_cut(e.continuation,
- continuation)
- raise
- else:
- inline = rule.body is None # inline facts
- try:
- # for the last rule (rulechain is None), this will always
- # return, because choice_point is False
- result = self.try_rule(rule, query, continuation,
- choice_point=choice_point,
- inline=inline)
- self.heap.discard(oldstate)
- return result
- except UnificationFailed:
- assert choice_point
- self.heap.revert(oldstate)
- rule = rulechain.rule
- rulechain = rulechain.next
-
- def try_rule(self, rule, query, continuation=DONOTHING, choice_point=True,
- inline=False):
- if not choice_point:
- return (TRY_RULE, query, continuation, rule)
- if not we_are_jitted():
- return self.portal_try_rule(rule, query, continuation, choice_point)
- if inline:
- return self.main_loop(TRY_RULE, query, continuation, rule)
- #if _is_early_constant(rule):
- # rule = hint(rule, promote=True)
- # #force right colors
- # query = hint(query, variable=True)
- # continuation = hint(continuation, variable=True)
- # return self.portal_try_rule(rule, query, continuation, True)
- return self._opaque_try_rule(rule, query, continuation, choice_point)
-
- def _opaque_try_rule(self, rule, query, continuation, choice_point):
- return self.portal_try_rule(rule, query, continuation, choice_point)
-
- def portal_try_rule(self, rule, query, continuation, choice_point):
- hint(None, global_merge_point=True)
- hint(choice_point, concrete=True)
- if not choice_point:
- return self._try_rule(rule, query, continuation)
- where = TRY_RULE
- next = (DONE, None, None, None)
- hint(where, concrete=True)
- hint(rule, concrete=True)
- signature = hint(query.signature, promote=True)
- while 1:
- hint(None, global_merge_point=True)
- if where == DONE:
- return next
- if rule is not None:
- assert rule.signature == signature
- next = self.dispatch_bytecode(where, query, continuation, rule)
- where, query, continuation, rule = next
- rule = hint(rule, promote=True)
- if query is not None:
- signature = hint(query.signature, promote=True)
- where = hint(where, promote=True)
-
- def _try_rule(self, rule, query, continuation):
- rule = hint(rule, deepfreeze=True)
- hint(self, concrete=True)
- # standardizing apart
- nextcall = rule.clone_and_unify_head(self.heap, query)
- if nextcall is not None:
- return self.call(nextcall, continuation, choice_point=False)
- else:
- return continuation.call(self, choice_point=False)
-
def continue_after_cut(self, continuation, lsc=None):
while 1:
try:
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 10:33:47 2007
@@ -1,16 +1,19 @@
from pypy.lang.prolog.interpreter import helper
-from pypy.lang.prolog.interpreter.term import Term, Atom, Var
+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, Continuation
from pypy.lang.prolog.interpreter.prologopcode import unrolling_opcode_descs, \
HAVE_ARGUMENT
class FrameContinuation(Continuation):
- def __init__(self, frame, pc):
+ def __init__(self, frame, pc, continuation):
self.frame = frame
self.pc = pc
+ self.continuation = continuation
def _call(self, engine):
- return frame.run(pc)
+ return self.frame.run(self.frame.code.opcode, self.pc,
+ self.continuation)
class Rule(object):
_immutable_ = True
@@ -37,6 +40,15 @@
return "%s." % (self.head, )
return "%s :- %s." % (self.head, self.body)
+class Query(object):
+ def __init__(self, body, engine):
+ from pypy.lang.prolog.interpreter.compiler import compile_query
+ self.code = compile_query(body, engine)
+ self.engine = engine
+
+ def make_frame(self):
+ return Frame(self.engine, self.code)
+
class Frame(object):
#_immutable_ = True # XXX?
@@ -45,34 +57,39 @@
self.engine = engine
self.code = code
self.localvarcache = [None] * code.maxlocalvar
+ self.stack = None
def unify_head(self, head):
- self.run(self.code.opcode_head, 0, None, [head])
+ self.run(self.code.opcode_head, 0, None)
+ self.stack[0].unify(head, self.engine.heap)
+ self.stack = None
+
+ def run_directly(self, continuation):
+ return self.run(self.code.opcode, 0, continuation)
- def run(self, bytecode, pc, continuation, stack=None):
- if stack is None:
- stack = []
+ def run(self, bytecode, pc, continuation):
+ stack = []
while pc < len(bytecode):
opcode = ord(bytecode[pc])
pc += 1
if opcode >= HAVE_ARGUMENT:
- lo = ord(bytecode[pc])
- hi = ord(bytecode[pc+1])
+ hi = ord(bytecode[pc])
+ lo = ord(bytecode[pc+1])
pc += 2
oparg = (hi << 8) | lo
else:
oparg = 0
+ #import pdb; pdb.set_trace()
for opdesc in unrolling_opcode_descs:
if opcode == opdesc.index:
# dispatch to the opcode method
meth = getattr(self, opdesc.name)
if opdesc.hascontinuation:
- continuation = FrameContinuation(
- self, pc, continuation)
+ cont = FrameContinuation(self, pc, continuation)
if opdesc.hasargument:
- res = meth(stack, oparg, continuation)
+ res = meth(stack, oparg, cont)
else:
- res = meth(stack, continuation)
+ res = meth(stack, cont)
else:
if opdesc.hasargument:
res = meth(stack, oparg)
@@ -85,14 +102,16 @@
if isinstance(continuation, FrameContinuation):
self = continuation.frame
pc = continuation.pc
- bytecode = self.code.bytecode
+ bytecode = self.code.opcode
stack = []
+ break
else:
res = continuation._call(self.engine)
break
else:
assert 0, "missing opcode"
- assert len(stack) == 0
+ if len(stack) != 0:
+ self.stack = stack
return (CONTINUATION, None, continuation, None)
def PUTCONSTANT(self, stack, number):
@@ -115,25 +134,26 @@
def CALL_BUILTIN(self, stack, number, continuation, *ignored):
from pypy.lang.prolog.builtin import builtins_list
- return builtins_list[number].call(self, stack.pop(), continuation)
+ return builtins_list[number][1].call(self.engine, stack.pop(),
+ continuation)
def DYNAMIC_CALL(self, stack, continuation, *ignored):
query = stack.pop()
+ assert isinstance(query, Callable)
+ signature = query.signature
function = self.engine._jit_lookup(signature)
rulechain = function.rulechain
if rulechain is None:
error.throw_existence_error(
"procedure", query.get_prolog_signature())
- oldstate = self.heap.branch()
+ oldstate = self.engine.heap.branch()
while rulechain is not None:
rule = rulechain.rule
try:
frame = rule.make_frame(query)
- if frame.code.bytecode:
- return frame.run(continuation)
- return None
- except UnificationFailed:
- self.heap.revert(oldstate)
+ return frame.run_directly(continuation)
+ except error.UnificationFailed:
+ self.engine.heap.revert(oldstate)
rule = rulechain.rule
rulechain = rulechain.next
Modified: pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/term.py
==============================================================================
--- pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/term.py (original)
+++ pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/term.py Thu Jun 7 10:33:47 2007
@@ -501,62 +501,6 @@
error.throw_type_error("evaluable", self.get_prolog_signature())
return func(engine, self)
-class Rule(object):
- _immutable_ = True
- unify_hash = []
- def __init__(self, head, body, engine):
- from pypy.lang.prolog.interpreter import helper
- assert isinstance(head, Callable)
- self.head = head
- if body is not None:
- body = helper.ensure_callable(body)
- self.body = body
- else:
- self.body = None
- self.signature = self.head.signature
- if isinstance(head, Term):
- self.unify_hash = [arg.get_unify_hash(None) for arg in head.args]
- self._does_contain_cut()
-
- def _does_contain_cut(self):
- if self.body is None:
- self.contains_cut = False
- return
- stack = [self.body]
- while stack:
- current = stack.pop()
- if isinstance(current, Atom):
- if current.name == "!":
- self.contains_cut = True
- return
- elif isinstance(current, Term):
- stack.extend(current.args)
- self.contains_cut = False
-
- def clone_and_unify_head(self, heap, head):
- memo = {}
- h2 = self.head
- hint(h2, concrete=True)
- if isinstance(h2, Term):
- assert isinstance(head, Term)
- i = 0
- while i < len(h2.args):
- i = hint(i, concrete=True)
- arg2 = h2.args[i]
- arg1 = head.args[i]
- arg2.copy_and_unify(arg1, heap, memo)
- i += 1
- body = self.body
- hint(body, concrete=True)
- if body is None:
- return None
- return body.copy(heap, memo)
-
- def __repr__(self):
- if self.body is None:
- return "%s." % (self.head, )
- return "%s :- %s." % (self.head, self.body)
-
@specialize.argtype(0)
def rcmp(a, b): # RPython does not support cmp...
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 10:33:47 2007
@@ -7,7 +7,7 @@
foo = Atom("foo")
code = compile(foo, None, e)
assert not code.opcode
- assert code.opcode_head == "c\x00\x00U"
+ assert code.opcode_head == "c\x00\x00"
assert code.constants == [foo]
def test_simple_withbody():
@@ -15,7 +15,7 @@
foo = Atom("foo")
bar = Atom("bar")
code = compile(foo, bar, e)
- assert code.opcode_head == "c\x00\x00U"
+ assert code.opcode_head == "c\x00\x00"
assert code.opcode == "c\x00\x01D"
assert code.constants == [foo, bar]
@@ -23,7 +23,7 @@
e = get_engine("")
head, body = get_query_and_vars("f(X) :- g(X).")[0].args
code = compile(head, body, e)
- assert code.opcode_head == "l\x00\x00t\x00\x00U"
+ assert code.opcode_head == "l\x00\x00t\x00\x00"
assert code.opcode == "l\x00\x00t\x00\x01D"
assert code.constants == []
assert code.term_info == [("f", 1, "f/1"), ("g", 1, "g/1")]
@@ -32,7 +32,7 @@
e = get_engine("")
head, body = get_query_and_vars("f(X, Y) :- g(X), h(Y).")[0].args
code = compile(head, body, e)
- assert code.opcode_head == "l\x00\x00l\x00\x01t\x00\x00U"
+ assert code.opcode_head == "l\x00\x00l\x00\x01t\x00\x00"
assert code.opcode == "l\x00\x00t\x00\x01Dl\x00\x01t\x00\x02D"
assert code.constants == []
assert code.term_info == [("f", 2, "f/2"), ("g", 1, "g/1"), ("h", 1, "h/1")]
@@ -41,7 +41,7 @@
e = get_engine("")
head = get_query_and_vars("f(g(X), a).")[0]
code = compile(head, None, e)
- assert code.opcode_head == "l\x00\x00t\x00\x00c\x00\x00t\x00\x01U"
+ 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")]
@@ -49,7 +49,7 @@
e = get_engine("")
head, body = get_query_and_vars("f(X, Y) :- g(X) = g(Y).")[0].args
code = compile(head, body, e)
- assert code.opcode_head == "l\x00\x00l\x00\x01t\x00\x00U"
+ assert code.opcode_head == "l\x00\x00l\x00\x01t\x00\x00"
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")]
Modified: pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/test/test_engine.py
==============================================================================
--- pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/test/test_engine.py (original)
+++ pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/test/test_engine.py Thu Jun 7 10:33:47 2007
@@ -224,11 +224,9 @@
% (chr(i), chr(i + 1))
for i in range(97, 122)]))
t = parse_query_term("f(x, g(y)).")
- for i in range(200):
- e.run(t)
+ e.run(t)
t = parse_query_term("f(x, g(y, a)).")
- for i in range(200):
- py.test.raises(UnificationFailed, e.run, t)
+ py.test.raises(UnificationFailed, e.run, t)
def test_indexing2():
e = get_engine("""
Modified: pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/test/test_unification.py
==============================================================================
--- pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/test/test_unification.py (original)
+++ pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/test/test_unification.py Thu Jun 7 10:33:47 2007
@@ -62,7 +62,8 @@
Term("f", [Y, X])]))
X = e.heap.newvar()
e.run(Term("f", [Atom.newatom("b"), X]))
- assert X.dereference(e.heap).name == "b"
+ assert X.dereference(e.heap).name == "a"
e.run(Term("f", [Atom.newatom("b"), Atom.newatom("a")]))
+ e.run(Term("f", [Atom.newatom("c"), Atom.newatom("c")]))
Modified: pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/test/tool.py
==============================================================================
--- pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/test/tool.py (original)
+++ pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/test/tool.py Thu Jun 7 10:33:47 2007
@@ -33,6 +33,7 @@
raise UnificationFailed
def collect_all(engine, s):
+ py.test.skip("collect_all currently does not work")
terms, vars = engine.parse(s)
term, = terms
collector = CollectAllContinuation(vars)
More information about the Pypy-commit
mailing list