[pypy-svn] r24181 - pypy/dist/pypy/translator/squeak

nik at codespeak.net nik at codespeak.net
Thu Mar 9 16:52:20 CET 2006


Author: nik
Date: Thu Mar  9 16:52:18 2006
New Revision: 24181

Modified:
   pypy/dist/pypy/translator/squeak/gensqueak.py
Log:
heavy gensqueak refactoring, breaking up stuff into node classes, in the
spirit of genc. uff, the code finally starts to feel not awkward anymore.


Modified: pypy/dist/pypy/translator/squeak/gensqueak.py
==============================================================================
--- pypy/dist/pypy/translator/squeak/gensqueak.py	(original)
+++ pypy/dist/pypy/translator/squeak/gensqueak.py	Thu Mar  9 16:52:18 2006
@@ -6,6 +6,7 @@
 from pypy.translator.gensupp import NameManager
 from pypy.translator.unsimplify import remove_direct_loops
 from pypy.translator.simplify import simplify_graph
+from pypy.rpython.ootypesystem.ootype import Instance, ROOT
 from pypy import conftest
 try:
     set
@@ -86,118 +87,57 @@
 
 class GenSqueak:
 
+    sqnames = {
+        Constant(None).key:  'nil',
+        Constant(False).key: 'false',
+        Constant(True).key:  'true',
+    }
+    
     def __init__(self, sqdir, translator, modname=None):
         self.sqdir = sqdir
         self.translator = translator
         self.modname = (modname or
                         translator.graphs[0].name)
-        self.sqnames = {
-            Constant(None).key:  'nil',
-            Constant(False).key: 'false',
-            Constant(True).key:  'true',
-        }
+
         self.name_manager = NameManager(number_sep="")
         self.unique_name_mapping = {}
-        self.pendinggraphs = []
-        self.pendingclasses = []
-        self.pendingmethods = []
-        self.pendingsetters = [] # XXX ugly. should generalize methods/setters
-        self.classes = [] 
-        self.methods = [] 
-        self.functions = []
-        self.function_container = False
-
-        t = self.translator
-        graph = t.graphs[0]
-        simplify_graph(graph)
-        remove_direct_loops(t, graph)
-        checkgraph(graph)
+        self.pending_nodes = []
+        self.generated_nodes = set()
 
         if conftest.option.view:
             self.translator.view()
 
-        self.pendinggraphs.append(graph)
+        graph = self.translator.graphs[0]
+        self.pending_nodes.append(FunctionNode(self, graph))
         self.filename = '%s.st' % graph.name
         file = self.sqdir.join(self.filename).open('w')
         self.gen_source(file)
         file.close()
 
-
     def gen_source(self, file):
-        while self.pendinggraphs or self.pendingclasses or self.pendingmethods \
-            or self.pendingsetters:
-            while self.pendinggraphs:
-                graph = self.pendinggraphs.pop()
-                self.gen_function(graph, file)
-            while self.pendingclasses:
-                INST = self.pendingclasses.pop(0)
-                self.gen_class(INST, file)
-            while self.pendingmethods:
-                (INST, method_name) = self.pendingmethods.pop()
-                self.gen_method(INST, method_name, file)
-            while self.pendingsetters:
-                (INST, field_name) = self.pendingsetters.pop()
-                self.gen_setter(INST, field_name, file)
-
-    def gen_fileout_header(self, class_name, category, f):
-        print >> f, "!%s methodsFor: '%s' stamp: 'pypy %s'!" % (
-                class_name, category,
-                datetime.datetime.now().strftime("%m/%d/%Y %H:%M"))
-
-    def gen_class(self, INSTANCE, f):
-        self.classes.append(INSTANCE)
-        print >> f, """%s subclass: #%s
-        instanceVariableNames: '%s'
-        classVariableNames: ''
-        poolDictionaries: ''
-        category: 'PyPy-Test'!
-        """ % (
-            self.nameof_Instance(INSTANCE._superclass), 
-            self.nameof_Instance(INSTANCE),
-            ' '.join(INSTANCE._fields.iterkeys()))
-
-    def gen_method(self, INSTANCE, method_name, f):
-        if (INSTANCE, method_name) in self.methods:
-            return
-        self.methods.append((INSTANCE, method_name))
-        self.gen_fileout_header(self.nameof_Instance(INSTANCE), "methods", f)
-        graph = INSTANCE._methods[method_name].graph
-        self.gen_methodbody(camel_case(method_name), graph, f)
-
-    def gen_setter(self, INSTANCE, field_name, f):
-        if (INSTANCE, field_name) in self.methods:
-            return
-        self.methods.append((INSTANCE, field_name))
-        self.gen_fileout_header(self.nameof_Instance(INSTANCE), "accessors", f)
-        print >> f, "%s: value" % field_name
-        print >> f, "  %s := value" % field_name
-        print >> f, "! !"
-
-    def gen_function(self, graph, f):
-        if not self.function_container:
-            self.gen_function_container(f)
-            self.function_container = True
-        func_name = self.nameof(graph.func)
-        if func_name in self.functions:
-            return
-        self.functions.append(func_name)
-        self.gen_fileout_header("PyFunctions class", "functions", f)
-        self.gen_methodbody(func_name, graph, f)
-
-    def gen_methodbody(self, method_name, graph, f):
-        renderer = MethodBodyRenderer(self, method_name, graph)
-        for line in renderer.render():
+        while self.pending_nodes:
+            node = self.pending_nodes.pop()
+            self.gen_node(node, file)
+
+    def gen_node(self, node, f):
+        for dep in node.dependencies():
+            if dep not in self.generated_nodes:
+                self.pending_nodes.append(node)
+                self.schedule_node(dep)
+                return
+        self.generated_nodes.add(node)
+        for line in node.render():
             print >> f, line
-        print >> f, '! !'
-        print >> f
+        print >> f, ""
+
+    def schedule_node(self, node):
+        if node not in self.generated_nodes:
+            if node in self.pending_nodes:
+                # We move the node to the front so we can enforce
+                # the generation of dependencies.
+                self.pending_nodes.remove(node)
+            self.pending_nodes.append(node)
 
-    def gen_function_container(self, f):
-        print >> f, """Object subclass: #PyFunctions
-            instanceVariableNames: ''
-            classVariableNames: ''
-            poolDictionaries: ''
-            category: 'PyPy'!"""
-        
     def nameof(self, obj):
         key = Constant(obj).key
         try:
@@ -225,7 +165,7 @@
     def nameof_Instance(self, INSTANCE):
         if INSTANCE is None:
             return "Object"
-        self.note_Instance(INSTANCE)
+        self.schedule_node(ClassNode(self, INSTANCE))
         class_name = INSTANCE._name.split(".")[-1]
         squeak_class_name = self.unique_name(INSTANCE, class_name)
         return "Py%s" % squeak_class_name
@@ -240,27 +180,6 @@
         squeak_func_name = self.unique_name(function, function.__name__)
         return squeak_func_name
         
-    def note_Instance(self, inst):
-        if inst not in self.classes:
-            if inst not in self.pendingclasses:
-                if inst._superclass is not None: # not root
-                    # Need to make sure that superclasses appear first in
-                    # the generated source.
-                    self.note_Instance(inst._superclass)
-                self.pendingclasses.append(inst)
-
-    def note_meth(self, inst, meth):
-        bm = (inst, meth)
-        if bm not in self.methods:
-            if bm not in self.pendingmethods:
-                self.pendingmethods.append(bm)
-
-    def note_function(self, function):
-        # 'function' is actually a _static_meth (always?)
-        graph = function.graph
-        if graph not in self.pendinggraphs:
-            self.pendinggraphs.append(graph)
-
     def unique_name(self, key, basename):
         if self.unique_name_mapping.has_key(key):
             unique = self.unique_name_mapping[key]
@@ -270,29 +189,58 @@
             self.unique_name_mapping[key] = unique
         return unique
 
-    def skipped_function(self, func):
-        # debugging only!  Generates a placeholder for missing functions
-        # that raises an exception when called.
-        name = self.unique_name(camel_case('skipped_' + func.__name__))
-        return name
 
+class CodeNode:
+
+    def __hash__(self):
+        return hash(self.hash_key)
+    
+    def __eq__(self, other):
+        return isinstance(other, CodeNode) \
+                and self.hash_key == other.hash_key
+    
+    # XXX need other comparison methods?
 
-class MethodBodyRenderer:
+    def render_fileout_header(self, class_name, category):
+        return "!%s methodsFor: '%s' stamp: 'pypy %s'!" % (
+                class_name, category,
+                datetime.datetime.now().strftime("%m/%d/%Y %H:%M"))
+
+class ClassNode(CodeNode):
 
-    def __init__(self, gen, method_name, graph):
+    def __init__(self, gen, INSTANCE):
         self.gen = gen
-        self.name = method_name
-        self.start = graph.startblock
-        self.loops = LoopFinder(self.start).loops
+        self.INSTANCE = INSTANCE
+        self.hash_key = INSTANCE
+
+    def dependencies(self):
+        if self.INSTANCE._superclass is not None: # not root
+            return [ClassNode(self.gen, self.INSTANCE._superclass)]
+        else:
+            return []
 
     def render(self):
-        args = self.start.inputargs
+        yield "%s subclass: #%s" % (
+            self.gen.nameof_Instance(self.INSTANCE._superclass), 
+            self.gen.nameof_Instance(self.INSTANCE))
+        yield "    instanceVariableNames: '%s'" % \
+            ' '.join(self.INSTANCE._fields.iterkeys())
+        yield "    classVariableNames: ''"
+        yield "    poolDictionaries: ''"
+        yield "    category: 'PyPy-Test'!"
+
+class CallableNode(CodeNode):
+
+    def render_body(self, startblock):
+        self.loops = LoopFinder(startblock).loops
+        args = startblock.inputargs
         sel = Selector(self.name, len(args))
         yield sel.signature([self.expr(v) for v in args])
  
         # XXX should declare local variables here
-        for line in self.render_block(self.start):
+        for line in self.render_block(startblock):
             yield "    %s" % line
+        yield '! !'
 
     def expr(self, v):
         if isinstance(v, Variable):
@@ -310,7 +258,8 @@
             # For now, send nil as the explicit self. XXX will probably have
             # to do something more intelligent.
             args = ["nil"] + args[2:]
-            self.gen.note_meth(op.args[1].concretetype, name)
+            self.gen.schedule_node(
+                    MethodNode(self.gen, op.args[1].concretetype, name))
         elif op.opname == "oogetfield":
             receiver = args[0]
             name = op.args[1].value
@@ -320,14 +269,16 @@
             name = op.args[1].value
             args = args[2:]
             # XXX should only generate setter if field is set from outside
-            self.gen.pendingsetters.append((op.args[0].concretetype, name))
+            self.gen.schedule_node(
+                    SetterNode(self.gen, op.args[0].concretetype, name))
         elif op.opname == "direct_call":
             # XXX not sure if static methods of a specific class should
             # be treated differently.
             receiver = "PyFunctions"
             name = args[0]
             args = args[1:]
-            self.gen.note_function(op.args[0].value)
+            self.gen.schedule_node(
+                FunctionNode(self.gen, op.args[0].value.graph))
         else:
             name = op.opname
             receiver = args[0]
@@ -395,4 +346,57 @@
                     yield "    %s" % line
                 yield "]"
 
+class MethodNode(CallableNode):
+
+    def __init__(self, gen, INSTANCE, method_name):
+        self.gen = gen
+        self.INSTANCE = INSTANCE
+        self.name = method_name
+        self.hash_key = (INSTANCE, method_name)
+
+    def dependencies(self):
+        return [ClassNode(self.gen, self.INSTANCE)]
+
+    def render(self):
+        yield self.render_fileout_header(
+                self.gen.nameof(self.INSTANCE), "methods")
+        graph = self.INSTANCE._methods[self.name].graph
+        for line in self.render_body(graph.startblock):
+            yield line
+
+class FunctionNode(CallableNode):
+    
+    FUNCTIONS = Instance("Functions", ROOT)
+
+    def __init__(self, gen, graph):
+        self.gen = gen
+        self.graph = graph
+        self.name = gen.nameof(graph.func)
+        self.hash_key = graph
+
+    def dependencies(self):
+        return [ClassNode(self.gen, self.FUNCTIONS)]
+
+    def render(self):
+        yield self.render_fileout_header("PyFunctions class", "functions")
+        for line in self.render_body(self.graph.startblock):
+            yield line
+
+class SetterNode(CodeNode):
+
+    def __init__(self, gen, INSTANCE, field_name):
+        self.gen = gen
+        self.INSTANCE = INSTANCE
+        self.field_name = field_name
+        self.hash_key = (INSTANCE, field_name)
+
+    def dependencies(self):
+        return [ClassNode(self.gen, self.INSTANCE)]
+
+    def render(self):
+        yield self.render_fileout_header(
+                self.gen.nameof_Instance(self.INSTANCE), "accessors")
+        yield "%s: value" % self.field_name
+        yield "    %s := value" % self.field_name
+        yield "! !"
 



More information about the Pypy-commit mailing list