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

antocuni at codespeak.net antocuni at codespeak.net
Thu May 25 16:42:26 CEST 2006


Author: antocuni
Date: Thu May 25 16:42:15 2006
New Revision: 27669

Modified:
   pypy/dist/pypy/translator/cli/cts.py
   pypy/dist/pypy/translator/cli/database.py
   pypy/dist/pypy/translator/cli/ilgenerator.py
   pypy/dist/pypy/translator/cli/record.py
   pypy/dist/pypy/translator/cli/src/pypylib.cs
   pypy/dist/pypy/translator/cli/test/runtest.py
   pypy/dist/pypy/translator/cli/test/test_runtest.py
Log:
- Added support for tuple constants.

- Added support for function that return tuples in runtest.CliTest,
and some methods for compatibility with OORtypeMixin.




Modified: pypy/dist/pypy/translator/cli/cts.py
==============================================================================
--- pypy/dist/pypy/translator/cli/cts.py	(original)
+++ pypy/dist/pypy/translator/cli/cts.py	Thu May 25 16:42:15 2006
@@ -79,6 +79,8 @@
             return 'void' # TODO: is it correct to ignore StaticMethod?
         elif isinstance(t, ootype.List):
             item_type = self.lltype_to_cts(t._ITEMTYPE)
+            if item_type == 'void': # special case: CLI doesn't allow List of void; use int instead
+                item_type = 'int32'
             return self.__class(PYPY_LIST % item_type, include_class)
         elif isinstance(t, ootype.Dict):
             key_type = self.lltype_to_cts(t._KEYTYPE)

Modified: pypy/dist/pypy/translator/cli/database.py
==============================================================================
--- pypy/dist/pypy/translator/cli/database.py	(original)
+++ pypy/dist/pypy/translator/cli/database.py	Thu May 25 16:42:15 2006
@@ -68,7 +68,7 @@
         return '%s.%s::%s' % (CONST_NAMESPACE, CONST_CLASS, name)
 
     def gen_constants(self, ilasm):
-        if not ilasm . show_const ():
+        if not ilasm.show_const():
             return
         ilasm.begin_namespace(CONST_NAMESPACE)
         ilasm.begin_class(CONST_CLASS)
@@ -83,7 +83,7 @@
         for const, name in self.consts.iteritems():
             const.init(ilasm)
             type_ = const.get_type()
-            ilasm.set_static_field ( type_, CONST_NAMESPACE, CONST_CLASS, name )
+            ilasm.set_static_field (type_, CONST_NAMESPACE, CONST_CLASS, name)
 
         ilasm.ret()
         ilasm.end_function()
@@ -102,10 +102,31 @@
 
         if isinstance(const, ootype._instance):
             return InstanceConst(db, const, static_type)
+        elif isinstance(const, ootype._record):
+            return RecordConst(db, const)
         else:
             assert False, 'Unknown constant: %s' % const
     make = staticmethod(make)
-    
+
+    def load(db, TYPE, value, ilasm):
+        # TODO: code duplicated from function.py, refactoring needed
+        if TYPE is ootype.Void:
+            pass
+        elif TYPE is ootype.Bool:
+            ilasm.opcode('ldc.i4', str(int(value)))
+        elif TYPE is ootype.Float:
+            ilasm.opcode('ldc.r8', repr(value))
+        elif TYPE in (ootype.Signed, ootype.Unsigned):
+            ilasm.opcode('ldc.i4', str(value))
+        elif TYPE in (ootype.SignedLongLong, ootype.UnsignedLongLong):
+            ilasm.opcode('ldc.i8', str(value))
+        else:
+            cts = CTS(db)
+            name = db.record_const(value)
+            cts_type = cts.lltype_to_cts(TYPE)
+            ilasm.opcode('ldsfld %s %s' % (cts_type, name))
+    load = staticmethod(load)
+
     def get_name(self):
         pass
 
@@ -115,6 +136,34 @@
     def init(self, ilasm):
         pass
 
+class RecordConst(AbstractConst):
+    def __init__(self, db, record):
+        self.db = db
+        self.cts = CTS(db)        
+        self.record = record
+
+    def __hash__(self):
+        return hash(self.record)
+
+    def __eq__(self, other):
+        return self.record == other.record
+
+    def get_name(self):
+        return 'Record'
+
+    def get_type(self):
+        return self.cts.lltype_to_cts(self.record._TYPE)
+
+    def init(self, ilasm):
+        class_name = self.record._TYPE._name
+        ilasm.new('instance void class %s::.ctor()' % class_name)
+        for f_name, (FIELD_TYPE, f_default) in self.record._TYPE._fields.iteritems():
+            f_type = self.cts.lltype_to_cts(FIELD_TYPE)
+            value = self.record._items[f_name]
+            ilasm.opcode('dup')
+            AbstractConst.load(self.db, FIELD_TYPE, value, ilasm)            
+            ilasm.set_field((f_type, class_name, f_name))
+
 class InstanceConst(AbstractConst):
     def __init__(self, db, obj, static_type):
         self.cts = CTS(db)

Modified: pypy/dist/pypy/translator/cli/ilgenerator.py
==============================================================================
--- pypy/dist/pypy/translator/cli/ilgenerator.py	(original)
+++ pypy/dist/pypy/translator/cli/ilgenerator.py	Thu May 25 16:42:15 2006
@@ -143,7 +143,7 @@
     def set_field(self, field_data ):
         self.opcode('stfld %s %s::%s' % field_data )
 
-    def get_field(self,field_data):
+    def get_field(self, field_data):
         self.opcode('ldfld %s %s::%s' % field_data )
 
     def load_set_field(self, cts_type, name):
@@ -158,7 +158,7 @@
     def ret(self):
         self.opcode('ret')
 
-    def castclass(self,cts_type):
+    def castclass(self, cts_type):
         self.opcode('castclass', cts_type)
     
     def load_self(self):

Modified: pypy/dist/pypy/translator/cli/record.py
==============================================================================
--- pypy/dist/pypy/translator/cli/record.py	(original)
+++ pypy/dist/pypy/translator/cli/record.py	Thu May 25 16:42:15 2006
@@ -11,8 +11,8 @@
 
         trans = string.maketrans('<>(), ', '______')
         name = ['Record']
-        for f_name, (f_type, f_default) in record._fields.iteritems():
-            type_name = f_type._short_name().translate(trans)
+        for f_name, (FIELD_TYPE, f_default) in record._fields.iteritems():
+            type_name = FIELD_TYPE._short_name().translate(trans)
             name.append(type_name)
         self.name = '__'.join(name)
         record._name = self.name
@@ -36,12 +36,13 @@
         self.ilasm = ilasm
 
         ilasm.begin_class(self.name, self.get_base_class())
-        for f_name, (f_type, f_default) in self.record._fields.iteritems():
-            cts_type = self.cts.lltype_to_cts(f_type)
+        for f_name, (FIELD_TYPE, f_default) in self.record._fields.iteritems():
+            cts_type = self.cts.lltype_to_cts(FIELD_TYPE)
             if cts_type != 'void':
                 ilasm.field(f_name, cts_type)
 
         self._ctor()
+        self._toString()
         ilasm.end_class()
 
         self.db.record_class(self.record, self.name)
@@ -53,3 +54,25 @@
         self.ilasm.opcode('ret')
         self.ilasm.end_function()
         
+    def _toString(self):
+        # only for testing purposes, and only if the Record represents a tuple
+        from pypy.translator.cli.test.runtest import format_object
+
+        for f_name in self.record._fields:
+            if not f_name.startswith('item'):
+                return # it's not a tuple
+
+        self.ilasm.begin_function('ToString', [], 'string', False, 'virtual', 'instance', 'default')
+        self.ilasm.opcode('ldstr', '""')
+        for i in xrange(len(self.record._fields)):
+            f_name = 'item%d' % i
+            FIELD_TYPE, f_default = self.record._fields[f_name]
+            self.ilasm.opcode('ldarg.0')
+            f_type = self.cts.lltype_to_cts(FIELD_TYPE)
+            self.ilasm.get_field((f_type, self.name, f_name))
+            format_object(FIELD_TYPE, self.ilasm)
+            self.ilasm.call('string string::Concat(string, string)')
+            self.ilasm.opcode('ldstr ", "')
+            self.ilasm.call('string string::Concat(string, string)')
+        self.ilasm.opcode('ret')
+        self.ilasm.end_function()

Modified: pypy/dist/pypy/translator/cli/src/pypylib.cs
==============================================================================
--- pypy/dist/pypy/translator/cli/src/pypylib.cs	(original)
+++ pypy/dist/pypy/translator/cli/src/pypylib.cs	Thu May 25 16:42:15 2006
@@ -9,16 +9,6 @@
         public static string ToPython(bool x)   { return x.ToString(); }
         public static string ToPython(double x) { return x.ToString(); }
         public static string ToPython(char x)   { return string.Format("'{0}'", x); }
-        
-        public static string ToPython<T>(pypy.runtime.List<T> lst)
-        {
-            // TODO: use StringBuilder instead
-            string res = "[";
-            foreach(T item in lst)
-                res += item.ToString() + ","; // XXX: only works for int, bool and double
-            res += "]";
-            return res;
-        }
     }
 }
 
@@ -37,6 +27,16 @@
     // rpython.ootypesystem.ootype.List.GENERIC_METHODS
     public class List<T>: System.Collections.Generic.List<T>
     {
+        public override string ToString()
+        {
+            // TODO: use StringBuilder instead
+            string res = "[";
+            foreach(T item in this)
+                res += item.ToString() + ","; // XXX: doesn't work for chars
+            res += "]";
+            return res;
+        }
+
         public int ll_length()
         {
             return this.Count;

Modified: pypy/dist/pypy/translator/cli/test/runtest.py
==============================================================================
--- pypy/dist/pypy/translator/cli/test/runtest.py	(original)
+++ pypy/dist/pypy/translator/cli/test/runtest.py	Thu May 25 16:42:15 2006
@@ -33,6 +33,14 @@
     else:
         assert res1 == res2
 
+def format_object(TYPE, ilasm):
+    if isinstance(TYPE, ootype.BuiltinType):
+        ilasm.call_method('string object::ToString()', virtual=True)
+    else:
+        type_ = cts.lltype_to_cts(TYPE)
+        ilasm.call('string class [pypylib]pypy.test.Result::ToPython(%s)' % type_)
+    
+
 class TestEntryPoint(Node):
     """
     This class produces a 'main' method that converts its arguments
@@ -61,22 +69,13 @@
         ilasm.call(cts.graph_to_signature(self.graph))
 
         # convert result to a string containing a valid python expression
-        var = self.graph.getreturnvar()
-        ilasm.call('string class [pypylib]pypy.test.Result::%s' %
-                   self.__output_method(var.concretetype))
+        TYPE = self.graph.getreturnvar().concretetype
+        format_object(TYPE, ilasm)
         ilasm.call('void class [mscorlib]System.Console::WriteLine(string)')
         ilasm.opcode('ret')
         ilasm.end_function()
         self.db.pending_function(self.graph)
 
-    def __output_method(self, TYPE):
-        if isinstance(TYPE, ootype.List):
-            item_type = cts.lltype_to_cts(TYPE._ITEMTYPE)
-            return 'ToPython<%s> (class [pypylib]pypy.runtime.List`1<!!0>)' % item_type
-        else:
-            type_ = cts.lltype_to_cts(TYPE)
-            return 'ToPython(%s)' % type_
-
     def __convert_method(self, arg_type):
         _conv = {
             'int32': 'ToInt32',
@@ -156,17 +155,18 @@
         retval = mono.wait()
         assert retval == 0, stderr
 
-        return eval(stdout)
-##        ret_type, ret_var = cts.llvar_to_cts(self.graph.getreturnvar())
-##        if 'int' in ret_type:
-##            return int(stdout)
-##        elif ret_type == 'float64':
-##            return float(stdout)
-##        elif ret_type == 'bool':
-##            return stdout.strip().lower() == 'true'
-##        else:
-##            assert False, 'Return type %s is not supported' % ret_type
-
+        res = eval(stdout)
+        if isinstance(res, tuple):
+            res = StructTuple(res) # so tests can access tuple elements with .item0, .item1, etc.
+        return res
+
+class StructTuple(tuple):
+    def __getattr__(self, name):
+        if name.startswith('item'):
+            i = int(name[len('item'):])
+            return self[i]
+        else:
+            raise AttributeError, name
 
 class CliTest(BaseRtypingTest, OORtypeMixin):
     def interpret(self, fn, args):
@@ -177,3 +177,11 @@
     def interpret_raises(exc, func, args):
         py.test.skip("CLI tests don't support interpret_raises")
     
+    def ll_to_string(self, s):
+        py.test.skip('ll_to_string not supported, yet')
+
+    def ll_to_list(self, l):
+        return l
+
+    def class_name(self, value):
+        py.test.skip('class_name not supported, yet')

Modified: pypy/dist/pypy/translator/cli/test/test_runtest.py
==============================================================================
--- pypy/dist/pypy/translator/cli/test/test_runtest.py	(original)
+++ pypy/dist/pypy/translator/cli/test/test_runtest.py	Thu May 25 16:42:15 2006
@@ -25,3 +25,8 @@
         def fn():
             return [1, 2, 3]
         assert self.interpret(fn, []) == [1, 2, 3]
+
+    def test_tuple(self):
+        def fn():
+            return 1, 2
+        assert self.interpret(fn, []) == (1, 2)



More information about the Pypy-commit mailing list