Author: Maciej Fijalkowski <fij...@gmail.com>
Branch: fileops2
Changeset: r67163:7c6969e0bd84
Date: 2013-10-06 10:51 +0200
http://bitbucket.org/pypy/pypy/changeset/7c6969e0bd84/

Log:    (fijal, arigo) work on fileops

diff --git a/rpython/flowspace/specialcase.py b/rpython/flowspace/specialcase.py
--- a/rpython/flowspace/specialcase.py
+++ b/rpython/flowspace/specialcase.py
@@ -1,3 +1,4 @@
+import os
 from rpython.flowspace.model import Constant, const
 
 SPECIAL_CASES = {}
@@ -37,6 +38,18 @@
     return space.frame.do_operation('simple_call', const(isinstance),
             w_instance, w_type)
 
+@register_flow_sc(open)
+def sc_open(space, *args_w):
+    from rpython.rlib.rfile import create_file
+
+    return space.frame.do_operation("simple_call", const(create_file), *args_w)
+
+@register_flow_sc(os.tmpfile)
+def sc_os_tmpfile(space):
+    from rpython.rlib.rfile import create_temp_rfile
+
+    return space.frame.do_operation("simple_call", const(create_temp_rfile))
+
 # _________________________________________________________________________
 # a simplified version of the basic printing routines, for RPython programs
 class StdOutBuffer:
diff --git a/rpython/rlib/rfile.py b/rpython/rlib/rfile.py
--- a/rpython/rlib/rfile.py
+++ b/rpython/rlib/rfile.py
@@ -1,55 +1,158 @@
 
-""" This file makes open() and friends RPython
+""" This file makes open() and friends RPython. Note that RFile should not
+be used directly and instead it's magically appearing each time you call
+python builtin open()
 """
 
 import os
-from rpython.annotator.model import SomeObject, SomeString, SomeInteger
-from rpython.rtyper.extregistry import ExtRegistryEntry
-from rpython.rtyper.extfunc import register_external
+from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.translator.tool.cbuild import ExternalCompilationInfo
+from rpython.rlib.rarithmetic import r_uint, intmask
+from rpython.rlib import rposix
+from rpython.rlib.rstring import StringBuilder
 
-class SomeFile(SomeObject):
-    def method_write(self, s_arg):
-        assert isinstance(s_arg, SomeString)
+eci = ExternalCompilationInfo(includes=['stdio.h'])
 
-    def method_read(self, s_arg=None):
-        if s_arg is not None:
-            assert isinstance(s_arg, SomeInteger)
-        return SomeString(can_be_None=False)
+def llexternal(*args):
+    return rffi.llexternal(*args, compilation_info=eci)
 
-    def method_close(self):
-        pass
+FILE = lltype.Struct('FILE') # opaque type maybe
 
-    def method_seek(self, s_arg, s_whence=None):
-        assert isinstance(s_arg, SomeInteger)
-        if s_whence is not None:
-            assert isinstance(s_whence, SomeInteger)
+c_open = llexternal('fopen', [rffi.CCHARP, rffi.CCHARP], lltype.Ptr(FILE))
+c_close = llexternal('fclose', [lltype.Ptr(FILE)], rffi.INT)
+c_write = llexternal('fwrite', [rffi.CCHARP, rffi.SIZE_T, rffi.SIZE_T,
+                                     lltype.Ptr(FILE)], rffi.SIZE_T)
+c_read = llexternal('fread', [rffi.CCHARP, rffi.SIZE_T, rffi.SIZE_T,
+                                   lltype.Ptr(FILE)], rffi.SIZE_T)
+c_feof = llexternal('feof', [lltype.Ptr(FILE)], rffi.INT)
+c_ferror = llexternal('ferror', [lltype.Ptr(FILE)], rffi.INT)
+c_clearerror = llexternal('clearerr', [lltype.Ptr(FILE)], lltype.Void)
+c_fseek = llexternal('fseek', [lltype.Ptr(FILE), rffi.LONG, rffi.INT],
+                          rffi.INT)
+c_tmpfile = llexternal('tmpfile', [], lltype.Ptr(FILE))
+c_fileno = llexternal('fileno', [lltype.Ptr(FILE)], rffi.INT)
+c_ftell = llexternal('ftell', [lltype.Ptr(FILE)], lltype.Signed)
+c_fflush = llexternal('fflush', [lltype.Ptr(FILE)], lltype.Signed)
 
-    def rtyper_makekey(self):
-        return self.__class__,
+BASE_BUF_SIZE = 4096
 
-    def rtyper_makerepr(self, rtyper):
-        from rpython.rtyper.lltypesystem.rfile import FileRepr
+def create_file(filename, mode="r", buffering=-1):
+    assert buffering == -1
+    assert filename is not None
+    assert mode is not None
+    ll_name = rffi.str2charp(filename)
+    try:
+        ll_mode = rffi.str2charp(mode)
+        try:
+            ll_f = c_open(ll_name, ll_mode)
+            if not ll_f:
+                errno = rposix.get_errno()
+                raise OSError(errno, os.strerror(errno))
+        finally:
+            lltype.free(ll_mode, flavor='raw')
+    finally:
+        lltype.free(ll_name, flavor='raw')
+    return RFile(ll_f)
 
-        return FileRepr(rtyper)
+def create_temp_rfile():
+    res = c_tmpfile()
+    if not res:
+        errno = rposix.get_errno()
+        raise OSError(errno, os.strerror(errno))
+    return RFile(res)
 
-class FileEntry(ExtRegistryEntry):
-    _about_ = open
+class RFile(object):
+    def __init__(self, ll_file):
+        self.ll_file = ll_file
 
-    def compute_result_annotation(self, s_name, s_mode=None):
-        assert isinstance(s_name, SomeString)
-        if s_mode is not None:
-            assert isinstance(s_mode, SomeString)
-        return SomeFile()
+    def write(self, value):
+        assert value is not None
+        ll_file = self.ll_file
+        if not ll_file:
+            raise ValueError("I/O operation on closed file")
+        assert value is not None
+        ll_value = rffi.get_nonmovingbuffer(value)
+        try:
+            # note that since we got a nonmoving buffer, it is either raw
+            # or already cannot move, so the arithmetics below are fine
+            total_bytes = 0
+            ll_current = ll_value
+            while total_bytes < len(value):
+                bytes = c_write(ll_current, 1, len(value) - 
r_uint(total_bytes),
+                                ll_file)
+                if bytes == 0:
+                    errno = rposix.get_errno()
+                    raise OSError(errno, os.strerror(errno))
+                total_bytes += bytes
+                ll_current = rffi.cast(rffi.CCHARP,
+                                       rffi.cast(lltype.Unsigned, ll_value) +
+                                       total_bytes)
+        finally:
+            rffi.free_nonmovingbuffer(value, ll_value)
 
-    def specialize_call(self, hop):
-        return hop.r_result.rtype_constructor(hop)
+    def close(self):
+        if self.ll_file:
+            # double close is allowed
+            res = c_close(self.ll_file)
+            self.ll_file = lltype.nullptr(FILE)
+            if res == -1:
+                errno = rposix.get_errno()
+                raise OSError(errno, os.strerror(errno))
 
-class OSTempfileEntry(ExtRegistryEntry):
-    _about_ = os.tmpfile
+    def read(self, size=-1):
+        ll_file = self.ll_file
+        if not ll_file:
+            raise ValueError("I/O operation on closed file")
+        if size < 0:
+            # read the entire contents
+            buf = lltype.malloc(rffi.CCHARP.TO, BASE_BUF_SIZE, flavor='raw')
+            try:
+                s = StringBuilder()
+                while True:
+                    returned_size = c_read(buf, 1, BASE_BUF_SIZE, ll_file)
+                    if returned_size == 0:
+                        if c_feof(ll_file):
+                            # ok, finished
+                            return s.build()
+                        errno = c_ferror(ll_file)
+                        c_clearerror(ll_file)
+                        raise OSError(errno, os.strerror(errno))
+                    s.append_charpsize(buf, returned_size)
+            finally:
+                lltype.free(buf, flavor='raw')
+        else:
+            raw_buf, gc_buf = rffi.alloc_buffer(size)
+            try:
+                returned_size = c_read(raw_buf, 1, size, ll_file)
+                if returned_size == 0:
+                    if not c_feof(ll_file):
+                        errno = c_ferror(ll_file)
+                        raise OSError(errno, os.strerror(errno))
+                s = rffi.str_from_buffer(raw_buf, gc_buf, size,
+                                         rffi.cast(lltype.Signed, 
returned_size))
+            finally:
+                rffi.keep_buffer_alive_until_here(raw_buf, gc_buf)
+            return s
 
-    def compute_result_annotation(self):
-        return SomeFile()
+    def seek(self, pos, whence=0):
+        ll_file = self.ll_file
+        if not ll_file:
+            raise ValueError("I/O operation on closed file")
+        res = c_fseek(ll_file, pos, whence)
+        if res == -1:
+            errno = rposix.get_errno()
+            raise OSError(errno, os.strerror(errno))
 
-    def specialize_call(self, hop):
-        return hop.r_result.rtype_tempfile(hop)
+    def fileno(self):
+        if self.ll_file:
+            return intmask(c_fileno(self.ll_file))
+        raise ValueError("I/O operation on closed file")
 
+    def tell(self):
+        if self.ll_file:
+            res = intmask(c_ftell(self.ll_file))
+            if res == -1:
+                errno = rposix.get_errno()
+                raise OSError(errno, os.strerror(errno))
+            return res
+        raise ValueError("I/O operation on closed file")
diff --git a/rpython/rlib/test/test_rfile.py b/rpython/rlib/test/test_rfile.py
--- a/rpython/rlib/test/test_rfile.py
+++ b/rpython/rlib/test/test_rfile.py
@@ -78,3 +78,31 @@
 
         f()
         self.interpret(f, [])
+
+    def test_fileno(self):
+        fname = str(self.tmpdir.join('file_5'))
+
+        def f():
+            f = open(fname, "w")
+            try:
+                return f.fileno()
+            finally:
+                f.close()
+
+        res = self.interpret(f, [])
+        assert res > 2
+
+    def test_tell(self):
+        fname = str(self.tmpdir.join('file_tell'))
+
+        def f():
+            f = open(fname, "w")
+            f.write("xyz")
+            try:
+                return f.tell()
+            finally:
+                f.close()
+
+        res = self.interpret(f, [])
+        assert res == 3
+
diff --git a/rpython/rtyper/lltypesystem/rfile.py 
b/rpython/rtyper/lltypesystem/rfile.py
deleted file mode 100644
--- a/rpython/rtyper/lltypesystem/rfile.py
+++ /dev/null
@@ -1,195 +0,0 @@
-
-import os
-from rpython.rlib import rposix
-from rpython.rlib.rarithmetic import r_uint
-from rpython.annotator import model as annmodel
-from rpython.rtyper.rtyper import Repr
-from rpython.rlib.rstring import StringBuilder
-from rpython.rtyper.lltypesystem import lltype, rffi, llmemory
-from rpython.rtyper.lltypesystem.rstr import string_repr, STR
-from rpython.translator.tool.cbuild import ExternalCompilationInfo
-from rpython.rtyper.annlowlevel import hlstr
-from rpython.rtyper.lltypesystem.lloperation import llop
-
-FILE = lltype.Struct('FILE') # opaque type maybe
-FILE_WRAPPER = lltype.GcStruct("FileWrapper", ('file', lltype.Ptr(FILE)))
-
-eci = ExternalCompilationInfo(includes=['stdio.h'])
-
-def llexternal(*args):
-    return rffi.llexternal(*args, compilation_info=eci)
-
-c_open = llexternal('fopen', [rffi.CCHARP, rffi.CCHARP], lltype.Ptr(FILE))
-c_close = llexternal('fclose', [lltype.Ptr(FILE)], rffi.INT)
-c_write = llexternal('fwrite', [rffi.CCHARP, rffi.SIZE_T, rffi.SIZE_T,
-                                     lltype.Ptr(FILE)], rffi.SIZE_T)
-c_read = llexternal('fread', [rffi.CCHARP, rffi.SIZE_T, rffi.SIZE_T,
-                                   lltype.Ptr(FILE)], rffi.SIZE_T)
-c_feof = llexternal('feof', [lltype.Ptr(FILE)], rffi.INT)
-c_ferror = llexternal('ferror', [lltype.Ptr(FILE)], rffi.INT)
-c_clearerror = llexternal('clearerr', [lltype.Ptr(FILE)], lltype.Void)
-c_fseek = llexternal('fseek', [lltype.Ptr(FILE), rffi.LONG, rffi.INT],
-                          rffi.INT)
-c_tmpfile = llexternal('tmpfile', [], lltype.Ptr(FILE))
-
-def ll_open(name, mode):
-    file_wrapper = lltype.malloc(FILE_WRAPPER)
-    ll_name = rffi.str2charp(name)
-    ll_mode = rffi.str2charp(mode)
-    try:
-        ll_f = c_open(ll_name, ll_mode)
-        if not ll_f:
-            errno = rposix.get_errno()
-            raise OSError(errno, os.strerror(errno))
-        file_wrapper.file = ll_f
-    finally:
-        lltype.free(ll_name, flavor='raw')
-        lltype.free(ll_mode, flavor='raw')
-    return file_wrapper
-
-def ll_tmpfile():
-    file_wrapper = lltype.malloc(FILE_WRAPPER)
-    res = c_tmpfile()
-    if not res:
-        errno = rposix.get_errno()
-        raise OSError(errno, os.strerror(errno))
-    file_wrapper.file = res
-    return file_wrapper
-
-def ll_write(file_wrapper, value):
-    ll_file = file_wrapper.file
-    if not ll_file:
-        raise ValueError("I/O operation on closed file")
-    value = hlstr(value)
-    assert value is not None
-    ll_value = rffi.get_nonmovingbuffer(value)
-    try:
-        # note that since we got a nonmoving buffer, it is either raw
-        # or already cannot move, so the arithmetics below are fine
-        total_bytes = 0
-        ll_current = ll_value
-        while total_bytes < len(value):
-            bytes = c_write(ll_current, 1, len(value) - r_uint(total_bytes),
-                            ll_file)
-            if bytes == 0:
-                errno = rposix.get_errno()
-                raise OSError(errno, os.strerror(errno))
-            total_bytes += bytes
-            ll_current = rffi.cast(rffi.CCHARP,
-                                   rffi.cast(lltype.Unsigned, ll_value) +
-                                   total_bytes)
-    finally:
-        rffi.free_nonmovingbuffer(value, ll_value)
-
-BASE_BUF_SIZE = 4096
-
-def ll_read(file_wrapper, size):
-    ll_file = file_wrapper.file
-    if not ll_file:
-        raise ValueError("I/O operation on closed file")
-    if size < 0:
-        # read the entire contents
-        buf = lltype.malloc(rffi.CCHARP.TO, BASE_BUF_SIZE, flavor='raw')
-        try:
-            s = StringBuilder()
-            while True:
-                returned_size = c_read(buf, 1, BASE_BUF_SIZE, ll_file)
-                if returned_size == 0:
-                    if c_feof(ll_file):
-                        # ok, finished
-                        return s.build()
-                    errno = c_ferror(ll_file)
-                    c_clearerror(ll_file)
-                    raise OSError(errno, os.strerror(errno))
-                s.append_charpsize(buf, returned_size)
-        finally:
-            lltype.free(buf, flavor='raw')
-    else:
-        raw_buf, gc_buf = rffi.alloc_buffer(size)
-        try:
-            returned_size = c_read(raw_buf, 1, size, ll_file)
-            if returned_size == 0:
-                if not c_feof(ll_file):
-                    errno = c_ferror(ll_file)
-                    raise OSError(errno, os.strerror(errno))
-            s = rffi.str_from_buffer(raw_buf, gc_buf, size,
-                                     rffi.cast(lltype.Signed, returned_size))
-        finally:
-            rffi.keep_buffer_alive_until_here(raw_buf, gc_buf)
-        return s
-def ll_seek(file_wrapper, pos, whence):
-    ll_file = file_wrapper.file
-    if not ll_file:
-        raise ValueError("I/O operation on closed file")
-    res = c_fseek(ll_file, pos, whence)
-    if res == -1:
-        errno = rposix.get_errno()
-        raise OSError(errno, os.strerror(errno))
-
-def ll_close(file_wrapper):
-    if file_wrapper.file:
-        # double close is allowed
-        res = c_close(file_wrapper.file)
-        file_wrapper.file = lltype.nullptr(FILE)
-        if res == -1:
-            errno = rposix.get_errno()
-            raise OSError(errno, os.strerror(errno))
-
-class FileRepr(Repr):
-    lowleveltype = lltype.Ptr(FILE_WRAPPER)
-
-    def __init__(self, typer):
-        Repr.__init__(self)
-
-    def rtype_constructor(self, hop):
-        repr = hop.rtyper.getrepr(annmodel.SomeString())
-        arg_0 = hop.inputarg(repr, 0)
-        if len(hop.args_v) == 1:
-            arg_1 = hop.inputconst(string_repr, "r")
-        else:
-            arg_1 = hop.inputarg(repr, 1)
-        hop.exception_is_here()
-        open = hop.rtyper.getannmixlevel().delayedfunction(
-            ll_open, [annmodel.SomeString()] * 2,
-            annmodel.SomePtr(self.lowleveltype))
-        v_open = hop.inputconst(lltype.typeOf(open), open)
-        return hop.genop('direct_call', [v_open, arg_0, arg_1],
-                         resulttype=self)
-
-    def rtype_tempfile(self, hop):
-        tmpfile = hop.rtyper.getannmixlevel().delayedfunction(
-            ll_tmpfile, [], annmodel.SomePtr(self.lowleveltype))
-        v_tmpfile = hop.inputconst(lltype.typeOf(tmpfile), tmpfile)
-        hop.exception_is_here()
-        return hop.genop('direct_call', [v_tmpfile], resulttype=self)
-
-
-    def rtype_method_write(self, hop):
-        args_v = hop.inputargs(self, string_repr)
-        hop.exception_is_here()
-        return hop.gendirectcall(ll_write, *args_v)
-
-    def rtype_method_close(self, hop):
-        r_self = hop.inputarg(self, 0)
-        hop.exception_is_here()
-        return hop.gendirectcall(ll_close, r_self)
-
-    def rtype_method_read(self, hop):
-        r_self = hop.inputarg(self, 0)
-        if len(hop.args_v) != 2:
-            arg_1 = hop.inputconst(lltype.Signed, -1)
-        else:
-            arg_1 = hop.inputarg(lltype.Signed, 1)
-        hop.exception_is_here()
-        return hop.gendirectcall(ll_read, r_self, arg_1)
-
-    def rtype_method_seek(self, hop):
-        r_self = hop.inputarg(self, 0)
-        arg_1 = hop.inputarg(lltype.Signed, 1)
-        if len(hop.args_v) != 3:
-            arg_2 = hop.inputconst(lltype.Signed, os.SEEK_SET)
-        else:
-            arg_2 = hop.inputarg(lltype.Signed, 2)
-        hop.exception_is_here()
-        return hop.gendirectcall(ll_seek, r_self, arg_1, arg_2)
-
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to