[pypy-svn] r44067 - in pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter: . test
cfbolz at codespeak.net
cfbolz at codespeak.net
Thu Jun 7 01:48:13 CEST 2007
Author: cfbolz
Date: Thu Jun 7 01:48:12 2007
New Revision: 44067
Added:
pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/interpreter.py (contents, props changed)
pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/test/test_interpreter.py (contents, props changed)
Log:
first experiments with a bytecode interpreter: not integrated with anything
else, byt a very simple test works.
Added: pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/interpreter.py
==============================================================================
--- (empty file)
+++ pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/interpreter.py Thu Jun 7 01:48:12 2007
@@ -0,0 +1,146 @@
+from pypy.lang.prolog.interpreter import helper
+from pypy.lang.prolog.interpreter.term import Term, Atom, Var
+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):
+ self.frame = frame
+ self.pc = pc
+
+ def _call(self, engine):
+ return frame.run(pc)
+
+class Rule(object):
+ _immutable_ = True
+ def __init__(self, head, body, engine):
+ from pypy.lang.prolog.interpreter.compiler import compile
+ head = helper.ensure_callable(head)
+ self.head = head
+ self.code = compile(head, body, engine)
+ if body is not None:
+ body = helper.ensure_callable(body)
+ self.body = body
+ else:
+ self.body = None
+ self.signature = self.head.signature
+ self.engine = engine
+
+ def make_frame(self, head):
+ f = Frame(self.engine, self.code)
+ f.unify_head(head)
+ return f
+
+ def __repr__(self):
+ if self.body is None:
+ return "%s." % (self.head, )
+ return "%s :- %s." % (self.head, self.body)
+
+
+class Frame(object):
+ #_immutable_ = True # XXX?
+
+ def __init__(self, engine, code):
+ self.engine = engine
+ self.code = code
+ self.localvarcache = [None] * code.maxlocalvar
+
+ def unify_head(self, head):
+ self.run(self.code.opcode_head, 0, None, [head])
+
+ def run(self, bytecode, pc, continuation, stack=None):
+ if stack is None:
+ stack = []
+ while pc < len(bytecode):
+ opcode = ord(bytecode[pc])
+ pc += 1
+ if opcode >= HAVE_ARGUMENT:
+ lo = ord(bytecode[pc])
+ hi = ord(bytecode[pc+1])
+ pc += 2
+ oparg = (hi << 8) | lo
+ else:
+ oparg = 0
+ 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)
+ if opdesc.hasargument:
+ res = meth(stack, oparg, continuation)
+ else:
+ res = meth(stack, continuation)
+ else:
+ if opdesc.hasargument:
+ res = meth(stack, oparg)
+ else:
+ res = meth(stack)
+ if res is not None:
+ while 1:
+ where, _, continuation, _ = res
+ assert where == CONTINUATION
+ if isinstance(continuation, FrameContinuation):
+ self = continuation.frame
+ pc = continuation.pc
+ bytecode = self.code.bytecode
+ stack = []
+ else:
+ res = continuation._call(self.engine)
+ break
+ else:
+ assert 0, "missing opcode"
+ assert len(stack) == 0
+ return (CONTINUATION, None, continuation, None)
+
+ def PUTCONSTANT(self, stack, number):
+ stack.append(self.code.constants[number])
+
+ def PUTLOCALVAR(self, stack, number):
+ result = self.localvarcache[number]
+ if result is None:
+ result = self.localvarcache[number] = self.engine.heap.newvar()
+ stack.append(result)
+
+ def MAKETERM(self, stack, number, *ignored):
+ name, numargs, signature = self.code.term_info[number]
+ args = [None] * numargs
+ i = 0
+ while i < numargs:
+ args[i] = stack.pop()
+ i += 1
+ stack.append(Term(name, args, signature))
+
+ 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)
+
+ def DYNAMIC_CALL(self, stack, continuation, *ignored):
+ query = stack.pop()
+ 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()
+ 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)
+ rule = rulechain.rule
+ rulechain = rulechain.next
+
+ def CLEAR_LOCAL(self, stack, number, *ignored):
+ self.localvarcache[number] = None
+
+ def UNIFY(self, stack, *ignored):
+ stack.pop().unify(stack.pop(), self.engine.heap)
+
+
Added: pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/test/test_interpreter.py
==============================================================================
--- (empty file)
+++ pypy/branch/prolog-bytecode/pypy/lang/prolog/interpreter/test/test_interpreter.py Thu Jun 7 01:48:12 2007
@@ -0,0 +1,17 @@
+import py
+from pypy.lang.prolog.interpreter.interpreter import Rule
+from pypy.lang.prolog.interpreter.parsing import get_engine, get_query_and_vars
+
+def test_simple():
+ e = get_engine("")
+ head, body = get_query_and_vars("f(X) :- X = a.")[0].args
+ r = Rule(head, body, e)
+ query = get_query_and_vars("f(a).")[0]
+ frame = r.make_frame(query)
+ assert frame.localvarcache[0].dereference(e.heap).name == "a"
+ cont = object()
+ res = frame.run(frame.code.opcode, 0, cont)
+ where, _, c2, _ = res
+ assert cont is c2
+
+
More information about the Pypy-commit
mailing list