[pypy-svn] r18724 - in pypy/dist/pypy/rpython: . lltypesystem ootypesystem ootypesystem/test
arigo at codespeak.net
arigo at codespeak.net
Mon Oct 17 20:07:38 CEST 2005
Author: arigo
Date: Mon Oct 17 20:07:36 2005
New Revision: 18724
Modified:
pypy/dist/pypy/rpython/lltypesystem/rclass.py
pypy/dist/pypy/rpython/ootypesystem/rclass.py
pypy/dist/pypy/rpython/ootypesystem/test/test_ooclean.py
pypy/dist/pypy/rpython/rclass.py
pypy/dist/pypy/rpython/rtyper.py
Log:
Support for general class attributes in the ootyper:
* moved the method/not-a-method distinction logic from lltypesystem/ up to
rpython/.
* three dicts: self.allfields, self.allmethods, self.allclassattributes.
* generally attach a graph to the methods in addition to a _callable.
* build an accessor method for each non-constant class attribute (it's a method
that just returns the value that corresponds to the class where the call
arrived).
* annotating low-level helpers in ootypesystem seems to work out of the box in
simple cases (after a minor fix in rtyper.py).
Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/rclass.py (original)
+++ pypy/dist/pypy/rpython/lltypesystem/rclass.py Mon Oct 17 20:07:36 2005
@@ -98,7 +98,10 @@
for name, attrdef in attrs:
if attrdef.readonly:
s_value = attrdef.s_value
- s_value = self.prepare_method(name, s_value, allmethods)
+ s_unboundmethod = self.prepare_method(s_value)
+ if s_unboundmethod is not None:
+ allmethods[name] = True
+ s_value = s_unboundmethod
r = self.rtyper.getrepr(s_value)
mangled_name = 'cls_' + name
clsfields[name] = mangled_name, r
@@ -125,36 +128,6 @@
self.allmethods = allmethods
self.vtable = None
- def prepare_method(self, name, s_value, allmethods):
- # special-casing for methods:
- # - a class (read-only) attribute that would contain a PBC
- # with {func: classdef...} is probably meant to be used as a
- # method, but in corner cases it could be a constant object
- # of type MethodType that just sits here in the class. But
- # as MethodType has a custom __get__ too and we don't support
- # it, it's a very bad idea anyway.
- if isinstance(s_value, annmodel.SomePBC):
- s_value = self.classdef.matching(s_value)
- debound = {}
- count = 0
- for x, classdef in s_value.prebuiltinstances.items():
- if isclassdef(classdef):
- #if classdef.commonbase(self.classdef) != self.classdef:
- # raise TyperError("methods from PBC set %r don't belong "
- # "in %r" % (s_value.prebuiltinstances,
- # self.classdef.cls))
- count += 1
- classdef = True
- debound[x] = classdef
- if count > 0:
- if count != len(s_value.prebuiltinstances):
- raise TyperError("mixing functions and methods "
- "in PBC set %r" % (
- s_value.prebuiltinstances,))
- s_value = annmodel.SomePBC(debound)
- allmethods[name] = True
- return s_value
-
def convert_const(self, value):
if not isinstance(value, (type, types.ClassType)):
raise TyperError("not a class: %r" % (value,))
Modified: pypy/dist/pypy/rpython/ootypesystem/rclass.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/rclass.py (original)
+++ pypy/dist/pypy/rpython/ootypesystem/rclass.py Mon Oct 17 20:07:36 2005
@@ -1,9 +1,10 @@
from pypy.rpython.rmodel import inputconst
from pypy.rpython.rclass import AbstractClassRepr, AbstractInstanceRepr, \
- getinstancerepr
+ getinstancerepr, getclassrepr
from pypy.rpython.rpbc import getsignature
from pypy.rpython.ootypesystem import ootype
from pypy.annotation.pairtype import pairtype
+from pypy.tool.sourcetools import func_with_new_name
CLASSTYPE = ootype.Class
@@ -36,10 +37,13 @@
def _setup_repr(self):
if self.baserepr is not None:
- self.allfields = self.baserepr.allfields.copy()
+ allfields = self.baserepr.allfields.copy()
+ allmethods = self.baserepr.allmethods.copy()
+ allclassattributes = self.baserepr.allclassattributes.copy()
else:
- self.allfields = {}
- self.allmethods = {}
+ allfields = {}
+ allmethods = {}
+ allclassattributes = {}
fields = {}
attrs = self.classdef.attrs.items()
@@ -47,44 +51,89 @@
for name, attrdef in attrs:
if not attrdef.readonly:
repr = self.rtyper.getrepr(attrdef.s_value)
- self.allfields[name] = repr
+ allfields[name] = repr
oot = repr.lowleveltype
fields[name] = oot
ootype.addFields(self.lowleveltype, fields)
methods = {}
+ classattributes = {}
baseInstance = self.lowleveltype._superclass
+ classrepr = getclassrepr(self.rtyper, self.classdef)
for classdef in self.classdef.getmro():
attrs = classdef.attrs.items()
for name, attrdef in attrs:
- if attrdef.readonly:
- try:
- impl = self.classdef.cls.__dict__[name]
- except KeyError:
- pass
- else:
- f, inputs, ret = getsignature(self.rtyper, impl)
- M = ootype.Meth([r.lowleveltype for r in inputs[1:]], ret.lowleveltype)
- m = ootype.meth(M, _name=name, _callable=impl)
- methods[name] = m
+ if not attrdef.readonly:
+ continue
+ try:
+ impl = self.classdef.cls.__dict__[name]
+ except KeyError:
+ continue
+ if classrepr.prepare_method(attrdef.s_value) is not None:
+ # a regular method
+ f, inputs, ret = getsignature(self.rtyper, impl)
+ M = ootype.Meth([r.lowleveltype for r in inputs[1:]], ret.lowleveltype)
+ m = ootype.meth(M, _name=name, _callable=impl,
+ graph=f.graph)
+ methods[name] = m
+ allmethods[name] = True
+ else:
+ # a non-method class attribute
+ allclassattributes[name] = True
+ if not attrdef.s_value.is_constant():
+ classattributes[name] = attrdef.s_value, impl
ootype.addMethods(self.lowleveltype, methods)
-
+ self.allfields = allfields
+ self.allmethods = allmethods
+ self.allclassattributes = allclassattributes
+
+ # step 2: provide accessor methods for class attributes that are
+ # really overridden in subclasses (this is done after the rest of
+ # the initialization because convert_const can require 'self' to
+ # be fully initialized)
+ for name, (s_value, impl) in classattributes.items():
+ r = self.rtyper.getrepr(s_value)
+ oovalue = r.convert_const(impl)
+ m = self.attach_class_attr_accessor(name, oovalue, r.lowleveltype)
+
+ def attach_class_attr_accessor(self, name, oovalue, oovaluetype):
+ def ll_getclassattr(self):
+ return oovalue
+ ll_getclassattr = func_with_new_name(ll_getclassattr, 'll_get_' + name)
+ sm = self.rtyper.annotate_helper(ll_getclassattr, [self.lowleveltype])
+ M = ootype.Meth([], oovaluetype)
+ m = ootype.meth(M, _name=name, _callable=ll_getclassattr,
+ graph=sm.graph)
+ ootype.addMethods(self.lowleveltype, {name: m})
+
def rtype_getattr(self, hop):
vlist = hop.inputargs(self, ootype.Void)
attr = hop.args_s[1].const
s_inst = hop.args_s[0]
- meth = self.lowleveltype._lookup(attr)
- if meth is not None:
+ if attr in self.allfields:
+ # regular instance attributes
+ self.lowleveltype._check_field(attr)
+ return hop.genop("oogetfield", vlist,
+ resulttype = hop.r_result.lowleveltype)
+ elif attr in self.allmethods:
# special case for methods: represented as their 'self' only
# (see MethodsPBCRepr)
return hop.r_result.get_method_from_instance(self, vlist[0],
hop.llops)
- self.lowleveltype._check_field(attr)
- return hop.genop("oogetfield", vlist,
- resulttype = hop.r_result.lowleveltype)
+ elif attr in self.allclassattributes:
+ # class attributes
+ if hop.s_result.is_constant():
+ oovalue = hop.r_result.convert_const(hop.s_result.const)
+ return hop.inputconst(hop.r_result, oovalue)
+ else:
+ cname = hop.inputconst(ootype.Void, attr)
+ return hop.genop("oosend", [cname, vlist[0]],
+ resulttype = hop.r_result.lowleveltype)
+ else:
+ raise TyperError("no attribute %r on %r" % (attr, self))
def rtype_setattr(self, hop):
attr = hop.args_s[1].const
Modified: pypy/dist/pypy/rpython/ootypesystem/test/test_ooclean.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/test/test_ooclean.py (original)
+++ pypy/dist/pypy/rpython/ootypesystem/test/test_ooclean.py Mon Oct 17 20:07:36 2005
@@ -129,3 +129,30 @@
return inst.f()
result = interpret(dummyfn, [], type_system='ootype')
assert result == 3
+
+class HasClassAttr(object):
+ a = 3
+ def f(self, n):
+ return n + self.a
+
+class OverridesClassAttr(HasClassAttr):
+ a = 42
+
+def test_single_class_attr():
+ def dummyfn():
+ inst = HasClassAttr()
+ return inst.f(100)
+ result = interpret(dummyfn, [], type_system='ootype')
+ assert result == 103
+
+def test_class_attr():
+ def dummyfn(flag):
+ if flag:
+ inst = HasClassAttr()
+ else:
+ inst = OverridesClassAttr()
+ return inst.f(100)
+ result = interpret(dummyfn, [True], type_system='ootype')
+ assert result == 103
+ result = interpret(dummyfn, [False], type_system='ootype')
+ assert result == 142
Modified: pypy/dist/pypy/rpython/rclass.py
==============================================================================
--- pypy/dist/pypy/rpython/rclass.py (original)
+++ pypy/dist/pypy/rpython/rclass.py Mon Oct 17 20:07:36 2005
@@ -80,6 +80,35 @@
#
return getclassrepr(self.rtyper, subclassdef).getruntime()
+ def prepare_method(self, s_value):
+ # special-casing for methods:
+ # - a class (read-only) attribute that would contain a PBC
+ # with {func: classdef...} is probably meant to be used as a
+ # method, but in corner cases it could be a constant object
+ # of type MethodType that just sits here in the class. But
+ # as MethodType has a custom __get__ too and we don't support
+ # it, it's a very bad idea anyway.
+ if isinstance(s_value, annmodel.SomePBC):
+ s_value = self.classdef.matching(s_value)
+ debound = {}
+ count = 0
+ for x, classdef in s_value.prebuiltinstances.items():
+ if isclassdef(classdef):
+ #if classdef.commonbase(self.classdef) != self.classdef:
+ # raise TyperError("methods from PBC set %r don't belong "
+ # "in %r" % (s_value.prebuiltinstances,
+ # self.classdef.cls))
+ count += 1
+ classdef = True
+ debound[x] = classdef
+ if count > 0:
+ if count != len(s_value.prebuiltinstances):
+ raise TyperError("mixing functions and methods "
+ "in PBC set %r" % (
+ s_value.prebuiltinstances,))
+ return annmodel.SomePBC(debound)
+ return None # not a method
+
def get_ll_eq_function(self):
return None
Modified: pypy/dist/pypy/rpython/rtyper.py
==============================================================================
--- pypy/dist/pypy/rpython/rtyper.py (original)
+++ pypy/dist/pypy/rpython/rtyper.py Mon Oct 17 20:07:36 2005
@@ -53,7 +53,7 @@
def getconcretetype(v):
return self.bindingrepr(v).lowleveltype
- return LowLevelTypeSystem.instance.getcallable(
+ return self.type_system.getcallable(
self.annotator.translator, graphfunc, getconcretetype)
self.getfunctionptr = getfunctionptr
More information about the Pypy-commit
mailing list