[pypy-svn] r44060 - in pypy/dist/pypy/lang/prolog/interpreter: . test
cfbolz at codespeak.net
cfbolz at codespeak.net
Thu Jun 7 01:09:20 CEST 2007
Author: cfbolz
Date: Thu Jun 7 01:09:19 2007
New Revision: 44060
Added:
pypy/dist/pypy/lang/prolog/interpreter/compiler.py (contents, props changed)
pypy/dist/pypy/lang/prolog/interpreter/test/test_compiler.py
Log:
start of the compiler
Added: pypy/dist/pypy/lang/prolog/interpreter/compiler.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/lang/prolog/interpreter/compiler.py Thu Jun 7 01:09:19 2007
@@ -0,0 +1,130 @@
+from pypy.lang.prolog.interpreter.term import NonVar, Term, Var
+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
+
+
+class Code(object):
+ _immutable_ = True
+ def __init__(self):
+ self.term_info = [] # tuples of (functor, numargs, signature)
+ self.opcode_head = ""
+ self.opcode = ""
+ self.constants = [] # list of ground Prolog objects
+ self.maxlocalvar = 0
+
+
+def compile(head, body, engine):
+ comp = Compiler(engine)
+ return comp.compile(head, body)
+
+class Compiler(object):
+ def __init__(self, engine):
+ self.engine = engine
+
+ def compile(self, head, body):
+ self.term_info = [] # tuples of (functor, numargs, signature)
+ self.term_info_map = {}
+ self.opcode = []
+ self.constants = [] # list of ground Prolog objects
+ self.constant_map = {}
+ self.maxlocalvar = 0
+ 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)
+ result.opcode = self.getbytecode()
+ result.constants = self.constants
+ result.term_info = self.term_info
+ result.maxlocalvar = len(self.varmap)
+ return result
+
+ def compile_termbuilding(self, term):
+ if helper.is_ground(term, self.engine):
+ num = self.getconstnum(term)
+ self.emit_opcode(opcodedesc.PUTCONSTANT, num)
+ elif isinstance(term, Var):
+ num = self.getvarnum(term)
+ self.emit_opcode(opcodedesc.PUTLOCALVAR, num)
+ else:
+ assert isinstance(term, Term)
+ for arg in term.args:
+ self.compile_termbuilding(arg)
+ num = self.getsignum(term)
+ self.emit_opcode(opcodedesc.MAKETERM, num)
+
+ def compile_body(self, body):
+ from pypy.lang.prolog.builtin import builtins_list, builtins_index
+
+ body = body.dereference(self.engine.heap)
+ if isinstance(body, Var):
+ self.compile_termbuilding(body)
+ self.emit_opcode(opcodedesc.DYNAMIC_CALL)
+ return
+ body = helper.ensure_callable(body)
+ if isinstance(body, Term):
+ if body.signature == ",/2":
+ self.compile_body(body.args[0])
+ self.compile_body(body.args[1])
+ return
+ if body.signature == "=/2":
+ self.compile_termbuilding(body.args[0])
+ self.compile_termbuilding(body.args[1])
+ self.emit_opcode(opcodedesc.UNIFY)
+ elif body.signature == "call/1": #XXX interactions with cuts correct?
+ self.compile_body(body.args[0])
+ elif body.signature in builtins_index:
+ i = builtins_index[body.signature]
+ self.compile_termbuilding(body)
+ self.emit_opcode(opcodedesc.CALL_BUILTIN, i)
+ else:
+ self.compile_termbuilding(body)
+ self.emit_opcode(opcodedesc.DYNAMIC_CALL)
+
+ def emit_opcode(self, desc, arg=-1):
+ self.opcode.append(desc.index)
+ if desc.hasargument:
+ if not 0 <= arg < 65536:
+ raise error.UncatchableError("too many constants or variables!")
+ self.opcode.append(arg >> 8)
+ self.opcode.append(arg & 0xff)
+
+ def getbytecode(self):
+ bytecodes = [chr(c) for c in self.opcode]
+ self.opcode = []
+ return "".join(bytecodes)
+
+
+ def getvarnum(self, var):
+ try:
+ return self.varmap[var]
+ except KeyError:
+ result = self.varmap[var] = len(self.varmap)
+ return result
+
+ def getsignum(self, term):
+ try:
+ return self.term_info_map[term.signature]
+ except KeyError:
+ result = len(self.term_info_map)
+ self.term_info_map[term.signature] = result
+ self.term_info.append((term.name, len(term.args), term.signature))
+ return result
+
+ def getconstnum(self, const):
+ try:
+ return self.constant_map[const]
+ except KeyError:
+ result = len(self.constant_map)
+ self.constant_map[const] = result
+ self.constants.append(const)
+ return result
+
+ self.constants.append(term.getvalue(self.engine.heap))
+
+
Added: pypy/dist/pypy/lang/prolog/interpreter/test/test_compiler.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/lang/prolog/interpreter/test/test_compiler.py Thu Jun 7 01:09:19 2007
@@ -0,0 +1,57 @@
+from pypy.lang.prolog.interpreter.compiler import compile
+from pypy.lang.prolog.interpreter.term import Atom, Var, Term
+from pypy.lang.prolog.interpreter.parsing import get_engine, get_query_and_vars
+
+def test_simple():
+ e = get_engine("")
+ foo = Atom("foo")
+ code = compile(foo, None, e)
+ assert not code.opcode
+ assert code.opcode_head == "c\x00\x00U"
+ assert code.constants == [foo]
+
+def test_simple_withbody():
+ e = get_engine("")
+ foo = Atom("foo")
+ bar = Atom("bar")
+ code = compile(foo, bar, e)
+ assert code.opcode_head == "c\x00\x00U"
+ assert code.opcode == "c\x00\x01D"
+ assert code.constants == [foo, bar]
+
+def test_simple_withargs():
+ 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 == "l\x00\x00t\x00\x01D"
+ assert code.constants == []
+ assert code.term_info == [("f", 1, "f/1"), ("g", 1, "g/1")]
+
+def test_simple_and():
+ 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 == "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")]
+
+def test_nested_term():
+ 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.term_info == [("g", 1, "g/1"), ("f", 2, "f/2")]
+ assert code.constants == [Atom("a")]
+
+def test_unify():
+ 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 == "l\x00\x00t\x00\x01l\x00\x01t\x00\x01U"
+ assert code.constants == []
+ assert code.term_info == [("f", 2, "f/2"), ("g", 1, "g/1")]
+
+
More information about the Pypy-commit
mailing list