[pypy-svn] r25621 - in pypy/dist/pypy/translator/cli: . test

antocuni at codespeak.net antocuni at codespeak.net
Sun Apr 9 14:18:34 CEST 2006


Author: antocuni
Date: Sun Apr  9 14:18:17 2006
New Revision: 25621

Added:
   pypy/dist/pypy/translator/cli/test/autopath.py   (contents, props changed)
Modified:
   pypy/dist/pypy/translator/cli/class_.py
   pypy/dist/pypy/translator/cli/cts.py
   pypy/dist/pypy/translator/cli/database.py
   pypy/dist/pypy/translator/cli/function.py
   pypy/dist/pypy/translator/cli/gencli.py
   pypy/dist/pypy/translator/cli/metavm.py
   pypy/dist/pypy/translator/cli/test/compile.py
   pypy/dist/pypy/translator/cli/test/runtest.py
   pypy/dist/pypy/translator/cli/test/test_oo.py
Log:
The algorithm for rendering pending nodes has been refactored. Now
every node (such as Function or Class) can enqueue new nodes that it
depends on, instead of having static dependencies as it was before.



Modified: pypy/dist/pypy/translator/cli/class_.py
==============================================================================
--- pypy/dist/pypy/translator/cli/class_.py	(original)
+++ pypy/dist/pypy/translator/cli/class_.py	Sun Apr  9 14:18:17 2006
@@ -1,5 +1,4 @@
 from pypy.translator.cli.node import Node
-from pypy.translator.cli.function import Function
 from pypy.translator.cli.cts import CTS
 
 class Class(Node):
@@ -9,6 +8,15 @@
         self.classdef = classdef
         self.namespace, self.name = self.cts.split_class_name(classdef._name)
 
+        if not self.is_root(classdef):
+            self.db.pending_class(classdef._superclass)
+
+    def __hash__(self):
+        return hash(self.classdef)
+
+    def __eq__(self, other):
+        return self.classdef == other.classdef
+
     def is_root(classdef):
         return classdef._superclass is None
     is_root = staticmethod(is_root)
@@ -26,7 +34,10 @@
     def render(self, ilasm):
         if self.is_root(self.classdef):
             return
-        
+
+        if self.db.class_name(self.classdef) is not None:
+            return # already rendered
+
         self.ilasm = ilasm
         if self.namespace:
             ilasm.begin_namespace(self.namespace)
@@ -38,9 +49,10 @@
         # TODO: should the .ctor set the default values?
         self._ctor()
 
+        # lazy import to avoid circular dependencies
+        import pypy.translator.cli.function as function
         for m_name, m_meth in self.classdef._methods.iteritems():
-            # TODO: handle class methods and attributes
-            f = Function(self.db, m_meth.graph, m_name, is_method = True)
+            f = function.Function(self.db, m_meth.graph, m_name, is_method = True)
             f.render(ilasm)
 
         ilasm.end_class()
@@ -48,10 +60,12 @@
         if self.namespace:
             ilasm.end_namespace()
 
+        self.db.record_class(self.classdef, self.name)
+
+
     def _ctor(self):
         self.ilasm.begin_function('.ctor', [], 'void', False, 'specialname', 'rtspecialname', 'instance')
         self.ilasm.opcode('ldarg.0')
         self.ilasm.call('instance void %s::.ctor()' % self.get_base_class())
         self.ilasm.opcode('ret')
         self.ilasm.end_function()
-

Modified: pypy/dist/pypy/translator/cli/cts.py
==============================================================================
--- pypy/dist/pypy/translator/cli/cts.py	(original)
+++ pypy/dist/pypy/translator/cli/cts.py	Sun Apr  9 14:18:17 2006
@@ -49,7 +49,7 @@
     def lltype_to_cts(self, t):
         if isinstance(t, Instance):
             name = t._name
-            self.db.classes.add(t)
+            self.db.pending_class(t)
             return 'class %s' % name
 
         return _get_from_dict(_lltype_to_cts, t, 'Unknown type %s' % t)

Modified: pypy/dist/pypy/translator/cli/database.py
==============================================================================
--- pypy/dist/pypy/translator/cli/database.py	(original)
+++ pypy/dist/pypy/translator/cli/database.py	Sun Apr  9 14:18:17 2006
@@ -1,3 +1,6 @@
+from pypy.translator.cli.cts import CTS
+from pypy.translator.cli.function import Function
+from pypy.translator.cli.class_ import Class
 from pypy.rpython.ootypesystem import ootype
 
 try:
@@ -10,20 +13,38 @@
 
 class LowLevelDatabase(object):
     def __init__(self):
-        self.classes = set()
-        self.pending_graphs = []
+        self._pending_nodes = set()
+        self._rendered_nodes = set()
+        self.classes = {} # classdef --> class_name
         self.functions = {} # graph --> function_name
         self.methods = {} # graph --> method_name
         self.consts = {}  # value --> const_name
 
+    def pending_function(self, graph):
+        self.pending_node(Function(self, graph))
+
+    def pending_class(self, classdef):
+        self.pending_node(Class(self, classdef))
+
+    def pending_node(self, node):
+        if node in self._pending_nodes or node in self._rendered_nodes:
+            return
+        self._pending_nodes.add(node)
+
     def record_function(self, graph, name):
         self.functions[graph] = name
 
+    def record_class(self, classdef, name):
+        self.classes[classdef] = name
+
     def function_name(self, graph):
         return self.functions.get(graph, None)
 
+    def class_name(self, classdef):
+        return self.classes.get(classdef, None)
+
     def record_const(self, value):
-        const = AbstractConst.make(value)
+        const = AbstractConst.make(self, value)
         name = const.get_name(len(self.consts))
         self.consts[const] = name
         return '%s.%s::%s' % (CONST_NAMESPACE, CONST_CLASS, name)
@@ -52,11 +73,11 @@
 
 
 class AbstractConst(object):
-    def make(const):
+    def make(db, const):
         if isinstance(const, ootype._view):
             const = const._inst
         if isinstance(const, ootype._instance):
-            return InstanceConst(const)
+            return InstanceConst(db, const)
         else:
             assert False, 'Unknown constant: %s' % const
     make = staticmethod(make)
@@ -71,7 +92,8 @@
         pass
 
 class InstanceConst(AbstractConst):
-    def __init__(self, obj):
+    def __init__(self, db, obj):
+        self.cts = CTS(db)
         self.obj = obj
 
     def get_name(self, n):
@@ -79,9 +101,16 @@
         return '%s_%d' % (name, n)
 
     def get_type(self):
-        return 'class %s' % self.obj._TYPE._name
+        return self.cts.lltype_to_cts(self.obj._TYPE)
+        #return 'class %s' % self.obj._TYPE._name
 
     def init(self, ilasm):
         classdef = self.obj._TYPE        
         ilasm.new('instance void class %s::.ctor()' % classdef._name)
-        # TODO: initialize fields
+        while classdef is not None:
+            for name, (type_, value) in classdef._fields.iteritems():
+                if isinstance(type_, ootype.StaticMethod):
+                    continue
+                elif type_ is ootype.Class:
+                    continue
+            classdef = classdef._superclass

Modified: pypy/dist/pypy/translator/cli/function.py
==============================================================================
--- pypy/dist/pypy/translator/cli/function.py	(original)
+++ pypy/dist/pypy/translator/cli/function.py	Sun Apr  9 14:18:17 2006
@@ -12,6 +12,7 @@
 from pypy.translator.cli.opcodes import opcodes
 from pypy.translator.cli.metavm import InstructionList, Generator
 from pypy.translator.cli.node import Node
+from pypy.translator.cli.class_ import Class
 
 from pypy.tool.ansi_print import ansi_log
 import py
@@ -33,6 +34,12 @@
     def get_name(self):
         return self.name
 
+    def __hash__(self):
+        return hash(self.graph)
+
+    def __eq__(self, other):
+        return self.graph == other.graph
+
     def _is_return_block(self, block):
         return (not block.exits) and len(block.inputargs) == 1
 
@@ -40,6 +47,9 @@
         return (not block.exits) and len(block.inputargs) == 2        
 
     def render(self, ilasm):
+        if self.db.function_name(self.graph) is not None and not self.is_method:
+            return # already rendered
+
         self.ilasm = ilasm
         graph = self.graph
         returntype, returnvar = self.cts.llvar_to_cts(graph.getreturnvar())
@@ -67,7 +77,7 @@
                 self.ilasm.begin_try()
 
             for op in block.operations:
-                self._search_for_classes(op)
+                #self._search_for_classes(op)
                 self._render_op(op)
 
             if self._is_raise_block(block):
@@ -200,14 +210,13 @@
             if isinstance(arg, flowmodel.Variable):
                 lltype = arg.concretetype
             elif isinstance(arg, flowmodel.Constant):
-                
                 lltype = arg.value
 
             if isinstance(lltype, ootype._view) and isinstance(lltype._inst, ootype._instance):
                 lltype = lltype._inst._TYPE
 
             if isinstance(lltype, ootype.Instance):
-                self.db.classes.add(lltype)
+                self.db.pending_class(lltype)
 
     def _render_op(self, op):
         instr_list = opcodes.get(op.opname, None)
@@ -248,7 +257,7 @@
         self.ilasm.opcode(instr, *args)
 
     def call(self, graph, func_name):
-        self.db.pending_graphs.append(graph)
+        self.db.pending_function(graph)
         self.ilasm.call(func_name)
 
     def new(self, obj):

Modified: pypy/dist/pypy/translator/cli/gencli.py
==============================================================================
--- pypy/dist/pypy/translator/cli/gencli.py	(original)
+++ pypy/dist/pypy/translator/cli/gencli.py	Sun Apr  9 14:18:17 2006
@@ -47,41 +47,22 @@
         # methods are rendered twice, once within the class and once
         # as an external function. Fix this.        
         self.gen_entrypoint()
-        self.find_superclasses()
-        self.gen_classes()
-        self.gen_functions()
+        self.gen_pendings()
         self.db.gen_constants(self.ilasm)
+        self.gen_pendings()
         out.close()
         return self.tmpfile.strpath
 
     def gen_entrypoint(self):
         if self.entrypoint:
-            self.db.pending_graphs += self.entrypoint.render(self.ilasm)
+            self.entrypoint.db = self.db
+            self.db.pending_node(self.entrypoint)
         else:
-            self.db.pending_graphs.append(self.translator.graphs[0])
+            self.db.pending_function(self.translator.graphs[0])
 
-        self.gen_functions()
+    def gen_pendings(self):
+        while self.db._pending_nodes:
+            node = self.db._pending_nodes.pop()
+            node.render(self.ilasm)
 
-    def gen_functions(self):
-        while self.db.pending_graphs:
-            graph = self.db.pending_graphs.pop()
-            if self.db.function_name(graph) is None:
-                f = Function(self.db, graph)
-                f.render(self.ilasm)
 
-    def find_superclasses(self):
-        classes = set()
-        pendings = self.db.classes
-
-        while pendings:
-            classdef = pendings.pop()
-            if classdef not in classes and classdef is not None:
-                classes.add(classdef)
-                pendings.add(classdef._superclass)
-
-        self.db.classes = classes
-
-    def gen_classes(self):
-        for classdef in self.db.classes:
-            c = Class(self.db, classdef)
-            c.render(self.ilasm)

Modified: pypy/dist/pypy/translator/cli/metavm.py
==============================================================================
--- pypy/dist/pypy/translator/cli/metavm.py	(original)
+++ pypy/dist/pypy/translator/cli/metavm.py	Sun Apr  9 14:18:17 2006
@@ -84,8 +84,8 @@
 class _SetField(MicroInstruction):
     def render(self, generator, op):
         this, field, value = op.args
-        if field.value == 'meta':
-            return # TODO
+##        if field.value == 'meta':
+##            return # TODO
         
         generator.load(this)
         generator.load(value)

Added: pypy/dist/pypy/translator/cli/test/autopath.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/cli/test/autopath.py	Sun Apr  9 14:18:17 2006
@@ -0,0 +1,112 @@
+"""
+self cloning, automatic path configuration 
+
+copy this into any subdirectory of pypy from which scripts need 
+to be run, typically all of the test subdirs. 
+The idea is that any such script simply issues
+
+    import autopath
+
+and this will make sure that the parent directory containing "pypy"
+is in sys.path. 
+
+If you modify the master "autopath.py" version (in pypy/tool/autopath.py) 
+you can directly run it which will copy itself on all autopath.py files
+it finds under the pypy root directory. 
+
+This module always provides these attributes:
+
+    pypydir    pypy root directory path 
+    this_dir   directory where this autopath.py resides 
+
+"""
+
+
+def __dirinfo(part):
+    """ return (partdir, this_dir) and insert parent of partdir
+    into sys.path.  If the parent directories don't have the part
+    an EnvironmentError is raised."""
+
+    import sys, os
+    try:
+        head = this_dir = os.path.realpath(os.path.dirname(__file__))
+    except NameError:
+        head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0]))
+
+    while head:
+        partdir = head
+        head, tail = os.path.split(head)
+        if tail == part:
+            break
+    else:
+        raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir)
+    
+    pypy_root = os.path.join(head, '')
+    try:
+        sys.path.remove(head)
+    except ValueError:
+        pass
+    sys.path.insert(0, head)
+
+    munged = {}
+    for name, mod in sys.modules.items():
+        fn = getattr(mod, '__file__', None)
+        if '.' in name or not isinstance(fn, str):
+            continue
+        newname = os.path.splitext(os.path.basename(fn))[0]
+        if not newname.startswith(part + '.'):
+            continue
+        path = os.path.join(os.path.dirname(os.path.realpath(fn)), '')
+        if path.startswith(pypy_root) and newname != part:
+            modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep)
+            if newname != '__init__':
+                modpaths.append(newname)
+            modpath = '.'.join(modpaths)
+            if modpath not in sys.modules:
+                munged[modpath] = mod
+
+    for name, mod in munged.iteritems():
+        if name not in sys.modules:
+            sys.modules[name] = mod
+        if '.' in name:
+            prename = name[:name.rfind('.')]
+            postname = name[len(prename)+1:]
+            if prename not in sys.modules:
+                __import__(prename)
+                if not hasattr(sys.modules[prename], postname):
+                    setattr(sys.modules[prename], postname, mod)
+
+    return partdir, this_dir
+
+def __clone():
+    """ clone master version of autopath.py into all subdirs """
+    from os.path import join, walk
+    if not this_dir.endswith(join('pypy','tool')):
+        raise EnvironmentError("can only clone master version "
+                               "'%s'" % join(pypydir, 'tool',_myname))
+
+
+    def sync_walker(arg, dirname, fnames):
+        if _myname in fnames:
+            fn = join(dirname, _myname)
+            f = open(fn, 'rwb+')
+            try:
+                if f.read() == arg:
+                    print "checkok", fn
+                else:
+                    print "syncing", fn
+                    f = open(fn, 'w')
+                    f.write(arg)
+            finally:
+                f.close()
+    s = open(join(pypydir, 'tool', _myname), 'rb').read()
+    walk(pypydir, sync_walker, s)
+
+_myname = 'autopath.py'
+
+# set guaranteed attributes
+
+pypydir, this_dir = __dirinfo('pypy')
+
+if __name__ == '__main__':
+    __clone()

Modified: pypy/dist/pypy/translator/cli/test/compile.py
==============================================================================
--- pypy/dist/pypy/translator/cli/test/compile.py	(original)
+++ pypy/dist/pypy/translator/cli/test/compile.py	Sun Apr  9 14:18:17 2006
@@ -28,25 +28,24 @@
         self.x = x
 
     def compute(self):
-        return self.x + 1
+        return self.x
 
 class Derived(Base):
     def __init__(self, x):
-        Base.__init__(self, x)
+        Base.__init__(self, x+42)
 
-def foo(cls, arg):
-    obj = cls(arg)
-    return obj.compute()
+def foo(cls, x):
+    return cls(x).compute()
 
 def bar(x, y):
-    obj = Base(x)
-    return obj.compute()
+    b = Derived(x)
+    return b.compute()
 #    return foo(Base, x) + foo(Derived, y)
 
 f = compile_function(bar, [int, int])
 
-##try:
-##    pass
-##except py.test.Item.Skipped:
-##    print 'Test skipped'
+try:
+    check(bar, f, 42, 13)
+except py.test.Item.Skipped:
+    print 'Test skipped'
 

Modified: pypy/dist/pypy/translator/cli/test/runtest.py
==============================================================================
--- pypy/dist/pypy/translator/cli/test/runtest.py	(original)
+++ pypy/dist/pypy/translator/cli/test/runtest.py	Sun Apr  9 14:18:17 2006
@@ -7,6 +7,7 @@
 from pypy.translator.translator import TranslationContext
 from pypy.translator.cli.option import getoption
 from pypy.translator.cli.gencli import GenCli
+from pypy.translator.cli.function import Function
 from pypy.translator.cli.node import Node
 from pypy.translator.cli.cts import CTS
 from pypy.translator.cli.database import LowLevelDatabase
@@ -33,6 +34,7 @@
     
     def __init__(self, graph_to_call):
         self.graph = graph_to_call
+        self.db = None
 
     def get_name(self):
         return 'main'
@@ -56,7 +58,7 @@
         ilasm.call('void class [mscorlib]System.Console::WriteLine(%s)' % ret_type)
         ilasm.opcode('ret')
         ilasm.end_function()
-        return [self.graph]
+        self.db.pending_function(self.graph)
 
     def __convert_method(self, arg_type):
         _conv = {
@@ -126,8 +128,10 @@
             return None
 
         self.__check_helper("ilasm")
-        retval = subprocess.call(["ilasm", tmpfile], stdout=subprocess.PIPE)
-        assert retval == 0, 'ilasm failed to assemble %s (%s)' % (self.graph.name, tmpfile)
+        ilasm = subprocess.Popen(["ilasm", tmpfile], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        stdout, stderr = ilasm.communicate()
+        retval = ilasm.wait()
+        assert retval == 0, 'ilasm failed to assemble %s (%s):\n%s' % (self.graph.name, tmpfile, stdout)
         return tmpfile.replace('.il', '.exe')
 
     def __call__(self, *args):

Modified: pypy/dist/pypy/translator/cli/test/test_oo.py
==============================================================================
--- pypy/dist/pypy/translator/cli/test/test_oo.py	(original)
+++ pypy/dist/pypy/translator/cli/test/test_oo.py	Sun Apr  9 14:18:17 2006
@@ -9,6 +9,8 @@
 
 
 class MyClass:
+    INCREMENT = 1
+
     def __init__(self, x, y):
         self.x = x
         self.y = y
@@ -23,7 +25,16 @@
         return x*y
     static_meth = staticmethod(static_meth)
 
+##    def class_meth(cls, x, y):
+##        return x*y + cls.INCREMENT
+##    class_meth = classmethod(class_meth)
+
+    def class_attribute(self):
+        return self.x + self.INCREMENT
+
 class MyDerivedClass(MyClass):
+    INCREMENT = 2
+
     def __init__(self, x, y):
         MyClass.__init__(self, x, y)
 
@@ -56,3 +67,15 @@
     return base.static_meth(x,y) + derived.static_meth(x, y)\
            + MyClass.static_meth(x, y) + MyDerivedClass.static_meth(x, y)
 
+def oo_class_attribute(x, y):
+    base = MyClass(x, y)
+    derived = MyDerivedClass(x, y)
+    return base.class_attribute() + derived.class_attribute()
+
+##def oo_class_meth(x, y):
+##    return MyClass.class_meth(x, y) + MyDerivedClass.class_meth(x, y)
+
+if __name__ == '__main__':
+    from pypy.translator.cli import conftest
+    conftest.option.wd = True    
+    check(oo_liskov, [int, int], (42, 13))



More information about the Pypy-commit mailing list