[pypy-svn] r37668 - in pypy/dist/pypy/translator/cli: . src test

antocuni at codespeak.net antocuni at codespeak.net
Wed Jan 31 14:41:49 CET 2007


Author: antocuni
Date: Wed Jan 31 14:41:46 2007
New Revision: 37668

Added:
   pypy/dist/pypy/translator/cli/src/support.cs
Modified:
   pypy/dist/pypy/translator/cli/dotnet.py
   pypy/dist/pypy/translator/cli/rte.py
   pypy/dist/pypy/translator/cli/support.py
   pypy/dist/pypy/translator/cli/test/test_dotnet.py
Log:
Add support for casting arbitrary RPython instances to System.Object
using the box() function.

This is very easy in the translated code, but tricky when using Python
for .NET: see also the comment at the end of box().



Modified: pypy/dist/pypy/translator/cli/dotnet.py
==============================================================================
--- pypy/dist/pypy/translator/cli/dotnet.py	(original)
+++ pypy/dist/pypy/translator/cli/dotnet.py	Wed Jan 31 14:41:46 2007
@@ -289,6 +289,20 @@
                  ootype.UnsignedLongLong, ootype.Bool, ootype.Float,
                  ootype.Char, ootype.String]
 
+class BoxedSpace:
+    objects = {}
+    index = 0
+    def put(cls, obj):
+        index = cls.index
+        cls.objects[index] = obj
+        cls.index += 1
+        return index
+    put = classmethod(put)
+
+    def get(cls, index):
+        return cls.objects[index]
+    get = classmethod(get)
+
 def box(x):
     t = type(x)
     if t is int:
@@ -310,12 +324,25 @@
             return CLR.System.String(x)
     elif isinstance(x, PythonNet.System.Object):
         return x
+    elif x is None:
+        return None
     else:
-        assert False
+        # cast RPython instances to System.Object is trivial when
+        # translated but not when interpreting, because Python for
+        # .NET doesn't support passing aribrary Python objects to
+        # .NET. To solve, we store them in the BoxedSpace, then we
+        # return an opaque objects, which will be used by unbox to
+        # retrieve the original RPython instance.
+        index = BoxedSpace.put(x)
+        res = PythonNet.pypy.test.ObjectWrapper(index)
+        return res
 
 def unbox(x, TYPE):
     # TODO: check that x is really of type TYPE
-    
+
+    if isinstance(x, PythonNet.pypy.test.ObjectWrapper):
+        return BoxedSpace.get(x.index)
+
     # this is a workaround against a pythonnet limitation: you can't
     # directly get the, e.g., python int from the System.Int32 object:
     # a simple way to do this is to put it into an ArrayList and
@@ -336,7 +363,7 @@
 
         hop.exception_cannot_occur()
         TYPE = v_obj.concretetype
-        if (TYPE is ootype.String or isinstance(TYPE, NativeInstance)):
+        if (TYPE is ootype.String or isinstance(TYPE, (ootype.Instance, ootype.BuiltinType, NativeInstance))):
             return hop.genop('ooupcast', [v_obj], hop.r_result.lowleveltype)
         else:
             if TYPE not in BOXABLE_TYPES:
@@ -352,12 +379,17 @@
         assert x_s.ootype == CLR.System.Object._INSTANCE
         assert type_s.is_constant()
         TYPE = type_s.const
-        assert TYPE in BOXABLE_TYPES
-        return OverloadingResolver.lltype_to_annotation(TYPE)
+        if isinstance(TYPE, (type, types.ClassType)):
+            # it's a user-defined class, so we return SomeInstance
+            classdef = self.bookkeeper.getuniqueclassdef(TYPE)
+            return SomeInstance(classdef, can_be_None=x_s.can_be_None)
+        else:
+            assert TYPE in BOXABLE_TYPES
+            return OverloadingResolver.lltype_to_annotation(TYPE)
 
     def specialize_call(self, hop):
         v_obj, v_type = hop.inputargs(*hop.args_r)
-        if v_type.value is ootype.String:
+        if v_type.value is ootype.String or isinstance(v_type.value, (type, types.ClassType)):
             return hop.genop('oodowncast', [v_obj], hop.r_result.lowleveltype)
         else:
             return hop.genop('cliunbox', [v_obj, v_type], hop.r_result.lowleveltype)

Modified: pypy/dist/pypy/translator/cli/rte.py
==============================================================================
--- pypy/dist/pypy/translator/cli/rte.py	(original)
+++ pypy/dist/pypy/translator/cli/rte.py	Wed Jan 31 14:41:46 2007
@@ -97,6 +97,11 @@
         Target.compile.im_func(cls, sources, out)
     compile = classmethod(compile)
 
+class Support(Target):
+    SOURCES = ['support.cs']
+    OUTPUT = 'support.dll'
+    FLAGS = ['/t:library']
+
 def get_pypy_dll():
     if os.environ.get('PYPYLIB', '').lower() == 'unix':
         DLL = UnixDLL

Added: pypy/dist/pypy/translator/cli/src/support.cs
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/cli/src/support.cs	Wed Jan 31 14:41:46 2007
@@ -0,0 +1,12 @@
+using System;
+
+namespace pypy.test {
+    public class ObjectWrapper {
+        public int index;
+
+        public ObjectWrapper(int index)
+        {
+            this.index = index;
+        }
+    }
+}

Modified: pypy/dist/pypy/translator/cli/support.py
==============================================================================
--- pypy/dist/pypy/translator/cli/support.py	(original)
+++ pypy/dist/pypy/translator/cli/support.py	Wed Jan 31 14:41:46 2007
@@ -1,12 +1,14 @@
 import py
 from pypy.rpython.ootypesystem import ootype
+from pypy.translator.cli.rte import Support
 
 from pypy.tool.ansi_print import ansi_log
-log = py.log.Producer("cli") 
+log = py.log.Producer("cli")
 py.log.setconsumer("cli", ansi_log) 
 
 try:
     import CLR as PythonNet
+    PythonNet.System.Reflection.Assembly.LoadFile(Support.get())
 except ImportError:
     class _PythonNet:
         __name__ = None

Modified: pypy/dist/pypy/translator/cli/test/test_dotnet.py
==============================================================================
--- pypy/dist/pypy/translator/cli/test/test_dotnet.py	(original)
+++ pypy/dist/pypy/translator/cli/test/test_dotnet.py	Wed Jan 31 14:41:46 2007
@@ -124,6 +124,27 @@
         assert isinstance(s, annmodel.SomeOOInstance)
         assert s.can_be_None == True
 
+    def test_box_instance(self):
+        class Foo:
+            pass
+        def fn():
+            return box(Foo())
+        a = RPythonAnnotator()
+        s = a.build_types(fn, [])
+        assert isinstance(s, annmodel.SomeOOInstance)
+        assert s.ootype._name == '[mscorlib]System.Object'
+
+    def test_unbox_instance(self):
+        class Foo:
+            pass
+        def fn():
+            boxed = box(Foo())
+            return unbox(boxed, Foo)
+        a = RPythonAnnotator()
+        s = a.build_types(fn, [])
+        assert isinstance(s, annmodel.SomeInstance)
+        assert s.classdef.name.endswith('Foo')
+
 
 class TestDotnetRtyping(CliTest):
     def _skip_pythonnet(self, msg):
@@ -314,6 +335,29 @@
         res = self.interpret(fn, [1])
         assert res is None
 
+    def test_box_unbox_instance(self):
+        class Foo:
+            pass
+        def fn():
+            obj = Foo()
+            b_obj = box(obj)
+            obj2 = unbox(b_obj, Foo)
+            return obj is obj2
+        res = self.interpret(fn, [])
+        assert res is True
+
+    def test_instance_wrapping(self):
+        class Foo:
+            pass
+        def fn():
+            obj = Foo()
+            x = ArrayList()
+            x.Add(box(obj))
+            obj2 = unbox(x.get_Item(0), Foo)
+            return obj is obj2
+        res = self.interpret(fn, [])
+        assert res is True
+
 class TestPythonnet(TestDotnetRtyping):
     # don't interpreter functions but execute them directly through pythonnet
     def interpret(self, f, args):



More information about the Pypy-commit mailing list