[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