[pypy-svn] r7665 - in pypy/trunk/src/pypy: annotation translator
arigo at codespeak.net
arigo at codespeak.net
Wed Nov 24 21:17:09 CET 2004
Author: arigo
Date: Wed Nov 24 21:17:08 2004
New Revision: 7665
Added:
pypy/trunk/src/pypy/annotation/bookkeeper.py
- copied, changed from r7664, pypy/trunk/src/pypy/annotation/factory.py
pypy/trunk/src/pypy/annotation/classdef.py
- copied, changed from r7664, pypy/trunk/src/pypy/annotation/factory.py
Modified:
pypy/trunk/src/pypy/annotation/binaryop.py
pypy/trunk/src/pypy/annotation/builtin.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
Log:
Don't be impressed by the diff size. This is merely a split of the now rather
large annotation.factory module into three modules:
annotation.factory
annotation.bookkeeper
annotation.classdef
Modified: pypy/trunk/src/pypy/annotation/binaryop.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/binaryop.py (original)
+++ pypy/trunk/src/pypy/annotation/binaryop.py Wed Nov 24 21:17:08 2004
@@ -9,7 +9,9 @@
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
+from pypy.annotation.factory import generalize
+from pypy.annotation.bookkeeper import getbookkeeper
+from pypy.annotation.classdef import isclassdef
from pypy.objspace.flow.model import Constant
# convenience only!
Copied: pypy/trunk/src/pypy/annotation/bookkeeper.py (from r7664, pypy/trunk/src/pypy/annotation/factory.py)
==============================================================================
--- pypy/trunk/src/pypy/annotation/factory.py (original)
+++ pypy/trunk/src/pypy/annotation/bookkeeper.py Wed Nov 24 21:17:08 2004
@@ -1,41 +1,14 @@
"""
-Mutable Objects Factories.
-
-A factory is associated to an SpaceOperation in the source that creates a
-mutable object, currently 'newlist' and 'call' (which can build instances).
-The factory remembers how general an object it has to create here.
+The Bookkeeper class.
"""
-from __future__ import generators
-import new
from types import FunctionType, ClassType, MethodType
from pypy.annotation.model import *
+from pypy.annotation.classdef import ClassDef
from pypy.interpreter.miscutils import getthreadlocals
from pypy.interpreter.pycode import CO_VARARGS
from pypy.tool.hack import func_with_new_name
-def ishashable(x):
- try:
- hash(x)
- except TypeError:
- return False
- else:
- return True
-
-class BlockedInference(Exception):
- """This exception signals the type inference engine that the situation
- is currently blocked, and that it should try to progress elsewhere."""
-
- def __init__(self):
- try:
- self.break_at = getbookkeeper().position_key
- except AttributeError:
- self.break_at = None
-
- def __repr__(self):
- return "<BlockedInference break_at %r>" %(self.break_at,)
- __str__ = __repr__
-
class Bookkeeper:
"""The log of choices that have been made while analysing the operations.
It ensures that the same 'choice objects' will be returned if we ask
@@ -51,6 +24,9 @@
self.userclasseslist = []# userclasses.keys() in creation order
self.cachespecializations = {}
self.pbccache = {}
+ # import ordering hack
+ global BUILTIN_ANALYZERS
+ from pypy.annotation.builtin import BUILTIN_ANALYZERS
def enter(self, position_key):
"""Start of an operation.
@@ -264,57 +240,13 @@
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 ishashable(x):
+ try:
+ hash(x)
+ except TypeError:
+ return False
+ else:
+ return True
def short_type_name(args):
l = []
@@ -325,157 +257,3 @@
name = x.__class__.__name__
l.append(name)
return "__".join(l)
-
-
-class Attribute:
- # readonly-ness
- # SomeThing-ness
- # more potential sources (pbcs or classes) of information
-
- def __init__(self, name, bookkeeper):
- self.name = name
- self.bookkeeper = bookkeeper
- self.sources = {} # source -> None or ClassDef
- # XXX a SomeImpossibleValue() constant? later!!
- self.s_value = SomeImpossibleValue()
- self.readonly = True
-
- def getvalue(self):
- while self.sources:
- source, classdef = self.sources.popitem()
- s_value = self.bookkeeper.immutablevalue(
- source.__dict__[self.name])
- if classdef:
- s_value = s_value.bindcallables(classdef)
- self.s_value = unionof(self.s_value, s_value)
- return self.s_value
-
- def merge(self, other):
- assert self.name == other.name
- self.sources.update(other.sources)
- self.s_value = unionof(self.s_value, other.s_value)
- self.readonly = self.readonly and other.readonly
-
-
-class ClassDef:
- "Wraps a user class."
-
- def __init__(self, cls, bookkeeper):
- self.bookkeeper = bookkeeper
- self.attrs = {} # {name: Attribute}
- self.revision = 0 # which increases the revision number
- self.instantiation_locations = {}
- self.cls = cls
- self.subdefs = {}
- assert (len(cls.__bases__) <= 1 or
- cls.__bases__[1:] == (object,), # for baseobjspace.Wrappable
- "single inheritance only right now: %r" % (cls,))
- if cls.__bases__:
- base = cls.__bases__[0]
- else:
- base = object
- self.basedef = bookkeeper.getclassdef(base)
- if self.basedef:
- self.basedef.subdefs[cls] = self
-
- # collect the (supposed constant) class attributes
- for name, value in cls.__dict__.items():
- # ignore some special attributes
- if name.startswith('_') and not isinstance(value, FunctionType):
- continue
- if isinstance(value, FunctionType):
- value.class_ = cls # remember that this is really a method
- self.add_source_for_attribute(name, cls, self)
-
- def add_source_for_attribute(self, attr, source, clsdef=None):
- self.find_attribute(attr).sources[source] = clsdef
-
- def locate_attribute(self, attr):
- for cdef in self.getmro():
- if attr in cdef.attrs:
- return cdef
- self.generalize_attr(attr)
- return self
-
- def find_attribute(self, attr):
- return self.locate_attribute(attr).attrs[attr]
-
- def __repr__(self):
- return "<ClassDef '%s.%s'>" % (self.cls.__module__, self.cls.__name__)
-
- def commonbase(self, other):
- while other is not None and not issubclass(self.cls, other.cls):
- other = other.basedef
- return other
-
- def superdef_containing(self, cls):
- clsdef = self
- while clsdef is not None and not issubclass(cls, clsdef.cls):
- clsdef = clsdef.basedef
- return clsdef
-
- def getmro(self):
- while self is not None:
- yield self
- self = self.basedef
-
- def getallsubdefs(self):
- pending = [self]
- seen = {}
- for clsdef in pending:
- yield clsdef
- for sub in clsdef.subdefs.values():
- if sub not in seen:
- pending.append(sub)
- seen[sub] = True
-
- def getallinstantiations(self):
- locations = {}
- for clsdef in self.getallsubdefs():
- locations.update(clsdef.instantiation_locations)
- return locations
-
- def _generalize_attr(self, attr, s_value):
- # first remove the attribute from subclasses -- including us!
- subclass_attrs = []
- for subdef in self.getallsubdefs():
- if attr in subdef.attrs:
- subclass_attrs.append(subdef.attrs[attr])
- del subdef.attrs[attr]
- # bump the revision number of this class and all subclasses
- subdef.revision += 1
-
- # do the generalization
- newattr = Attribute(attr, self.bookkeeper)
- if s_value:
- newattr.s_value = s_value
-
- for subattr in subclass_attrs:
- newattr.merge(subattr)
- self.attrs[attr] = newattr
-
- # reflow from all factories
- 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.
- for clsdef in self.getmro():
- if attr in clsdef.attrs:
- clsdef._generalize_attr(attr, s_value)
- else:
- self._generalize_attr(attr, s_value)
-
- def about_attribute(self, name):
- for cdef in self.getmro():
- if name in cdef.attrs:
- s_result = cdef.attrs[name].s_value
- if s_result != SomeImpossibleValue():
- return s_result
- else:
- return None
- return None
-
-
-
-from pypy.annotation.builtin import BUILTIN_ANALYZERS
Modified: pypy/trunk/src/pypy/annotation/builtin.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/builtin.py (original)
+++ pypy/trunk/src/pypy/annotation/builtin.py Wed Nov 24 21:17:08 2004
@@ -4,7 +4,8 @@
from pypy.annotation.model import SomeInteger, SomeObject, SomeChar, SomeBool
from pypy.annotation.model import SomeList, SomeString, SomeTuple
-from pypy.annotation.factory import ListFactory, getbookkeeper
+from pypy.annotation.bookkeeper import getbookkeeper
+from pypy.annotation.factory import ListFactory
from pypy.objspace.flow.model import Constant
import pypy.objspace.std.restricted_int
Copied: pypy/trunk/src/pypy/annotation/classdef.py (from r7664, pypy/trunk/src/pypy/annotation/factory.py)
==============================================================================
--- pypy/trunk/src/pypy/annotation/factory.py (original)
+++ pypy/trunk/src/pypy/annotation/classdef.py Wed Nov 24 21:17:08 2004
@@ -1,330 +1,10 @@
"""
-Mutable Objects Factories.
-
-A factory is associated to an SpaceOperation in the source that creates a
-mutable object, currently 'newlist' and 'call' (which can build instances).
-The factory remembers how general an object it has to create here.
+Type inference for user-defined classes.
"""
from __future__ import generators
-import new
-from types import FunctionType, ClassType, MethodType
-from pypy.annotation.model import *
-from pypy.interpreter.miscutils import getthreadlocals
-from pypy.interpreter.pycode import CO_VARARGS
-from pypy.tool.hack import func_with_new_name
-
-def ishashable(x):
- try:
- hash(x)
- except TypeError:
- return False
- else:
- return True
-
-class BlockedInference(Exception):
- """This exception signals the type inference engine that the situation
- is currently blocked, and that it should try to progress elsewhere."""
-
- def __init__(self):
- try:
- self.break_at = getbookkeeper().position_key
- except AttributeError:
- self.break_at = None
-
- def __repr__(self):
- return "<BlockedInference break_at %r>" %(self.break_at,)
- __str__ = __repr__
-
-class Bookkeeper:
- """The log of choices that have been made while analysing the operations.
- It ensures that the same 'choice objects' will be returned if we ask
- again during reflowing. Like ExecutionContext, there is an implicit
- Bookkeeper that can be obtained from a thread-local variable.
-
- Currently used for factories and user-defined classes."""
-
- def __init__(self, annotator):
- self.annotator = annotator
- self.creationpoints = {} # map position-in-a-block to its Factory
- self.userclasses = {} # map classes to ClassDefs
- self.userclasseslist = []# userclasses.keys() in creation order
- self.cachespecializations = {}
- self.pbccache = {}
-
- def enter(self, position_key):
- """Start of an operation.
- The operation is uniquely identified by the given key."""
- self.position_key = position_key
- getthreadlocals().bookkeeper = self
-
- def leave(self):
- """End of an operation."""
- del getthreadlocals().bookkeeper
- del self.position_key
-
- def is_in_an_operation(self):
- return hasattr(self, 'position_key')
-
- def getfactory(self, factorycls):
- """Get the Factory associated with the current position,
- or build it if it doesn't exist yet."""
- try:
- factory = self.creationpoints[self.position_key]
- except KeyError:
- factory = factorycls()
- factory.bookkeeper = self
- factory.position_key = self.position_key
- self.creationpoints[self.position_key] = factory
- assert isinstance(factory, factorycls)
- return factory
-
- def getclassdef(self, cls):
- """Get the ClassDef associated with the given user cls."""
- if cls is object:
- return None
- try:
- return self.userclasses[cls]
- except KeyError:
- cdef = ClassDef(cls, self)
- self.userclasses[cls] = cdef
- self.userclasseslist.append(cdef)
- return self.userclasses[cls]
-
-
- def immutablevalue(self, x):
- """The most precise SomeValue instance that contains the
- immutable value x."""
- tp = type(x)
- if tp is bool:
- result = SomeBool()
- elif tp is int:
- result = SomeInteger(nonneg = x>=0)
- elif tp is str:
- result = SomeString()
- elif tp is tuple:
- result = SomeTuple(items = [self.immutablevalue(e) for e in x])
- elif tp is list:
- items_s = [self.immutablevalue(e) for e in x]
- result = SomeList({}, unionof(*items_s))
- elif tp is dict: # exactly a dict
- items = {}
- for key, value in x.items():
- items[key] = self.immutablevalue(value)
- result = SomeDict({}, items)
- elif ishashable(x) and x in BUILTIN_ANALYZERS:
- result = SomeBuiltin(BUILTIN_ANALYZERS[x])
- elif callable(x) or isinstance(x, staticmethod): # XXX
- # maybe 'x' is a method bound to a not-yet-frozen cache?
- # fun fun fun.
- if (hasattr(x, 'im_self') and isinstance(x.im_self, Cache)
- and not x.im_self.frozen):
- x.im_self.freeze()
- if hasattr(x, '__self__') and x.__self__ is not None:
- s_self = self.immutablevalue(x.__self__)
- # stop infinite recursion getattr<->immutablevalue
- del s_self.const
- s_name = self.immutablevalue(x.__name__)
- result = s_self.getattr(s_name)
- else:
- return self.getpbc(x)
- elif hasattr(x, '__class__') \
- and x.__class__.__module__ != '__builtin__':
- if isinstance(x, Cache) and not x.frozen:
- x.freeze()
- return self.getpbc(x)
- elif x is None:
- return self.getpbc(None)
- else:
- result = SomeObject()
- result.const = x
- return result
-
- def getpbc(self, x):
- try:
- # this is not just an optimization, but needed to avoid
- # infinitely repeated calls to add_source_for_attribute()
- return self.pbccache[x]
- except KeyError:
- result = SomePBC({x: True}) # pre-built inst
- clsdef = self.getclassdef(new_or_old_class(x))
- for attr in getattr(x, '__dict__', {}):
- clsdef.add_source_for_attribute(attr, x)
- self.pbccache[x] = result
- return result
-
- def valueoftype(self, t):
- """The most precise SomeValue instance that contains all
- objects of type t."""
- if t is bool:
- return SomeBool()
- elif t is int:
- return SomeInteger()
- elif t is str:
- return SomeString()
- elif t is list:
- return SomeList(factories={})
- # can't do dict, tuple
- elif isinstance(t, (type, ClassType)) and \
- 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
- # 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 pycall(self, func, *args):
- if isinstance(func, (type, ClassType)) and \
- func.__module__ != '__builtin__':
- cls = func
- x = getattr(cls, "_specialize_", False)
- if x:
- if x == "location":
- cls = self.specialize_by_key(cls, self.position_key)
- else:
- raise Exception, \
- "unsupported specialization type '%s'"%(x,)
-
- 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,)
- return s_instance
- if hasattr(func, '__call__') and \
- isinstance(func.__call__, MethodType):
- func = func.__call__
- if hasattr(func, 'im_func'):
- if func.im_self is not None:
- s_self = self.immutablevalue(func.im_self)
- args = [s_self] + list(args)
- try:
- func.im_func.class_ = func.im_class
- except AttributeError:
- # probably a builtin function, we don't care to preserve
- # class information then
- pass
- func = func.im_func
- assert isinstance(func, FunctionType), "expected function, got %r"%func
- # do we need to specialize this function in several versions?
- x = getattr(func, '_specialize_', False)
- #if not x:
- # x = 'argtypes'
- if x:
- if x == 'argtypes':
- key = short_type_name(args)
- func = self.specialize_by_key(func, key,
- func.__name__+'__'+key)
- elif x == "location":
- # fully specialize: create one version per call position
- func = self.specialize_by_key(func, self.position_key)
- else:
- raise Exception, "unsupported specialization type '%s'"%(x,)
-
- elif func.func_code.co_flags & CO_VARARGS:
- # calls to *arg functions: create one version per number of args
- func = self.specialize_by_key(func, len(args),
- name='%s__%d' % (func.func_name,
- len(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.cachespecializations[key]
- except KeyError:
- if isinstance(thing, FunctionType):
- # XXX XXX XXX HAAAAAAAAAAAACK
- 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.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 = []
- for x in args:
- if isinstance(x, SomeInstance) and hasattr(x, 'knowntype'):
- name = "SI_" + x.knowntype.__name__
- else:
- name = x.__class__.__name__
- l.append(name)
- return "__".join(l)
+from types import FunctionType
+from pypy.annotation.model import SomeImpossibleValue, unionof
class Attribute:
@@ -477,5 +157,5 @@
return None
-
-from pypy.annotation.builtin import BUILTIN_ANALYZERS
+def isclassdef(x):
+ return isinstance(x, ClassDef)
Modified: pypy/trunk/src/pypy/annotation/factory.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/factory.py (original)
+++ pypy/trunk/src/pypy/annotation/factory.py Wed Nov 24 21:17:08 2004
@@ -2,25 +2,14 @@
Mutable Objects Factories.
A factory is associated to an SpaceOperation in the source that creates a
-mutable object, currently 'newlist' and 'call' (which can build instances).
+built-in mutable object: currently 'newlist' and 'newdict'.
The factory remembers how general an object it has to create here.
"""
-from __future__ import generators
-import new
-from types import FunctionType, ClassType, MethodType
-from pypy.annotation.model import *
-from pypy.interpreter.miscutils import getthreadlocals
-from pypy.interpreter.pycode import CO_VARARGS
-from pypy.tool.hack import func_with_new_name
-
-def ishashable(x):
- try:
- hash(x)
- except TypeError:
- return False
- else:
- return True
+from pypy.annotation.model import SomeList, SomeDict
+from pypy.annotation.model import SomeImpossibleValue, unionof
+from pypy.annotation.bookkeeper import getbookkeeper
+
class BlockedInference(Exception):
"""This exception signals the type inference engine that the situation
@@ -36,248 +25,6 @@
return "<BlockedInference break_at %r>" %(self.break_at,)
__str__ = __repr__
-class Bookkeeper:
- """The log of choices that have been made while analysing the operations.
- It ensures that the same 'choice objects' will be returned if we ask
- again during reflowing. Like ExecutionContext, there is an implicit
- Bookkeeper that can be obtained from a thread-local variable.
-
- Currently used for factories and user-defined classes."""
-
- def __init__(self, annotator):
- self.annotator = annotator
- self.creationpoints = {} # map position-in-a-block to its Factory
- self.userclasses = {} # map classes to ClassDefs
- self.userclasseslist = []# userclasses.keys() in creation order
- self.cachespecializations = {}
- self.pbccache = {}
-
- def enter(self, position_key):
- """Start of an operation.
- The operation is uniquely identified by the given key."""
- self.position_key = position_key
- getthreadlocals().bookkeeper = self
-
- def leave(self):
- """End of an operation."""
- del getthreadlocals().bookkeeper
- del self.position_key
-
- def is_in_an_operation(self):
- return hasattr(self, 'position_key')
-
- def getfactory(self, factorycls):
- """Get the Factory associated with the current position,
- or build it if it doesn't exist yet."""
- try:
- factory = self.creationpoints[self.position_key]
- except KeyError:
- factory = factorycls()
- factory.bookkeeper = self
- factory.position_key = self.position_key
- self.creationpoints[self.position_key] = factory
- assert isinstance(factory, factorycls)
- return factory
-
- def getclassdef(self, cls):
- """Get the ClassDef associated with the given user cls."""
- if cls is object:
- return None
- try:
- return self.userclasses[cls]
- except KeyError:
- cdef = ClassDef(cls, self)
- self.userclasses[cls] = cdef
- self.userclasseslist.append(cdef)
- return self.userclasses[cls]
-
-
- def immutablevalue(self, x):
- """The most precise SomeValue instance that contains the
- immutable value x."""
- tp = type(x)
- if tp is bool:
- result = SomeBool()
- elif tp is int:
- result = SomeInteger(nonneg = x>=0)
- elif tp is str:
- result = SomeString()
- elif tp is tuple:
- result = SomeTuple(items = [self.immutablevalue(e) for e in x])
- elif tp is list:
- items_s = [self.immutablevalue(e) for e in x]
- result = SomeList({}, unionof(*items_s))
- elif tp is dict: # exactly a dict
- items = {}
- for key, value in x.items():
- items[key] = self.immutablevalue(value)
- result = SomeDict({}, items)
- elif ishashable(x) and x in BUILTIN_ANALYZERS:
- result = SomeBuiltin(BUILTIN_ANALYZERS[x])
- elif callable(x) or isinstance(x, staticmethod): # XXX
- # maybe 'x' is a method bound to a not-yet-frozen cache?
- # fun fun fun.
- if (hasattr(x, 'im_self') and isinstance(x.im_self, Cache)
- and not x.im_self.frozen):
- x.im_self.freeze()
- if hasattr(x, '__self__') and x.__self__ is not None:
- s_self = self.immutablevalue(x.__self__)
- # stop infinite recursion getattr<->immutablevalue
- del s_self.const
- s_name = self.immutablevalue(x.__name__)
- result = s_self.getattr(s_name)
- else:
- return self.getpbc(x)
- elif hasattr(x, '__class__') \
- and x.__class__.__module__ != '__builtin__':
- if isinstance(x, Cache) and not x.frozen:
- x.freeze()
- return self.getpbc(x)
- elif x is None:
- return self.getpbc(None)
- else:
- result = SomeObject()
- result.const = x
- return result
-
- def getpbc(self, x):
- try:
- # this is not just an optimization, but needed to avoid
- # infinitely repeated calls to add_source_for_attribute()
- return self.pbccache[x]
- except KeyError:
- result = SomePBC({x: True}) # pre-built inst
- clsdef = self.getclassdef(new_or_old_class(x))
- for attr in getattr(x, '__dict__', {}):
- clsdef.add_source_for_attribute(attr, x)
- self.pbccache[x] = result
- return result
-
- def valueoftype(self, t):
- """The most precise SomeValue instance that contains all
- objects of type t."""
- if t is bool:
- return SomeBool()
- elif t is int:
- return SomeInteger()
- elif t is str:
- return SomeString()
- elif t is list:
- return SomeList(factories={})
- # can't do dict, tuple
- elif isinstance(t, (type, ClassType)) and \
- 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
- # 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 pycall(self, func, *args):
- if isinstance(func, (type, ClassType)) and \
- func.__module__ != '__builtin__':
- cls = func
- x = getattr(cls, "_specialize_", False)
- if x:
- if x == "location":
- cls = self.specialize_by_key(cls, self.position_key)
- else:
- raise Exception, \
- "unsupported specialization type '%s'"%(x,)
-
- 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,)
- return s_instance
- if hasattr(func, '__call__') and \
- isinstance(func.__call__, MethodType):
- func = func.__call__
- if hasattr(func, 'im_func'):
- if func.im_self is not None:
- s_self = self.immutablevalue(func.im_self)
- args = [s_self] + list(args)
- try:
- func.im_func.class_ = func.im_class
- except AttributeError:
- # probably a builtin function, we don't care to preserve
- # class information then
- pass
- func = func.im_func
- assert isinstance(func, FunctionType), "expected function, got %r"%func
- # do we need to specialize this function in several versions?
- x = getattr(func, '_specialize_', False)
- #if not x:
- # x = 'argtypes'
- if x:
- if x == 'argtypes':
- key = short_type_name(args)
- func = self.specialize_by_key(func, key,
- func.__name__+'__'+key)
- elif x == "location":
- # fully specialize: create one version per call position
- func = self.specialize_by_key(func, self.position_key)
- else:
- raise Exception, "unsupported specialization type '%s'"%(x,)
-
- elif func.func_code.co_flags & CO_VARARGS:
- # calls to *arg functions: create one version per number of args
- func = self.specialize_by_key(func, len(args),
- name='%s__%d' % (func.func_name,
- len(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.cachespecializations[key]
- except KeyError:
- if isinstance(thing, FunctionType):
- # XXX XXX XXX HAAAAAAAAAAAACK
- 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.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()
@@ -316,166 +63,14 @@
else:
return False
-def short_type_name(args):
- l = []
- for x in args:
- if isinstance(x, SomeInstance) and hasattr(x, 'knowntype'):
- name = "SI_" + x.knowntype.__name__
- else:
- name = x.__class__.__name__
- l.append(name)
- return "__".join(l)
-
-
-class Attribute:
- # readonly-ness
- # SomeThing-ness
- # more potential sources (pbcs or classes) of information
-
- def __init__(self, name, bookkeeper):
- self.name = name
- self.bookkeeper = bookkeeper
- self.sources = {} # source -> None or ClassDef
- # XXX a SomeImpossibleValue() constant? later!!
- self.s_value = SomeImpossibleValue()
- self.readonly = True
-
- def getvalue(self):
- while self.sources:
- source, classdef = self.sources.popitem()
- s_value = self.bookkeeper.immutablevalue(
- source.__dict__[self.name])
- if classdef:
- s_value = s_value.bindcallables(classdef)
- self.s_value = unionof(self.s_value, s_value)
- return self.s_value
-
- def merge(self, other):
- assert self.name == other.name
- self.sources.update(other.sources)
- self.s_value = unionof(self.s_value, other.s_value)
- self.readonly = self.readonly and other.readonly
-
-
-class ClassDef:
- "Wraps a user class."
-
- def __init__(self, cls, bookkeeper):
- self.bookkeeper = bookkeeper
- self.attrs = {} # {name: Attribute}
- self.revision = 0 # which increases the revision number
- self.instantiation_locations = {}
- self.cls = cls
- self.subdefs = {}
- assert (len(cls.__bases__) <= 1 or
- cls.__bases__[1:] == (object,), # for baseobjspace.Wrappable
- "single inheritance only right now: %r" % (cls,))
- if cls.__bases__:
- base = cls.__bases__[0]
- else:
- base = object
- self.basedef = bookkeeper.getclassdef(base)
- if self.basedef:
- self.basedef.subdefs[cls] = self
-
- # collect the (supposed constant) class attributes
- for name, value in cls.__dict__.items():
- # ignore some special attributes
- if name.startswith('_') and not isinstance(value, FunctionType):
- continue
- if isinstance(value, FunctionType):
- value.class_ = cls # remember that this is really a method
- self.add_source_for_attribute(name, cls, self)
-
- def add_source_for_attribute(self, attr, source, clsdef=None):
- self.find_attribute(attr).sources[source] = clsdef
-
- def locate_attribute(self, attr):
- for cdef in self.getmro():
- if attr in cdef.attrs:
- return cdef
- self.generalize_attr(attr)
- return self
-
- def find_attribute(self, attr):
- return self.locate_attribute(attr).attrs[attr]
-
- def __repr__(self):
- return "<ClassDef '%s.%s'>" % (self.cls.__module__, self.cls.__name__)
-
- def commonbase(self, other):
- while other is not None and not issubclass(self.cls, other.cls):
- other = other.basedef
- return other
-
- def superdef_containing(self, cls):
- clsdef = self
- while clsdef is not None and not issubclass(cls, clsdef.cls):
- clsdef = clsdef.basedef
- return clsdef
-
- def getmro(self):
- while self is not None:
- yield self
- self = self.basedef
-
- def getallsubdefs(self):
- pending = [self]
- seen = {}
- for clsdef in pending:
- yield clsdef
- for sub in clsdef.subdefs.values():
- if sub not in seen:
- pending.append(sub)
- seen[sub] = True
-
- def getallinstantiations(self):
- locations = {}
- for clsdef in self.getallsubdefs():
- locations.update(clsdef.instantiation_locations)
- return locations
-
- def _generalize_attr(self, attr, s_value):
- # first remove the attribute from subclasses -- including us!
- subclass_attrs = []
- for subdef in self.getallsubdefs():
- if attr in subdef.attrs:
- subclass_attrs.append(subdef.attrs[attr])
- del subdef.attrs[attr]
- # bump the revision number of this class and all subclasses
- subdef.revision += 1
-
- # do the generalization
- newattr = Attribute(attr, self.bookkeeper)
- if s_value:
- newattr.s_value = s_value
-
- for subattr in subclass_attrs:
- newattr.merge(subattr)
- self.attrs[attr] = newattr
-
- # reflow from all factories
- 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.
- for clsdef in self.getmro():
- if attr in clsdef.attrs:
- clsdef._generalize_attr(attr, s_value)
- else:
- self._generalize_attr(attr, s_value)
-
- def about_attribute(self, name):
- for cdef in self.getmro():
- if name in cdef.attrs:
- s_result = cdef.attrs[name].s_value
- if s_result != SomeImpossibleValue():
- return s_result
- else:
- return None
- return None
-
-
-from pypy.annotation.builtin import BUILTIN_ANALYZERS
+def generalize(factories, *args):
+ """Signals all the factories in the given set to generalize themselves.
+ The args must match the signature of the generalize() method of the
+ particular factories (which should all be of the same class).
+ """
+ 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
Modified: pypy/trunk/src/pypy/annotation/model.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/model.py (original)
+++ pypy/trunk/src/pypy/annotation/model.py Wed Nov 24 21:17:08 2004
@@ -60,7 +60,8 @@
def __new__(cls, *args, **kw):
self = super(SomeObject, cls).__new__(cls, *args, **kw)
try:
- position_key = pypy.annotation.factory.getbookkeeper().position_key
+ bookkeeper = pypy.annotation.bookkeeper.getbookkeeper()
+ position_key = bookkeeper.position_key
except AttributeError:
pass
else:
@@ -240,4 +241,3 @@
# this has the side-effect of registering the unary and binary operations
from pypy.annotation.unaryop import UNARY_OPERATIONS
from pypy.annotation.binaryop import BINARY_OPERATIONS
-from pypy.annotation.builtin import BUILTIN_ANALYZERS
Modified: pypy/trunk/src/pypy/annotation/unaryop.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/unaryop.py (original)
+++ pypy/trunk/src/pypy/annotation/unaryop.py Wed Nov 24 21:17:08 2004
@@ -10,8 +10,9 @@
from pypy.annotation.model import SomeInstance, SomeBuiltin
from pypy.annotation.model import SomeIterator, SomePBC, new_or_old_class
from pypy.annotation.model import unionof, set, setunion, missing_operation
-from pypy.annotation.factory import BlockedInference, getbookkeeper
-from pypy.annotation.factory import isclassdef
+from pypy.annotation.factory import BlockedInference
+from pypy.annotation.bookkeeper import getbookkeeper
+from pypy.annotation.classdef import isclassdef
# convenience only!
def immutablevalue(x):
Modified: pypy/trunk/src/pypy/translator/annrpython.py
==============================================================================
--- pypy/trunk/src/pypy/translator/annrpython.py (original)
+++ pypy/trunk/src/pypy/translator/annrpython.py Wed Nov 24 21:17:08 2004
@@ -3,8 +3,8 @@
from types import FunctionType, ClassType
from pypy.annotation import model as annmodel
from pypy.annotation.model import pair
-from pypy.annotation.factory import ListFactory, DictFactory
-from pypy.annotation.factory import BlockedInference, Bookkeeper
+from pypy.annotation.factory import ListFactory, DictFactory, BlockedInference
+from pypy.annotation.bookkeeper import Bookkeeper
from pypy.objspace.flow.model import Variable, Constant, UndefinedConstant
from pypy.objspace.flow.model import SpaceOperation, FunctionGraph
from pypy.objspace.flow.model import last_exception, last_exc_value
Modified: pypy/trunk/src/pypy/translator/genpyrex.py
==============================================================================
--- pypy/trunk/src/pypy/translator/genpyrex.py (original)
+++ pypy/trunk/src/pypy/translator/genpyrex.py Wed Nov 24 21:17:08 2004
@@ -7,7 +7,7 @@
from pypy.objspace.flow.model import mkentrymap, last_exception
from pypy.translator.annrpython import RPythonAnnotator
from pypy.annotation.model import SomePBC
-from pypy.annotation.factory import isclassdef
+from pypy.annotation.classdef import isclassdef
import inspect
class Op:
More information about the Pypy-commit
mailing list