[pypy-svn] r33500 - in pypy/dist/pypy: annotation rpython/ootypesystem rpython/ootypesystem/test

antocuni at codespeak.net antocuni at codespeak.net
Fri Oct 20 14:44:58 CEST 2006


Author: antocuni
Date: Fri Oct 20 14:44:55 2006
New Revision: 33500

Modified:
   pypy/dist/pypy/annotation/unaryop.py
   pypy/dist/pypy/rpython/ootypesystem/ootype.py
   pypy/dist/pypy/rpython/ootypesystem/rootype.py
   pypy/dist/pypy/rpython/ootypesystem/test/test_ooann.py
   pypy/dist/pypy/rpython/ootypesystem/test/test_ootype.py
Log:
Support for overloaded bound methods in ootype. This is quite useless
in plain RPython, but it can be exploited by high level backends such
as gencli to expose native classes.



Modified: pypy/dist/pypy/annotation/unaryop.py
==============================================================================
--- pypy/dist/pypy/annotation/unaryop.py	(original)
+++ pypy/dist/pypy/annotation/unaryop.py	Fri Oct 20 14:44:55 2006
@@ -11,7 +11,6 @@
      unionof, set, missing_operation, add_knowntypedata
 from pypy.annotation.bookkeeper import getbookkeeper
 from pypy.annotation import builtin
-
 from pypy.annotation.binaryop import _clone ## XXX where to put this?
 from pypy.rpython import extregistry
 
@@ -705,9 +704,23 @@
 class __extend__(SomeOOBoundMeth):
     def simple_call(m, *args_s):
         inst = m.ootype._example()
-        RESULT = ootype.typeOf(m.ootype._lookup(m.name)[1]).RESULT
+        _, meth = m.ootype._lookup(m.name)
+        if isinstance(meth, ootype._overloaded_meth):
+            ARGS = tuple([m._annotation_to_lltype(arg_s) for arg_s in args_s])
+            METH = meth._resolve_overloading(ARGS)._TYPE
+        else:
+            METH = ootype.typeOf(meth)
+        RESULT = METH.RESULT
         return lltype_to_annotation(RESULT)
 
+    def _annotation_to_lltype(self, ann):
+        if isinstance(ann, SomeChar):
+            return ootype.Char
+        elif isinstance(ann, SomeString):
+            return ootype.String
+        else:
+            return annotation_to_lltype(ann)
+
 class __extend__(SomeOOStaticMeth):
     def simple_call(m, *args_s):
         llargs = [annotation_to_lltype(arg_s)._example() for arg_s in args_s]

Modified: pypy/dist/pypy/rpython/ootypesystem/ootype.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/ootype.py	(original)
+++ pypy/dist/pypy/rpython/ootypesystem/ootype.py	Fri Oct 20 14:44:55 2006
@@ -6,6 +6,11 @@
 from pypy.rpython import objectmodel
 from pypy.tool.uid import uid
 
+try:
+    set
+except NameError:
+    from sets import Set as set
+
 STATICNESS = True
 
 class OOType(LowLevelType):
@@ -732,7 +737,7 @@
         res = getattr(self._inst, name)
         if meth:
             assert isinstance(res, _bound_meth)
-            return _bound_meth(res.DEFINST, _view(res.DEFINST, res.inst), res.meth)
+            return res.__class__(res.DEFINST, _view(res.DEFINST, res.inst), res.meth)
         return res
 
     def _instanceof(self, INSTANCE):
@@ -826,25 +831,84 @@
    def __repr__(self):
        return 'sm %s' % self._name
 
+
+class _bound_meth(object):
+    def __init__(self, DEFINST, inst, meth):
+        self.DEFINST = DEFINST
+        self.inst = inst
+        self.meth = meth
+
+    def __call__(self, *args):
+        callb, checked_args = self.meth._checkargs(args)
+        return callb(self.inst, *checked_args)
+
+
 class _meth(_callable):
-   
+    _bound_class = _bound_meth
+    
     def __init__(self, METHOD, **attrs):
         assert isinstance(METHOD, Meth)
         _callable.__init__(self, METHOD, **attrs)
 
     def _bound(self, DEFINST, inst):
-        assert isinstance(inst, _instance) or isinstance(inst, _builtin_type)
-        return _bound_meth(DEFINST, inst, self)
+        TYPE = typeOf(inst)
+        assert isinstance(TYPE, (Instance, BuiltinType))
+        return self._bound_class(DEFINST, inst, self)
 
-class _bound_meth(object):
+
+class _overloaded_meth_desc:
+    def __init__(self, name, TYPE):
+        self.name = name
+        self.TYPE = TYPE
+
+
+class _overloaded_bound_meth(_bound_meth):
     def __init__(self, DEFINST, inst, meth):
         self.DEFINST = DEFINST
         self.inst = inst
         self.meth = meth
 
+    def _get_bound_meth(self, *args):
+        ARGS = tuple([typeOf(arg) for arg in args])
+        meth = self.meth._resolve_overloading(ARGS)
+        assert isinstance(meth, _meth)
+        return meth._bound(self.DEFINST, self.inst)
+
     def __call__(self, *args):
-       callb, checked_args = self.meth._checkargs(args)
-       return callb(self.inst, *checked_args)
+        bound_meth = self._get_bound_meth(*args)
+        return bound_meth(*args)
+
+
+class _overloaded_meth(_meth):
+    _bound_class = _overloaded_bound_meth
+    
+    def __init__(self, *overloadings, **attrs):
+        assert '_callable' not in attrs
+        _meth.__init__(self, Meth([], Void), _callable=None, **attrs) # use a fake method type
+        self._overloadings = overloadings
+        self._check_overloadings()
+
+    def _check_overloadings(self):
+        signatures = set()
+        for meth in self._overloadings:
+            ARGS = meth._TYPE.ARGS
+            if ARGS in signatures:
+                raise TypeError, 'Bad overloading'
+            signatures.add(ARGS)
+
+    def _resolve_overloading(self, ARGS):
+        for meth in self._overloadings:
+            # check if one of the overloadings has the correct signature
+            # TODO: this algorithm is quite naive, it doesn't handle
+            # automatic conversions
+            METH = meth._TYPE
+            if METH.ARGS == ARGS:
+                return meth
+        raise TypeError, 'No suitable overloading found for method'
+
+    def _get_desc(self, name, ARGS):
+        meth = self._resolve_overloading(ARGS)
+        return _overloaded_meth_desc(name, meth._TYPE)
 
 
 class _builtin_type(object):
@@ -1210,6 +1274,9 @@
 def meth(METHOD, **attrs):
     return _meth(METHOD, **attrs)
 
+def overload(*overloadings, **attrs):
+    return _overloaded_meth(*overloadings, **attrs)
+
 def null(INSTANCE_OR_FUNCTION):
     return INSTANCE_OR_FUNCTION._null
 

Modified: pypy/dist/pypy/rpython/ootypesystem/rootype.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/rootype.py	(original)
+++ pypy/dist/pypy/rpython/ootypesystem/rootype.py	Fri Oct 20 14:44:55 2006
@@ -75,15 +75,21 @@
         v = rpair.rtype_eq(hop)
         return hop.genop("bool_not", [v], resulttype=ootype.Bool)
 
-
 class OOBoundMethRepr(Repr):
     def __init__(self, ootype, name):
         self.lowleveltype = ootype
         self.name = name
 
     def rtype_simple_call(self, hop):
+        TYPE = hop.args_r[0].lowleveltype
+        _, meth = TYPE._lookup(self.name)
+        if isinstance(meth, ootype._overloaded_meth):
+            ARGS = tuple([repr.lowleveltype for repr in hop.args_r[1:]])
+            desc = meth._get_desc(self.name, ARGS)
+            cname = hop.inputconst(Void, desc)
+        else:
+            cname = hop.inputconst(Void, self.name)
         vlist = hop.inputargs(self, *hop.args_r[1:])
-        cname = hop.inputconst(Void, self.name)
         hop.exception_is_here()
         return hop.genop("oosend", [cname]+vlist,
                          resulttype = hop.r_result.lowleveltype)

Modified: pypy/dist/pypy/rpython/ootypesystem/test/test_ooann.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/test/test_ooann.py	(original)
+++ pypy/dist/pypy/rpython/ootypesystem/test/test_ooann.py	Fri Oct 20 14:44:55 2006
@@ -1,3 +1,4 @@
+import py
 from pypy.rpython.ootypesystem.ootype import *
 from pypy.annotation import model as annmodel
 from pypy.objspace.flow import FlowObjSpace
@@ -235,3 +236,39 @@
     a = RPythonAnnotator()
     s = a.build_types(oof, [int, int])
     assert isinstance(s, annmodel.SomeInteger)
+
+def test_overloaded_meth():
+    C = Instance("test", ROOT, {},
+                 {'foo': overload(meth(Meth([Float], Void)),
+                                  meth(Meth([Signed], Signed)),
+                                  meth(Meth([], Float)))})
+    def fn1():
+        return new(C).foo(42.5)
+    def fn2():
+        return new(C).foo(42)
+    def fn3():
+        return new(C).foo()
+    a = RPythonAnnotator()
+    assert a.build_types(fn1, []) is annmodel.s_None
+    assert isinstance(a.build_types(fn2, []), annmodel.SomeInteger)
+    assert isinstance(a.build_types(fn3, []), annmodel.SomeFloat)
+
+def test_overloaded_meth_string():
+    C = Instance("test", ROOT, {},
+                 {'foo': overload(meth(Meth([Char], Signed)),
+                                  meth(Meth([String], Float)))})
+    def fn1():
+        return new(C).foo('a')
+    def fn2():
+        return new(C).foo('aa')
+    a = RPythonAnnotator()
+    assert isinstance(a.build_types(fn1, []), annmodel.SomeInteger)
+    assert isinstance(a.build_types(fn2, []), annmodel.SomeFloat)
+
+def test_bad_overload():
+    def fn():
+        C = Instance("test", ROOT, {},
+                     {'foo': overload(meth(Meth([Signed], Void)),
+                                      meth(Meth([Signed], Signed)))})
+    py.test.raises(TypeError, fn)
+

Modified: pypy/dist/pypy/rpython/ootypesystem/test/test_ootype.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/test/test_ootype.py	(original)
+++ pypy/dist/pypy/rpython/ootypesystem/test/test_ootype.py	Fri Oct 20 14:44:55 2006
@@ -174,6 +174,23 @@
 
     assert c.m(c) == 6
 
+def test_overloaded_method():
+    C = Instance("test", ROOT, {'a': (Signed, 3)})
+    def m1(self, x):
+        return self.a+x
+    def m2(self, x, y):
+        return self.a+x+y
+    def m3(self, x):
+        return self.a*x
+    m = overload(meth(Meth([Signed], Signed), _callable=m1, _name='m'),
+                 meth(Meth([Signed, Signed], Signed), _callable=m2, _name='m'),
+                 meth(Meth([Float], Float), _callable=m3, _name='m'))
+    addMethods(C, {"m": m})
+    c = new(C)
+    assert c.m(1) == 4
+    assert c.m(2, 3) == 8
+    assert c.m(2.0) == 6
+
 def test_explicit_name_clash():
     C = Instance("test", ROOT, {})
 



More information about the Pypy-commit mailing list