[pypy-svn] r7628 - in pypy/trunk/src/pypy: annotation translator translator/test

mwh at codespeak.net mwh at codespeak.net
Tue Nov 23 18:02:39 CET 2004


Author: mwh
Date: Tue Nov 23 18:02:38 2004
New Revision: 7628

Modified:
   pypy/trunk/src/pypy/annotation/binaryop.py
   pypy/trunk/src/pypy/annotation/factory.py
   pypy/trunk/src/pypy/annotation/model.py
   pypy/trunk/src/pypy/annotation/unaryop.py
   pypy/trunk/src/pypy/translator/annrpython.py
   pypy/trunk/src/pypy/translator/genpyrex.py
   pypy/trunk/src/pypy/translator/test/test_annrpython.py
Log:
Right code, wrong place: bye bye CallableFactory, SomeCallable.

We're well on the way to 

svn mv factory.py bookkeeper.py

as the functionality of CallableFactory is now contained in the Bookkeeper
class.  SomeCallable is borged with SomePBC.

There's a lot of fairly mindless refactoring associated with this.

genpyrex is currently broken.  Probably shallow.

Add assertions that SomeBuiltins are never merged.

Teach annotator about list.pop, list.insert.  This possibly should be
a separate commit, but I'm too lazy for that.

diff gets rather the wrong idea about unaryop.py and factory.py.  What
can you do?


Modified: pypy/trunk/src/pypy/annotation/binaryop.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/binaryop.py	(original)
+++ pypy/trunk/src/pypy/annotation/binaryop.py	Tue Nov 23 18:02:38 2004
@@ -6,8 +6,7 @@
 from pypy.annotation.model import SomeObject, SomeInteger, SomeBool
 from pypy.annotation.model import SomeString, SomeChar, SomeList, SomeDict
 from pypy.annotation.model import SomeTuple, SomeImpossibleValue
-from pypy.annotation.model import SomeInstance, SomeCallable
-from pypy.annotation.model import SomeBuiltin, SomeIterator
+from pypy.annotation.model import SomeInstance, SomeBuiltin, SomeIterator
 from pypy.annotation.model import SomePBC
 from pypy.annotation.model import unionof, set, setunion, missing_operation
 from pypy.annotation.factory import generalize, isclassdef, getbookkeeper
@@ -269,25 +268,27 @@
 
     def union((bltn1, bltn2)):
         if bltn1.analyser != bltn2.analyser:
+            assert False, "merging incompatible builtins == BAD!"
             return SomeObject()
         else:
             s_self = unionof(bltn1.s_self, bltn2.s_self)
             return SomeBuiltin(bltn1.analyser, s_self)
 
-class __extend__(pairtype(SomeCallable, SomeCallable)):
-
-    def union((cal1, cal2)):
-        d = cal1.callables.copy()
-        for cal, classdef in cal2.callables.items():
-            if cal in d:
-                if bool(isclassdef(classdef)) ^ bool(isclassdef(d[cal])):
+class __extend__(pairtype(SomePBC, SomePBC)):
+    def union((pbc1, pbc2)):
+        if isinstance(pbc1, SomeBuiltin) or isinstance(pbc2, SomeBuiltin):
+            assert False, "merging builtin & PBC == BAD!"
+        d = pbc1.prebuiltinstances.copy()
+        for x, classdef in pbc2.prebuiltinstances.items():
+            if x in d:
+                if bool(isclassdef(classdef)) ^ bool(isclassdef(d[x])):
                     raise Exception(
                         "union failed for %r with classdefs %r and %r" % 
-                        (cal, classdef, d[cal]))
+                        (x, classdef, d[x]))
                 if isclassdef(classdef):
-                    classdef = classdef.commonbase(d[cal])
-            d[cal] = classdef
-        return SomeCallable(d)
+                    classdef = classdef.commonbase(d[x])
+            d[x] = classdef
+        return SomePBC(d)
 
 class __extend__(pairtype(SomeImpossibleValue, SomeObject)):
     def union((imp1, obj2)):
@@ -297,12 +298,6 @@
     def union((obj1, imp2)):
         return obj1
 
-
-class __extend__(pairtype(SomePBC, SomePBC)):
-    def union((pbc1, pbc2)):
-        return SomePBC(setunion(pbc1.prebuiltinstances,
-                                pbc2.prebuiltinstances))
-
 class __extend__(pairtype(SomeInstance, SomePBC)):
     def union((ins, pbc)):
         classdef = ins.currentdef().superdef_containing(pbc.knowntype)

Modified: pypy/trunk/src/pypy/annotation/factory.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/factory.py	(original)
+++ pypy/trunk/src/pypy/annotation/factory.py	Tue Nov 23 18:02:38 2004
@@ -126,7 +126,7 @@
                 s_name = self.immutablevalue(x.__name__)
                 result = s_self.getattr(s_name)
             else:
-                result = SomeCallable({x : True})
+                result = SomePBC({x : True})
         elif hasattr(x, '__class__') \
                  and x.__class__.__module__ != '__builtin__':
             if isinstance(x, Cache) and not x.frozen:
@@ -158,77 +158,17 @@
                  t.__module__ != '__builtin__':
             classdef = self.getclassdef(t)
             if self.is_in_an_operation():
-                # woha! instantiating a "mutable" SomeXxx like SomeInstance
-                # is always dangerous, because we need to record this fact
-                # in a factory, to allow reflowing from the current operation
-                # if/when the classdef later changes.
-                factory = self.getfactory(CallableFactory)
-                classdef.instancefactories[factory] = True
+                # woha! instantiating a "mutable" SomeXxx like
+                # SomeInstance is always dangerous, because we need to
+                # allow reflowing from the current operation if/when
+                # the classdef later changes.
+                classdef.instantiation_locations[self.position_key] = True
             return SomeInstance(classdef)
         else:
             o = SomeObject()
             o.knowntype = t
             return o
 
-def getbookkeeper():
-    """Get the current Bookkeeper.
-    Only works during the analysis of an operation."""
-    return getthreadlocals().bookkeeper
-
-
-#
-#  Factories
-#
-
-def generalize(factories, *args):
-    modified = [factory for factory in factories if factory.generalize(*args)]
-    if modified:
-        for factory in modified:
-            factory.bookkeeper.annotator.reflowfromposition(factory.position_key)
-        raise BlockedInference   # reflow now
-
-def isclassdef(x):
-    return isinstance(x, ClassDef)
-
-class ListFactory:
-    s_item = SomeImpossibleValue()
-
-    def __repr__(self):
-        return '%s(s_item=%r)' % (self.__class__.__name__, self.s_item)
-
-    def create(self):
-        return SomeList(factories = {self: True}, s_item = self.s_item)
-
-    def generalize(self, s_new_item):
-        if not self.s_item.contains(s_new_item):
-            self.s_item = unionof(self.s_item, s_new_item)
-            return True
-        else:
-            return False
-
-
-class DictFactory:
-    items = {}
-
-    def __repr__(self):
-        return '%s(items=%r)' % (self.__class__.__name__, self.items)
-
-    def create(self):
-        return SomeDict(factories = {self: True}, items = self.items)
-
-    def generalize(self, key, s_new_value):
-        self.items = self.items.copy()
-        if key not in self.items:
-            self.items[key] = s_new_value
-            return True
-        elif not self.items[key].contains(s_new_value):
-            self.items[key] = unionof(self.items[key], s_new_value)
-            return True
-        else:
-            return False
-
-
-class CallableFactory:
     def pycall(self, func, *args):
         if isinstance(func, (type, ClassType)) and \
             func.__module__ != '__builtin__':
@@ -241,12 +181,14 @@
                     raise Exception, \
                           "unsupported specialization type '%s'"%(x,)
 
-            classdef = self.bookkeeper.getclassdef(cls)
-            classdef.instancefactories[self] = True
+            classdef = self.getclassdef(cls)
+            classdef.instantiation_locations[self.position_key] = True 
             s_instance = SomeInstance(classdef)
             # flow into __init__() if the class has got one
             init = getattr(cls, '__init__', None)
             if init is not None and init != object.__init__:
+                attrdef = classdef.find_attribute('__init__')
+                attrdef.getvalue()
                 self.pycall(init, s_instance, *args)
             else:
                 assert not args, "no __init__ found in %r" % (cls,)
@@ -256,7 +198,7 @@
             func = func.__call__
         if hasattr(func, 'im_func'):
             if func.im_self is not None:
-                s_self = self.bookkeeper.immutablevalue(func.im_self)
+                s_self = self.immutablevalue(func.im_self)
                 args = [s_self] + list(args)
             try:
                 func.im_func.class_ = func.im_class
@@ -286,24 +228,82 @@
             func = self.specialize_by_key(func, len(args),
                                           name='%s__%d' % (func.func_name,
                                                            len(args)))
-        return self.bookkeeper.annotator.recursivecall(func, self, *args)
+        return self.annotator.recursivecall(func, self.position_key, *args)
 
     def specialize_by_key(self, thing, key, name=None):
         key = thing, key
         try:
-            thing = self.bookkeeper.cachespecializations[key]
+            thing = self.cachespecializations[key]
         except KeyError:
             if isinstance(thing, FunctionType):
                 # XXX XXX XXX HAAAAAAAAAAAACK
-                self.bookkeeper.annotator.translator.getflowgraph(thing)
+                self.annotator.translator.getflowgraph(thing)
                 thing = func_with_new_name(thing, name or thing.func_name)
             elif isinstance(thing, (type, ClassType)):
                 assert not "not working yet"
                 thing = type(thing)(name or thing.__name__, (thing,))
             else:
                 raise Exception, "specializing %r?? why??"%thing
-            self.bookkeeper.cachespecializations[key] = thing
+            self.cachespecializations[key] = thing
         return thing
+        
+
+def getbookkeeper():
+    """Get the current Bookkeeper.
+    Only works during the analysis of an operation."""
+    return getthreadlocals().bookkeeper
+
+
+#
+#  Factories
+#
+
+def generalize(factories, *args):
+    modified = [factory for factory in factories if factory.generalize(*args)]
+    if modified:
+        for factory in modified:
+            factory.bookkeeper.annotator.reflowfromposition(factory.position_key)
+        raise BlockedInference   # reflow now
+
+def isclassdef(x):
+    return isinstance(x, ClassDef)
+
+class ListFactory:
+    s_item = SomeImpossibleValue()
+
+    def __repr__(self):
+        return '%s(s_item=%r)' % (self.__class__.__name__, self.s_item)
+
+    def create(self):
+        return SomeList(factories = {self: True}, s_item = self.s_item)
+
+    def generalize(self, s_new_item):
+        if not self.s_item.contains(s_new_item):
+            self.s_item = unionof(self.s_item, s_new_item)
+            return True
+        else:
+            return False
+
+
+class DictFactory:
+    items = {}
+
+    def __repr__(self):
+        return '%s(items=%r)' % (self.__class__.__name__, self.items)
+
+    def create(self):
+        return SomeDict(factories = {self: True}, items = self.items)
+
+    def generalize(self, key, s_new_value):
+        self.items = self.items.copy()
+        if key not in self.items:
+            self.items[key] = s_new_value
+            return True
+        elif not self.items[key].contains(s_new_value):
+            self.items[key] = unionof(self.items[key], s_new_value)
+            return True
+        else:
+            return False
 
 def short_type_name(args):
     l = []
@@ -353,7 +353,7 @@
         self.bookkeeper = bookkeeper
         self.attrs = {}          # {name: Attribute}
         self.revision = 0        # which increases the revision number
-        self.instancefactories = {}
+        self.instantiation_locations = {}
         self.cls = cls
         self.subdefs = {}
         assert (len(cls.__bases__) <= 1 or
@@ -418,11 +418,11 @@
                     pending.append(sub)
                     seen[sub] = True
 
-    def getallfactories(self):
-        factories = {}
+    def getallinstantiations(self):
+        locations = {}
         for clsdef in self.getallsubdefs():
-            factories.update(clsdef.instancefactories)
-        return factories
+            locations.update(clsdef.instantiation_locations)
+        return locations
 
     def _generalize_attr(self, attr, s_value):
         # first remove the attribute from subclasses -- including us!
@@ -444,8 +444,8 @@
         self.attrs[attr] = newattr
 
         # reflow from all factories
-        for factory in self.getallfactories():
-            self.bookkeeper.annotator.reflowfromposition(factory.position_key)
+        for position in self.getallinstantiations():
+            self.bookkeeper.annotator.reflowfromposition(position)
 
     def generalize_attr(self, attr, s_value=None):
         # if the attribute exists in a superclass, generalize there.

Modified: pypy/trunk/src/pypy/annotation/model.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/model.py	(original)
+++ pypy/trunk/src/pypy/annotation/model.py	Tue Nov 23 18:02:38 2004
@@ -151,20 +151,28 @@
         self.knowntype = classdef.cls
         self.revision = classdef.revision
 
+def new_or_old_class(c):
+    if hasattr(c, '__class__'):
+        return c.__class__
+    else:
+        return type(c)
 
-class SomeCallable(SomeObject):
-    """Stands for a (callable) function, method, 
-    prebuiltconstant or class"""
-    def __init__(self, callables):
-        # callables is a dictionary containing concrete python 
-        # callable objects as keys and - in the case of a method - 
-        # the value contains the classdef (see SomeMethod below) 
-        self.callables = callables
-        if len(callables) == 1:
-            self.const, = callables
+class SomePBC(SomeObject):
+    """Stands for a global user instance, built prior to the analysis,
+    or a set of such instances."""
+    def __init__(self, prebuiltinstances):
+        # prebuiltinstances is a dictionary containing concrete python
+        # objects as keys.
+        # if the key is a function, the value can be a classdef to
+        # indicate that it is really a method.
+        self.prebuiltinstances = prebuiltinstances  
+        self.knowntype = reduce(commonbase,
+                                [new_or_old_class(x) for x in prebuiltinstances])
+        if len(prebuiltinstances) == 1:
+            self.const, = prebuiltinstances
 
 
-class SomeBuiltin(SomeCallable):
+class SomeBuiltin(SomePBC):
     "Stands for a built-in function or method with special-cased analysis."
     knowntype = BuiltinFunctionType  # == BuiltinMethodType
     def __init__(self, analyser, s_self=None):
@@ -172,15 +180,6 @@
         self.s_self = s_self
 
 
-class SomePBC(SomeObject):
-    """Stands for a global user instance, built prior to the analysis,
-    or a set of such instances."""
-    def __init__(self, prebuiltinstances):
-        self.prebuiltinstances = prebuiltinstances  
-        self.knowntype = reduce(commonbase,
-                                [x.__class__ for x in prebuiltinstances])
-
-
 class SomeImpossibleValue(SomeObject):
     """The empty set.  Instances are placeholders for objects that
     will never show up at run-time, e.g. elements of an empty list."""

Modified: pypy/trunk/src/pypy/annotation/unaryop.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/unaryop.py	(original)
+++ pypy/trunk/src/pypy/annotation/unaryop.py	Tue Nov 23 18:02:38 2004
@@ -8,11 +8,10 @@
 from pypy.annotation.model import SomeString, SomeChar, SomeList, SomeDict
 from pypy.annotation.model import SomeTuple, SomeImpossibleValue
 from pypy.annotation.model import SomeInstance, SomeBuiltin 
-from pypy.annotation.model import SomeCallable, SomeIterator
-from pypy.annotation.model import SomePBC
+from pypy.annotation.model import SomeIterator, SomePBC
 from pypy.annotation.model import unionof, set, setunion, missing_operation
 from pypy.annotation.factory import BlockedInference, getbookkeeper
-from pypy.annotation.factory import CallableFactory, isclassdef 
+from pypy.annotation.factory import isclassdef 
 
 # convenience only!
 def immutablevalue(x):
@@ -82,12 +81,18 @@
 
 class __extend__(SomeList):
 
-    def method_append(lst, s_item):
-        pair(lst, SomeInteger()).setitem(s_item)
+    def method_append(lst, s_value):
+        pair(lst, SomeInteger()).setitem(s_value)
 
     def method_reverse(lst):
         pass
 
+    def method_insert(lst, s_index, s_value):
+        pair(lst, SomeInteger()).setitem(s_value)
+        
+    def method_pop(lst, s_index=None):
+        return lst.s_item
+
     def iter(lst):
         return SomeIterator(lst.s_item)
 
@@ -144,6 +149,7 @@
             raise BlockedInference
         return
 
+
 class __extend__(SomeBuiltin):
     def simple_call(bltn, *args):
         if bltn.s_self is not None:
@@ -151,26 +157,44 @@
         else:
             return bltn.analyser(*args)
 
-class __extend__(SomeCallable):
-    def simple_call(cal, *args):
-        factory = getbookkeeper().getfactory(CallableFactory) 
+
+class __extend__(SomePBC):
+
+    def getattr(pbc, s_attr):
+        assert s_attr.is_constant()
+        attr = s_attr.const
+        actuals = []
+        
+        for c in pbc.prebuiltinstances:
+            if hasattr(c, attr):
+                actuals.append(immutablevalue(getattr(c, attr)))
+        return unionof(*actuals)
+
+    def setattr(pbc, s_attr, s_value):
+        #raise Exception, "oops!"
+        print "*** WARNING: setattr not wanted on %r" % pbc 
+        pass
+
+    def simple_call(pbc, *args):
+        bookkeeper = getbookkeeper()
         results = []
-        for func, classdef in cal.callables.items():
+        for func, classdef in pbc.prebuiltinstances.items():
             if isclassdef(classdef): 
                 # create s_self and record the creation in the factory
                 s_self = SomeInstance(classdef)
-                classdef.instancefactories[factory] = True
-                results.append(factory.pycall(func, s_self, *args))
+                classdef.instantiation_locations[
+                    bookkeeper.position_key] = True
+                results.append(bookkeeper.pycall(func, s_self, *args))
             else:
-                results.append(factory.pycall(func, *args))
+                results.append(bookkeeper.pycall(func, *args))
         return unionof(*results) 
 
-    def bindcallables(cal, classdef):   
+    def bindcallables(pbc, classdef):   
         """ turn the callables in the given SomeCallable 'cal' 
             into bound versions.
         """
-        d = cal.callables.copy()
-        for func, value in cal.callables.items():
+        d = {}
+        for func, value in pbc.prebuiltinstances.items():
             if isinstance(func, FunctionType): 
                 if isclassdef(value): 
                     print ("!!! rebinding an already bound"
@@ -180,27 +204,5 @@
                 d[func.__get__(43)] = value
             else:
                 d[func] = value 
-        return SomeCallable(d)
-                
-    #def simple_call(fun, *args):
-    #    factory = getbookkeeper().getfactory(CallableFactory)
-    #    results = [factory.pycall(func, *args) for func in fun.funcs]
-    #    return unionof(*results)
-
-
-class __extend__(SomePBC):
+        return SomePBC(d)
 
-    def getattr(pbc, s_attr):
-        assert s_attr.is_constant()
-        attr = s_attr.const
-        actuals = []
-        
-        for c in pbc.prebuiltinstances:
-            if hasattr(c, attr):
-                actuals.append(immutablevalue(getattr(c, attr)))
-        return unionof(*actuals)
-
-    def setattr(pbc, s_attr, s_value):
-        #raise Exception, "oops!"
-        print "*** WARNING: setattr not wanted on %r" % pbc 
-        pass

Modified: pypy/trunk/src/pypy/translator/annrpython.py
==============================================================================
--- pypy/trunk/src/pypy/translator/annrpython.py	(original)
+++ pypy/trunk/src/pypy/translator/annrpython.py	Tue Nov 23 18:02:38 2004
@@ -29,7 +29,7 @@
                                     # records the location of BlockedInference
                                     # exceptions that blocked some blocks.
         self.blocked_functions = {} # set of functions that have blocked blocks
-        self.notify = {}         # {block: {factory-to-invalidate-when-done}}
+        self.notify = {}        # {block: {positions-to-reflow-from-when-done}}
         self.bindingshistory = {}# map Variables to lists of SomeValues
         self.binding_caused_by = {}     # map Variables to Factories
                 # records the FuncCallFactory that caused bindings of inputargs
@@ -168,15 +168,15 @@
 
     #___ interface for annotator.factory _______
 
-    def recursivecall(self, func, factory, *args):
-        parent_fn, parent_block, parent_index = factory.position_key
+    def recursivecall(self, func, position_key, *args):
+        parent_fn, parent_block, parent_index = position_key
         graph = self.translator.getflowgraph(func, parent_fn,
-                                             factory.position_key)
-        # self.notify[graph.returnblock] is a dictionary of
-        # FuncCallFactories (call points to this func) which triggers a
-        # reflow whenever the return block of this graph has been analysed.
-        callfactories = self.notify.setdefault(graph.returnblock, {})
-        callfactories[factory] = True
+                                             position_key)
+        # self.notify[graph.returnblock] is a dictionary of call
+        # points to this func which triggers a reflow whenever the
+        # return block of this graph has been analysed.
+        callpositions = self.notify.setdefault(graph.returnblock, {})
+        callpositions[position_key] = True
         # generalize the function's input arguments
         block = graph.startblock
         inputcells = list(args)
@@ -214,7 +214,7 @@
             for extra in func.func_defaults[-missingargs:]:
                 inputcells.append(self.bookkeeper.immutablevalue(extra))
         inputcells.extend(extracells)
-        self.addpendingblock(func, block, inputcells, factory)
+        self.addpendingblock(func, block, inputcells, position_key)
 
         # get the (current) return value
         v = graph.getreturnvar()
@@ -355,9 +355,9 @@
                 cells.append(cell)
             self.addpendingblock(fn, link.target, cells)
         if block in self.notify:
-            # invalidate some factories when this block is done
-            for factory in self.notify[block]:
-                self.reflowfromposition(factory.position_key)
+            # reflow from certain positions when this block is done
+            for position_key in self.notify[block]:
+                self.reflowfromposition(position_key)
 
 
     #___ creating the annotations based on operations ______

Modified: pypy/trunk/src/pypy/translator/genpyrex.py
==============================================================================
--- pypy/trunk/src/pypy/translator/genpyrex.py	(original)
+++ pypy/trunk/src/pypy/translator/genpyrex.py	Tue Nov 23 18:02:38 2004
@@ -6,7 +6,7 @@
 from pypy.objspace.flow.model import Variable, Constant, UndefinedConstant
 from pypy.objspace.flow.model import mkentrymap, last_exception
 from pypy.translator.annrpython import RPythonAnnotator
-from pypy.annotation.model import SomeCallable
+#from pypy.annotation.model import SomeCallable
 from pypy.annotation.factory import isclassdef
 import inspect
 

Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py
==============================================================================
--- pypy/trunk/src/pypy/translator/test/test_annrpython.py	(original)
+++ pypy/trunk/src/pypy/translator/test/test_annrpython.py	Tue Nov 23 18:02:38 2004
@@ -7,8 +7,6 @@
 from pypy.translator.translator import Translator
 from pypy.objspace.flow.model import *
 
-from pypy.annotation.model import SomeCallable
-
 from pypy.translator.test import snippet
 
 class AnnonateTestCase(testit.IntTestCase):
@@ -318,7 +316,7 @@
         s = a.build_types(snippet.mergefunctions, [int])
         # the test is mostly that the above line hasn't blown up
         # but let's at least check *something*
-        self.assert_(isinstance(s, SomeCallable))
+        self.assert_(isinstance(s, annmodel.SomePBC))
 
     def test_func_calls_func_which_just_raises(self):
         a = RPythonAnnotator()



More information about the Pypy-commit mailing list