[pypy-svn] r7615 - pypy/trunk/src/pypy/translator
tismer at codespeak.net
tismer at codespeak.net
Tue Nov 23 13:41:48 CET 2004
Author: tismer
Date: Tue Nov 23 13:41:47 2004
New Revision: 7615
Added:
pypy/trunk/src/pypy/translator/genrpy.py
Log:
initial rough version of a Python to RPython code generator.
A lot more has to be done.
But at least it creates almost correct looking code.
TODO: subclass translator and flow space for the unrpythonic case
Added: pypy/trunk/src/pypy/translator/genrpy.py
==============================================================================
--- (empty file)
+++ pypy/trunk/src/pypy/translator/genrpy.py Tue Nov 23 13:41:47 2004
@@ -0,0 +1,256 @@
+from pypy.objspace.flow.model import traverse
+from pypy.objspace.flow import FlowObjSpace
+from pypy.objspace.flow.model import FunctionGraph, Block, Link, Variable, Constant
+from pypy.objspace.flow.model import last_exception, last_exc_value
+from pypy.translator.simplify import simplify_graph
+from pypy.interpreter.error import OperationError
+
+from pypy.translator.translator import Translator
+
+import sys
+
+def somefunc(arg):
+ pass
+
+def f(a,b):
+ print "start"
+ a = []
+ a.append(3)
+ for i in range(3):
+ print i
+ if a > b:
+ try:
+ if b == 123:
+ raise ValueError
+ elif b == 321:
+ raise IndexError
+ return 123
+ except ValueError:
+ raise TypeError
+ else:
+ dummy = somefunc(23)
+ return 42
+
+def ff(a, b):
+ try:
+ raise SystemError, 42
+ return a+b
+ finally:
+ a = 7
+
+glob = 100
+def fff():
+ global glob
+ return 42+glob
+
+def app_str_decode__String_ANY_ANY(str, encoding=None, errors=None):
+ if encoding is None and errors is None:
+ return unicode(str)
+ elif errors is None:
+ return unicode(str, encoding)
+ else:
+ return unicode(str, encoding, errors)
+
+
+def ordered_blocks(graph):
+ # collect all blocks
+ allblocks = []
+ def visit(block):
+ if isinstance(block, Block):
+ # first we order by offset in the code string
+ if block.operations:
+ ofs = block.operations[0].offset
+ else:
+ ofs = sys.maxint
+ # then we order by input variable name or value
+ if block.inputargs:
+ txt = str(block.inputargs[0])
+ else:
+ txt = "dummy"
+ allblocks.append((ofs, txt, block))
+ traverse(visit, graph)
+ allblocks.sort()
+ #for ofs, txt, block in allblocks:
+ # print ofs, txt, block
+ return [block for ofs, txt, block in allblocks]
+
+
+class GenRpy:
+ def __init__(self, f, translator):
+ self.f = f
+ self.translator = translator
+ self.rpynames = {}
+
+ # special constructors:
+ self.has_listarg = {}
+ for name in "newtuple newlist newdict newstring".split():
+ self.has_listarg[name] = name
+
+ def nameof(self, obj):
+ key = Constant(obj).key
+ try:
+ return self.rpynames[key]
+ except KeyError:
+ name = "w(%s)" % str(obj)
+ self.rpynames[key] = name
+ return name
+
+ def gen_rpyfunction(self, func):
+
+ local_names = {}
+
+ def expr(v, wrapped = True):
+ if isinstance(v, Variable):
+ n = v.name
+ if n.startswith("v") and n[1:].isdigit():
+ ret = local_names.get(v.name)
+ if not ret:
+ if wrapped:
+ local_names[v.name] = ret = "w_%d" % len(local_names)
+ else:
+ local_names[v.name] = ret = "v%d" % len(local_names)
+ return ret
+ return v.name
+ elif isinstance(v, Constant):
+ return self.nameof(v.value)
+ else:
+ #raise TypeError, "expr(%r)" % (v,)
+ # XXX how do I resolve these?
+ return "space.%s" % str(v)
+
+ def arglist(args):
+ res = [expr(arg) for arg in args]
+ return ", ".join(res)
+
+ def oper(op):
+ # specialcase is_true
+ if op.opname in self.has_listarg:
+ fmt = "%s = %s([%s])"
+ else:
+ fmt = "%s = %s(%s)"
+ if op.opname == "is_true":
+ return fmt % (expr(op.result, False), expr(op.opname), arglist(op.args))
+ return fmt % (expr(op.result), expr(op.opname), arglist(op.args))
+
+ def gen_link(link, linklocalvars=None):
+ "Generate the code to jump across the given Link."
+ linklocalvars = linklocalvars or {}
+ left, right = [], []
+ for a1, a2 in zip(link.args, link.target.inputargs):
+ if a1 in linklocalvars:
+ src = linklocalvars[a1]
+ else:
+ src = expr(a1)
+ left.append(expr(a2))
+ right.append(src)
+ yield "%s = %s" % (", ".join(left), ", ".join(right))
+ goto = blocknum[link.target]
+ yield 'goto = %d' % goto
+ if goto <= blocknum[block]:
+ yield 'continue'
+
+ f = self.f
+ t = self.translator
+ t.simplify(func, rpython=False)
+ graph = t.getflowgraph(func)
+
+ start = graph.startblock
+ blocks = ordered_blocks(graph)
+ nblocks = len(blocks)
+ assert blocks[0] is start
+
+ blocknum = {}
+ for block in blocks:
+ blocknum[block] = len(blocknum)+1
+
+ # create function declaration
+ name = func.__name__ # change this
+ args = [expr(var) for var in start.inputargs]
+ argstr = ", ".join(args)
+ print >> f, "def %s(space, %s):" % (name, argstr)
+ print >> f, " w = space.wrap"
+ print >> f, " goto = 1 # startblock"
+ print >> f, " while True:"
+
+ def render_block(block):
+ catch_exception = block.exitswitch == Constant(last_exception)
+ regular_op = len(block.operations) - catch_exception
+ # render all but maybe the last op
+ for op in block.operations[:regular_op]:
+ yield "%s" % oper(op)
+ # render the last op if it is exception handled
+ for op in block.operations[regular_op:]:
+ yield "try:"
+ yield " %s" % oper(op)
+
+ if len(block.exits) == 0:
+ if len(block.inputargs) == 2: # exc_cls, exc_value
+ # exceptional return block
+ exc_cls = expr(block.inputargs[0])
+ exc_val = expr(block.inputargs[1])
+ yield "raise OperationError(%s, %s)" % (exc_cls, exc_val)
+ else:
+ # regular return block
+ retval = expr(block.inputargs[0])
+ yield"return %s" % retval
+ return
+ elif block.exitswitch is None:
+ # single-exit block
+ assert len(block.exits) == 1
+ for op in gen_link(block.exits[0]):
+ yield " %s" % op
+ elif catch_exception:
+ # block catching the exceptions raised by its last operation
+ # we handle the non-exceptional case first
+ link = block.exits[0]
+ assert link.exitcase is None
+ for op in gen_link(link):
+ yield " %s" % op
+ # we must catch the exception raised by the last operation,
+ # which goes to the last err%d_%d label written above.
+ yield "except OperationError, e:"
+ for link in block.exits[1:]:
+ assert issubclass(link.exitcase, Exception)
+ for op in gen_link(link, {
+ Constant(last_exception): 'e.w_type',
+ Constant(last_exc_value): 'e.w_value'}):
+ yield " %s" % op
+ else:
+ # block ending in a switch on a value
+ exits = list(block.exits)
+ if len(exits) == 2 and (
+ exits[0].exitcase is False and exits[1].exitcase is True):
+ # order these guys like Python does
+ exits.reverse()
+ q = "if"
+ for link in exits[:-1]:
+ yield "%s %s == %s:" % (q, expr(block.exitswitch),
+ link.exitcase)
+ for op in gen_link(link):
+ yield " %s" % op
+ q = "elif"
+ link = exits[-1]
+ yield "else:"
+ yield " assert %s == %s" % (expr(block.exitswitch),
+ link.exitcase)
+ for op in gen_link(exits[-1]):
+ yield " %s" % op
+
+ for block in blocks:
+ blockno = blocknum[block]
+ print >> f
+ print " if goto == %d:" % blockno
+ for line in render_block(block):
+ print " %s" % line
+
+entry_point = (f, ff, fff, app_str_decode__String_ANY_ANY) [0]
+
+t = Translator(entry_point, verbose=False, simplifying=False)
+#t.simplify(rpython=False)
+#t.view()
+gen = GenRpy(sys.stdout, t)
+gen.gen_rpyfunction(t.functions[0])
+# debugging
+graph = t.getflowgraph()
+ab = ordered_blocks(graph) # use ctrl-b in PyWin with ab
+
More information about the Pypy-commit
mailing list