[pypy-svn] r2986 - in pypy/trunk/src/pypy: tool translator translator/testtranslator/tool
arigo at codespeak.net
arigo at codespeak.net
Mon Feb 16 22:20:40 CET 2004
Author: arigo
Date: Mon Feb 16 22:20:39 2004
New Revision: 2986
Modified:
pypy/trunk/src/pypy/tool/testit.py
pypy/trunk/src/pypy/translator/annrpython.py
pypy/trunk/src/pypy/translator/gencl.py
pypy/trunk/src/pypy/translator/genpyrex.py
pypy/trunk/src/pypy/translator/test/test_pyrextrans.py
pypy/trunk/src/pypy/translator/tool/buildcl.py
pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py
pypy/trunk/src/pypy/translator/translator.py
Log:
Generate Pyrex class definitions.
This is for attributes only, there is no support for methods, and it is not
clear if there should be. If we keep C in mind then we should probably
generate global functions only, and introduce explicit tricks to emulate
virtual methods -- though I believe that Pyrex can do precisely that, so maybe
we should just go ahead and emit methods.
Modified: pypy/trunk/src/pypy/tool/testit.py
==============================================================================
--- pypy/trunk/src/pypy/tool/testit.py (original)
+++ pypy/trunk/src/pypy/tool/testit.py Mon Feb 16 22:20:39 2004
@@ -68,8 +68,12 @@
def record_trace(self, test):
# XXX hack for TraceObjSpace
- if hasattr(test.space, 'settrace'):
- self.trace_information += test.space.getresult(),
+ try:
+ result = test.space.getresult()
+ except AttributeError:
+ pass
+ else:
+ self.trace_information += result
test.space.settrace()
def addError(self, test, err):
Modified: pypy/trunk/src/pypy/translator/annrpython.py
==============================================================================
--- pypy/trunk/src/pypy/translator/annrpython.py (original)
+++ pypy/trunk/src/pypy/translator/annrpython.py Mon Feb 16 22:20:39 2004
@@ -28,6 +28,8 @@
self.bindings = {} # map Variables/Constants to SomeValues
self.annotated = {} # set of blocks already seen
self.translator = translator
+ self.userclasses = {} # set of user classes discovered,
+ # mapped to sets of instance attributes
#___ convenience high-level interface __________________
@@ -58,6 +60,19 @@
raise TypeError, ("Variable or Constant instance expected, "
"got %r" % (variable,))
+ def getuserclasses(self):
+ """Return a set of known user classes."""
+ return self.userclasses
+
+ def getuserattributes(self, cls):
+ """Enumerate the attributes of the given user class, as Variable()s."""
+ for attr in self.userclasses[cls]:
+ clscell = self.constant(cls)
+ attrcell = self.heap.get(ANN.instanceattr[attr], clscell)
+ v = Variable(name=attr)
+ self.bindings[v] = attrcell
+ yield v
+
#___ medium-level interface ____________________________
@@ -214,25 +229,33 @@
def consider_op_setattr(self,obj,attr,newval):
objtype = self.heap.get(ANN.type,obj)
- if isinstance(objtype,type):
+ if objtype in self.userclasses:
attr = self.heap.get(ANN.const,attr)
if isinstance(attr, str):
- # update the annotation 'instanceattr' about the class 'cls'
- cls = self.constant(objtype)
- self.heap.set_or_generalize(ANN.instanceattr[attr], cls, newval)
+ # do we already know about this attribute?
+ attrdict = self.userclasses[objtype]
+ clscell = self.constant(objtype)
+ if attr not in attrdict:
+ # no -> create it
+ attrdict[attr] = True
+ self.heap.set(ANN.instanceattr[attr], clscell, newval)
+ else:
+ # yes -> update it
+ self.heap.generalize(ANN.instanceattr[attr], clscell, newval)
return SomeValue()
def consider_op_getattr(self,obj,attr):
result = SomeValue()
objtype = self.heap.get(ANN.type,obj)
- if isinstance(objtype,type):
+ if objtype in self.userclasses:
attr = self.heap.get(ANN.const,attr)
if isinstance(attr, str):
- if hasattr(objtype,attr): # XXX shortcut to keep methods working
- return result
- # return the current annotation for the class 'cls'
- cls = self.constant(objtype)
- return self.heap.get(ANN.instanceattr[attr], cls)
+ # do we know something about this attribute?
+ attrdict = self.userclasses[objtype]
+ if attr in attrdict:
+ # yes -> return the current annotation
+ clscell = self.constant(objtype)
+ return self.heap.get(ANN.instanceattr[attr], clscell)
return result
@@ -376,6 +399,8 @@
elif isinstance(func,type):
# XXX flow into __init__/__new__
self.heap.settype(result,func)
+ if func.__module__ != '__builtin__':
+ self.userclasses.setdefault(func, {})
return result
def consider_const(self, constvalue):
Modified: pypy/trunk/src/pypy/translator/gencl.py
==============================================================================
--- pypy/trunk/src/pypy/translator/gencl.py (original)
+++ pypy/trunk/src/pypy/translator/gencl.py Mon Feb 16 22:20:39 2004
@@ -205,7 +205,6 @@
sys.stdout = oldstdout
return out.getvalue()
def emit(self):
- self.emit_prelude()
self.emit_defun(self.fun)
def emit_defun(self, fun):
print ";;;; Main"
@@ -322,12 +321,11 @@
print trans % argreprs,
print ")"
print ")"
- def emit_prelude(self):
- print ";;;; Prelude"
- print prelude
+ def globaldeclarations(self):
+ return prelude
-prelude = """\
+prelude = """;;;; Prelude
(defun make-iterator (seq)
(let ((i 0))
(lambda ()
Modified: pypy/trunk/src/pypy/translator/genpyrex.py
==============================================================================
--- pypy/trunk/src/pypy/translator/genpyrex.py (original)
+++ pypy/trunk/src/pypy/translator/genpyrex.py Mon Feb 16 22:20:39 2004
@@ -127,6 +127,14 @@
else:
return "%s = getattr(%s)" % (self.resultname, ", ".join(args))
+ def op_setattr(self):
+ args = self.argnames
+ attr = self.op.args[1]
+ if isinstance(attr, Constant) and self.ispythonident(attr.value):
+ return "%s.%s = %s" % (args[0], attr.value, args[2])
+ else:
+ return "setattr(%s, %s, %s)" % args
+
def op_not(self):
return "%s = not %s" % (self.resultname, self.argnames[0])
@@ -214,8 +222,11 @@
return None
def get_varname(self, var):
- if self.get_type(var) in (int, bool):
+ vartype = self.get_type(var)
+ if vartype in (int, bool):
prefix = "i_"
+ elif self.annotator and vartype in self.annotator.getuserclasses():
+ prefix = "p_"
else:
prefix = ""
return prefix + var.name
@@ -224,11 +235,16 @@
vartype = self.get_type(var)
if vartype in (int, bool):
ctype = "int"
+ elif self.annotator and vartype in self.annotator.getuserclasses():
+ ctype = self.get_classname(vartype)
else:
ctype = "object"
return (ctype, self.get_varname(var))
+ def get_classname(self, userclass):
+ return userclass.__name__
+
def _vardecl(self, var):
vartype, varname = self._paramvardecl(var)
if vartype != "object":
@@ -310,3 +326,27 @@
self.putline("%s = %s" % (", ".join(targs), ", ".join(sargs)))
self.gen_block(block)
+
+ def globaldeclarations(self):
+ """Static method to generate the global class declaration for a
+ group of functions."""
+ if self.annotator:
+ self.lines = []
+ self.indent = 0
+ for cls in self.annotator.getuserclasses():
+ self.putline("cdef class %s:" % self.get_classname(cls))
+ self.indent += 1
+ empty = True
+ for var in self.annotator.getuserattributes(cls):
+ vartype, varname = self._paramvardecl(var)
+ varname = var.name # no 'i_' prefix
+ self.putline("cdef %s %s" % (vartype, varname))
+ empty = False
+ else:
+ if empty:
+ self.putline("pass")
+ self.indent -= 1
+ self.putline("")
+ return '\n'.join(self.lines)
+ else:
+ return ''
Modified: pypy/trunk/src/pypy/translator/test/test_pyrextrans.py
==============================================================================
--- pypy/trunk/src/pypy/translator/test/test_pyrextrans.py (original)
+++ pypy/trunk/src/pypy/translator/test/test_pyrextrans.py Mon Feb 16 22:20:39 2004
@@ -7,7 +7,7 @@
from pypy.translator.test import snippet as t
-class TypedPyrexGenTestCase(testit.IntTestCase):
+class NoTypePyrexGenTestCase(testit.IntTestCase):
def setUp(self):
self.space = testit.objspace('flow')
@@ -20,7 +20,6 @@
options = {
'simplify' : 1,
'dot' : dot,
- 'inputargtypes' : [int] * func.func_code.co_argcount
}
return build_cfunc(func, **options)
@@ -84,7 +83,7 @@
self.assertEquals(sand(0, 6), "no")
self.assertEquals(sand(0, 0), "no")
-class NoTypePyrexGenTestCase(TypedPyrexGenTestCase):
+class TypedPyrexGenTestCase(NoTypePyrexGenTestCase):
def build_cfunc(self, func):
try: func = func.im_func
@@ -94,8 +93,15 @@
options = {
'simplify' : 1,
'dot' : dot,
+ 'inputargtypes' : [int] * func.func_code.co_argcount
}
return build_cfunc(func, **options)
+ # _______________________________________________________
+ # The following tests require the type inference to work.
+ def test_set_attr(self):
+ set_attr = self.build_cfunc(t.set_attr)
+ self.assertEquals(set_attr(), 2)
+
if __name__ == '__main__':
testit.main()
Modified: pypy/trunk/src/pypy/translator/tool/buildcl.py
==============================================================================
--- pypy/trunk/src/pypy/translator/tool/buildcl.py (original)
+++ pypy/trunk/src/pypy/translator/tool/buildcl.py Mon Feb 16 22:20:39 2004
@@ -45,7 +45,7 @@
def _make_cl_func(func, cl, path, argtypes=[]):
fun = FlowObjSpace().build_flow(func)
gen = GenCL(fun, argtypes)
- out = gen.emitcode()
+ out = gen.globaldeclarations() + '\n' + gen.emitcode()
i = 1
fpath = path.join("%s.lisp" % fun.name)
def _(*args):
Modified: pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py
==============================================================================
--- pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py (original)
+++ pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py Mon Feb 16 22:20:39 2004
@@ -133,10 +133,11 @@
pyxstring = genpyrex.emitcode()
#funcgraph.source = inspect.getsource(func)
- mod = make_module_from_pyxstring(name, udir, pyxstring)
else:
pyxstring = genpyrex.emitcode()
- mod = make_module_from_pyxstring(name, udir, pyxstring)
+
+ pyxheader = genpyrex.globaldeclarations()
+ mod = make_module_from_pyxstring(name, udir, pyxheader + '\n' + pyxstring)
if dot:
if name != func.func_name: # if some transformations have been done
Modified: pypy/trunk/src/pypy/translator/translator.py
==============================================================================
--- pypy/trunk/src/pypy/translator/translator.py (original)
+++ pypy/trunk/src/pypy/translator/translator.py Mon Feb 16 22:20:39 2004
@@ -144,16 +144,18 @@
else:
ann = RPythonAnnotator(self)
if func is None:
- code = self.generatecode1(gencls, input_arg_types,
- self.entrypoint, ann)
- codes = [code]
+ codes = [self.generatecode1(gencls, input_arg_types,
+ self.entrypoint, ann)]
for func in self.functions:
if func is not self.entrypoint:
code = self.generatecode1(gencls, None, func, ann)
codes.append(code)
- return '\n\n#_________________\n\n'.join(codes)
else:
- return self.generatecode1(gencls, input_arg_types, func, ann)
+ codes = [self.generatecode1(gencls, input_arg_types, func, ann)]
+ code = self.generateglobaldecl(gencls, func, ann)
+ if code:
+ codes.insert(0, code)
+ return '\n\n#_________________\n\n'.join(codes)
def generatecode1(self, gencls, input_arg_types, func, ann):
graph = self.getflowgraph(func)
@@ -164,6 +166,13 @@
g.setannotator(ann)
return g.emitcode()
+ def generateglobaldecl(self, gencls, func, ann):
+ graph = self.getflowgraph(func)
+ g = gencls(graph)
+ if ann is not None:
+ g.setannotator(ann)
+ return g.globaldeclarations()
+
def compile(self):
"""Returns compiled function.
More information about the Pypy-commit
mailing list