[pypy-svn] r46018 - in pypy/branch/pypy-more-rtti-inprogress: rpython/module rpython/ootypesystem/module translator/cli/test

arigo at codespeak.net arigo at codespeak.net
Mon Aug 27 13:46:53 CEST 2007


Author: arigo
Date: Mon Aug 27 13:46:51 2007
New Revision: 46018

Added:
   pypy/branch/pypy-more-rtti-inprogress/rpython/module/r_os_stat.py   (contents, props changed)
Modified:
   pypy/branch/pypy-more-rtti-inprogress/rpython/module/ll_os_stat.py
   pypy/branch/pypy-more-rtti-inprogress/rpython/ootypesystem/module/ll_os.py
   pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_builtin.py
Log:
Custom annotation and rtyping support for os.stat_result objects.
They are rtyped just like a tuple of the correct length supporting
only indexing and the st_xxx attributes.  We need a custom StatResultRepr
because when rtyping for LL backends we have extra platform-dependent
items at the end of the tuple, but for OO backends we only want the
portable items.  This allows the OO backends to assume a fixed shape for
the tuples returned by os.stat().

The gencli os.stat() tests pass.


Modified: pypy/branch/pypy-more-rtti-inprogress/rpython/module/ll_os_stat.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/rpython/module/ll_os_stat.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/rpython/module/ll_os_stat.py	Mon Aug 27 13:46:51 2007
@@ -4,36 +4,27 @@
 """
 import os, sys
 from pypy.annotation import model as annmodel
+from pypy.annotation.pairtype import pairtype
 from pypy.tool.sourcetools import func_with_new_name
-from pypy.rpython.controllerentry import Controller, SomeControlledInstance
+from pypy.rpython import extregistry
 from pypy.rpython.extfunc import register_external
 from pypy.rpython.lltypesystem import rffi, lltype
 
-if sys.platform.startswith('win'):
-    # XXX on Windows, stat() is flawed; see CPython's posixmodule.c for
-    # an implementation based on the Win32 API
-    LongLongIfNotWindows = lltype.Signed
-else:
-    LongLongIfNotWindows = lltype.SignedLongLong
+# XXX on Windows, stat() is flawed; see CPython's posixmodule.c for
+# an implementation based on the Win32 API
 
-# NOTE: float times are disabled for now, for compatibility with CPython
-if 0:  #sys.platform.startswith('linux2'):
-    # XXX assume the tv_nsec way of accessing the sub-second timestamps
-    # XXX also assume, as in Linux, that it's in a 'struct timespec'
-    TIMESPEC = rffi.CStructPtr('timespec',
-                               ('tv_sec', lltype.Signed),
-                               ('tv_nsec', lltype.Signed))
-    ModTime = rffi.DOUBLE
-else:
-    # XXX add support for more platforms
-    TIMESPEC = None
-    ModTime = lltype.Signed
+# NOTE: float times are disabled for now, for simplicity.  They make the life
+# of OO backends more complicated because for them we try to not depend on
+# the details of the platform on which we do the translation.  Also, they
+# seem not essential because they are disabled by default in CPython.
+TIMESPEC = None
+ModTime = lltype.Signed
 
 # all possible fields - some of them are not available on all platforms
 ALL_STAT_FIELDS = [
     ("st_mode",      lltype.Signed),
     ("st_ino",       lltype.SignedLongLong),
-    ("st_dev",       LongLongIfNotWindows),
+    ("st_dev",       lltype.SignedLongLong),
     ("st_nlink",     lltype.Signed),
     ("st_uid",       lltype.Signed),
     ("st_gid",       lltype.Signed),
@@ -61,6 +52,7 @@
 
 def _expand(lst, originalname, timespecname):
     if TIMESPEC is not None:
+        XXX # code not used right now
         for i, (_name, _TYPE) in enumerate(lst):
             if _name == originalname:
                 # replace the 'st_atime' field of type rffi.DOUBLE
@@ -75,40 +67,56 @@
 
 del _expand, _name, _TYPE
 
+# For OO backends, expose only the portable fields (the first 10).
+PORTABLE_STAT_FIELDS = STAT_FIELDS[:N_INDEXABLE_FIELDS]
+
 # ____________________________________________________________
 #
 # Annotation support
 
-class StatResultController(Controller):
-    """Controls a stat_result object in RPython: internally it is just a
-    tuple, but the Controller adds the support for the st_xxx attributes.
-    """
+class SomeStatResult(annmodel.SomeObject):
     knowntype = os.stat_result
 
-    def getitem(self, obj, index):
-        if 0 <= index < N_INDEXABLE_FIELDS:
-            return obj[index]
-        else:
-            raise IndexError
-    getitem._annspecialcase_ = 'specialize:arg(2)'   # 'index' must be constant
-
-    def install_getter(cls, name):
-        # def get_st_mode(), def get_st_ino(), etc...
-        index = STAT_FIELD_NAMES.index(name)
-        def get_st_xxx(self, obj):
-            return obj[index]
-        method_name = 'get_%s' % (name,)
-        setattr(cls, method_name, func_with_new_name(get_st_xxx, method_name))
-    install_getter = classmethod(install_getter)
-
-for _name in STAT_FIELD_NAMES:
-    StatResultController.install_getter(_name)
-
-stat_controller = StatResultController()
-s_tuple_StatResult = annmodel.SomeTuple([annmodel.lltype_to_annotation(_TYPE)
-                                         for _name, _TYPE in STAT_FIELDS])
-s_StatResult = SomeControlledInstance(s_tuple_StatResult,
-                                      controller = stat_controller)
+    def rtyper_makerepr(self, rtyper):
+        from pypy.rpython.module import r_os_stat
+        return r_os_stat.StatResultRepr(rtyper)
+
+    def rtyper_makekey_ex(self, rtyper):
+        return self.__class__,
+
+    def getattr(self, s_attr):
+        assert s_attr.is_constant(), "non-constant attr name in getattr()"
+        attrname = s_attr.const
+        TYPE = STAT_FIELD_TYPES[attrname]
+        return annmodel.lltype_to_annotation(TYPE)
+
+class __extend__(pairtype(SomeStatResult, annmodel.SomeInteger)):
+    def getitem((s_sta, s_int)):
+        assert s_int.is_constant(), "os.stat()[index]: index must be constant"
+        index = s_int.const
+        assert 0 <= index < N_INDEXABLE_FIELDS, "os.stat()[index] out of range"
+        name, TYPE = STAT_FIELDS[index]
+        return annmodel.lltype_to_annotation(TYPE)
+
+s_StatResult = SomeStatResult()
+
+def make_stat_result(tup):
+    """Turn a tuple into an os.stat_result object."""
+    positional = tup[:N_INDEXABLE_FIELDS]
+    kwds = {}
+    for i, name in enumerate(STAT_FIELD_NAMES[N_INDEXABLE_FIELDS:]):
+        kwds[name] = tup[N_INDEXABLE_FIELDS + i]
+    return os.stat_result(positional, kwds)
+
+class MakeStatResultEntry(extregistry.ExtRegistryEntry):
+    _about_ = make_stat_result
+
+    def compute_result_annotation(self, s_tup):
+        return s_StatResult
+
+    def specialize_call(self, hop):
+        from pypy.rpython.module import r_os_stat
+        return r_os_stat.specialize_make_stat_result(hop)
 
 # ____________________________________________________________
 #
@@ -124,6 +132,7 @@
 
 
 def build_stat_result(st):
+    # only for LL backends
     if TIMESPEC is not None:
         atim = st.c_st_atim; atime = atim.c_tv_sec + 1E-9 * atim.c_tv_nsec
         mtim = st.c_st_mtim; mtime = mtim.c_tv_sec + 1E-9 * mtim.c_tv_nsec
@@ -149,7 +158,7 @@
     if "st_rdev"    in STAT_FIELD_TYPES: result += (st.c_st_rdev,)
     if "st_flags"   in STAT_FIELD_TYPES: result += (st.c_st_flags,)
 
-    return stat_controller.box(result)
+    return make_stat_result(result)
 
 
 def register_stat_variant(name):

Added: pypy/branch/pypy-more-rtti-inprogress/rpython/module/r_os_stat.py
==============================================================================
--- (empty file)
+++ pypy/branch/pypy-more-rtti-inprogress/rpython/module/r_os_stat.py	Mon Aug 27 13:46:51 2007
@@ -0,0 +1,68 @@
+"""
+RTyping support for os.stat_result objects.
+They are rtyped just like a tuple of the correct length supporting
+only indexing and the st_xxx attributes.  We need a custom StatResultRepr
+because when rtyping for LL backends we have extra platform-dependent
+items at the end of the tuple, but for OO backends we only want the
+portable items.  This allows the OO backends to assume a fixed shape for
+the tuples returned by os.stat().
+"""
+from pypy.annotation import model as annmodel
+from pypy.objspace.flow.model import Constant
+from pypy.tool.pairtype import pairtype
+from pypy.rpython.rmodel import Repr, IntegerRepr
+from pypy.rpython.error import TyperError
+from pypy.rpython.module import ll_os_stat
+
+
+class StatResultRepr(Repr):
+
+    def __init__(self, rtyper):
+        self.rtyper = rtyper
+        if rtyper.type_system.name == "lltypesystem":
+            self.stat_fields = ll_os_stat.STAT_FIELDS
+        else:
+            self.stat_fields = ll_os_stat.PORTABLE_STAT_FIELDS
+
+        self.stat_field_indexes = {}
+        for i, (name, TYPE) in enumerate(self.stat_fields):
+            self.stat_field_indexes[name] = i
+
+        self.s_tuple = annmodel.SomeTuple([annmodel.lltype_to_annotation(TYPE)
+                                           for name, TYPE in self.stat_fields])
+        self.r_tuple = rtyper.getrepr(self.s_tuple)
+        self.lowleveltype = self.r_tuple.lowleveltype
+
+    def redispatch_getfield(self, hop, index):
+        rtyper = self.rtyper
+        s_index = rtyper.annotator.bookkeeper.immutablevalue(index)
+        hop2 = hop.copy()
+        hop2.forced_opname = 'getitem'
+        hop2.args_v = [hop2.args_v[0], Constant(index)]
+        hop2.args_s = [self.s_tuple, s_index]
+        hop2.args_r = [self.r_tuple, rtyper.getrepr(s_index)]
+        return hop2.dispatch()
+
+    def rtype_getattr(self, hop):
+        s_attr = hop.args_s[1]
+        attr = s_attr.const
+        try:
+            index = self.stat_field_indexes[attr]
+        except KeyError:
+            raise TyperError("os.stat().%s: field not available" % (attr,))
+        return self.redispatch_getfield(hop, index)
+
+
+class __extend__(pairtype(StatResultRepr, IntegerRepr)):
+
+    def rtype_getitem((r_sta, r_int), hop):
+        s_int = hop.args_s[1]
+        index = s_int.const
+        return r_sta.redispatch_getfield(hop, index)
+
+
+def specialize_make_stat_result(hop):
+    r_StatResult = hop.rtyper.getrepr(ll_os_stat.s_StatResult)
+    [v_result] = hop.inputargs(r_StatResult.r_tuple)
+    # no-op conversion from r_StatResult.r_tuple to r_StatResult
+    return v_result

Modified: pypy/branch/pypy-more-rtti-inprogress/rpython/ootypesystem/module/ll_os.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/rpython/ootypesystem/module/ll_os.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/rpython/ootypesystem/module/ll_os.py	Mon Aug 27 13:46:51 2007
@@ -8,4 +8,6 @@
     fields = dict(zip(fieldnames, FIELDS))
     return ootype.Record(fields)
 
-STAT_RESULT = _make_tuple([ootype.Signed]*10)
+from pypy.rpython.module.ll_os_stat import PORTABLE_STAT_FIELDS
+
+STAT_RESULT = _make_tuple([_TYPE for _name, _TYPE in PORTABLE_STAT_FIELDS])

Modified: pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_builtin.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_builtin.py	(original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/cli/test/test_builtin.py	Mon Aug 27 13:46:51 2007
@@ -91,9 +91,14 @@
         assert contents == long2str(MAGIC)
 
     def test_os_stat(self):
-        def fn():
-            return os.stat('.')[0]
-        mode = self.interpret(fn, [])
+        def fn(flag):
+            if flag:
+                return os.stat('.')[0]
+            else:
+                return os.stat('.').st_mode
+        mode = self.interpret(fn, [0])
+        assert stat.S_ISDIR(mode)
+        mode = self.interpret(fn, [1])
         assert stat.S_ISDIR(mode)
 
     def test_os_stat_oserror(self):



More information about the Pypy-commit mailing list