From: Jean Privat Date: Sat, 13 Dec 2014 07:49:28 +0000 (-0500) Subject: Merge: Newstreams X-Git-Tag: v0.7~55 X-Git-Url: http://nitlanguage.org?hp=e6dd04f329ee5308befc14a9546a388e4333b37e Merge: Newstreams Small refactoring of Streams/Files: - Added a simple error management system - Removed FDStreams, reified under FStream Next PR to come: Proposition for renaming of the classes of the stream hierarchy (as requested in #466) Pull-Request: #932 Reviewed-by: Alexis Laferrière Reviewed-by: Alexandre Terrasa Reviewed-by: Jean Privat --- diff --git a/lib/io/push_back_reader.nit b/lib/io/push_back_reader.nit index 257c662..5453901 100644 --- a/lib/io/push_back_reader.nit +++ b/lib/io/push_back_reader.nit @@ -12,7 +12,7 @@ module io::push_back_reader # Input stream that permits to push bytes back to the stream. -interface PushBackReader +class PushBackReader super IStream # Push the specified byte back to the stream. diff --git a/lib/pnacl.nit b/lib/pnacl.nit index 4008422..70b8e7c 100644 --- a/lib/pnacl.nit +++ b/lib/pnacl.nit @@ -44,6 +44,7 @@ in "C Header" `{ #include #include #include + #include #define MAX_DICTIONARY_QUEUE_SIZE 200 #define MAX_MESSAGE_QUEUE_SIZE 10 @@ -358,7 +359,7 @@ in "C Header" `{ } /* Hack in order to avoid the problem with file. */ - int poll(void *fds, int nfds, int timeout) { return 0; } + int poll(struct pollfd* fds, nfds_t nfds, int timeout) { return 0; } `} # Nit class representing a Pepper C API PP_Var typed as a Dictionary. diff --git a/lib/standard/exec.nit b/lib/standard/exec.nit index 2495800..79f9bfd 100644 --- a/lib/standard/exec.nit +++ b/lib/standard/exec.nit @@ -15,7 +15,7 @@ # Standard input and output can be handled through streams. module exec -import stream +import file # Simple sub-process class Process @@ -93,7 +93,7 @@ class IProcess super IStream # File Descriptor used for the input. - var stream_in: FDIStream is noinit + var stream_in: IFStream is noinit redef fun close do stream_in.close @@ -106,7 +106,7 @@ class IProcess redef fun execute do super - stream_in = new FDIStream(data.out_fd) + stream_in = new IFStream.from_fd(data.out_fd) end end @@ -129,7 +129,7 @@ class OProcess redef fun execute do super - stream_out = new FDOStream(data.in_fd) + stream_out = new OFStream.from_fd(data.in_fd) end end diff --git a/lib/standard/exec_nit.c b/lib/standard/exec_nit.c index c808105..c69ba64 100644 --- a/lib/standard/exec_nit.c +++ b/lib/standard/exec_nit.c @@ -26,22 +26,19 @@ se_exec_data_t* exec_Process_Process_basic_exec_execute_4(void *s, char *prog, c if (pipeflag & 1) { int res = pipe(in_fd); if ( res == -1 ) { - fprintf( stderr, "Pipe init failed in Process:basic_exec_execute: %s\n", strerror( errno ) ); - exit(1); + return NULL; } } if (pipeflag & 2) { int res = pipe(out_fd); if ( res == -1 ) { - fprintf( stderr, "Pipe init failed in Process:basic_exec_execute: %s\n", strerror( errno ) ); - exit(1); + return NULL; } } if (pipeflag & 4) { int res = pipe(err_fd); if ( res == -1 ) { - fprintf( stderr, "Pipe init failed in Process:basic_exec_execute: %s\n", strerror( errno ) ); - exit(1); + return NULL; } } diff --git a/lib/standard/file.nit b/lib/standard/file.nit index 88fb3c8..a7c48db 100644 --- a/lib/standard/file.nit +++ b/lib/standard/file.nit @@ -27,6 +27,8 @@ in "C Header" `{ #include #include #include + #include + #include `} # File Abstract Stream @@ -43,6 +45,21 @@ abstract class FStream # File descriptor of this file fun fd: Int do return _file.fileno + + # Sets the buffering mode for the current FStream + # + # If the buf_size is <= 0, its value will be 512 by default + # + # The mode is any of the buffer_mode enumeration in `Sys`: + # - buffer_mode_full + # - buffer_mode_line + # - buffer_mode_none + fun set_buffering_mode(buf_size, mode: Int) do + if buf_size <= 0 then buf_size = 512 + if _file.set_buffering_type(buf_size, mode) != 0 then + last_error = new IOError("Error while changing buffering type for FStream, returned error {sys.errno.strerror}") + end + end end # File input stream @@ -56,8 +73,14 @@ class IFStream # The original path is reused, therefore the reopened file can be a different file. fun reopen do - if not eof then close + if not eof and not _file.address_is_null then close + last_error = null _file = new NativeFile.io_open_read(path.to_cstring) + if _file.address_is_null then + last_error = new IOError("Error: Opening file at '{path.as(not null)}' failed with '{sys.errno.strerror}'") + end_reached = true + return + end end_reached = false _buffer_pos = 0 _buffer.clear @@ -65,7 +88,8 @@ class IFStream redef fun close do - _file.io_close + if _file.address_is_null then return + var i = _file.io_close _buffer.clear end_reached = true end @@ -80,7 +104,7 @@ class IFStream _buffer.length = nb _buffer_pos = 0 end - + # End of file? redef var end_reached: Bool = false @@ -90,11 +114,21 @@ class IFStream self.path = path prepare_buffer(10) _file = new NativeFile.io_open_read(path.to_cstring) - assert not _file.address_is_null else - print "Error: Opening file at '{path}' failed with '{sys.errno.strerror}'" + if _file.address_is_null then + last_error = new IOError("Error: Opening file at '{path}' failed with '{sys.errno.strerror}'") + end_reached = true end end + init from_fd(fd: Int) do + self.path = "" + prepare_buffer(1) + _file = fd.fd_to_stream(read_only) + if _file.address_is_null then + last_error = new IOError("Error: Converting fd {fd} to stream failed with '{sys.errno.strerror}'") + end_reached = true + end + end end # File output stream @@ -104,30 +138,52 @@ class OFStream redef fun write(s) do - assert _is_writable + if last_error != null then return + if not _is_writable then + last_error = new IOError("Cannot write to non-writable stream") + return + end if s isa FlatText then write_native(s.to_cstring, s.length) else for i in s.substrings do write_native(i.to_cstring, i.length) end + _file.flush end redef fun close do - _file.io_close + if _file.address_is_null then + if last_error != null then return + last_error = new IOError("Cannot close unopened write stream") + _is_writable = false + return + end + var i = _file.io_close + if i != 0 then + last_error = new IOError("Close failed due to error {sys.errno.strerror}") + end _is_writable = false end - redef var is_writable = false # Write `len` bytes from `native`. private fun write_native(native: NativeString, len: Int) do - assert _is_writable + if last_error != null then return + if not _is_writable then + last_error = new IOError("Cannot write to non-writable stream") + return + end + if _file.address_is_null then + last_error = new IOError("Writing on a null stream") + _is_writable = false + return + end var err = _file.io_write(native, len) if err != len then # Big problem - printn("Problem in writing : ", err, " ", len, "\n") + last_error = new IOError("Problem in writing : {err} {len} \n") end end @@ -135,14 +191,43 @@ class OFStream init open(path: String) do _file = new NativeFile.io_open_write(path.to_cstring) - assert not _file.address_is_null else - print "Error: Opening file at '{path}' failed with '{sys.errno.strerror}'" - end self.path = path _is_writable = true + if _file.address_is_null then + last_error = new IOError("Error: Opening file at '{path}' failed with '{sys.errno.strerror}'") + is_writable = false + end + end + + # Creates a new File stream from a file descriptor + init from_fd(fd: Int) do + self.path = "" + _file = fd.fd_to_stream(wipe_write) + _is_writable = true + if _file.address_is_null then + last_error = new IOError("Error: Opening stream from file descriptor {fd} failed with '{sys.errno.strerror}'") + _is_writable = false + end end end +redef class Int + # Creates a file stream from a file descriptor `fd` using the file access `mode`. + # + # NOTE: The `mode` specified must be compatible with the one used in the file descriptor. + private fun fd_to_stream(mode: NativeString): NativeFile is extern "file_int_fdtostream" +end + +# Constant for read-only file streams +private fun read_only: NativeString do return "r".to_cstring + +# Constant for write-only file streams +# +# If a stream is opened on a file with this method, +# it will wipe the previous file if any. +# Else, it will create the file. +private fun wipe_write: NativeString do return "w".to_cstring + ############################################################################### # Standard input stream. @@ -617,6 +702,10 @@ private extern class NativeFile `{ FILE* `} fun io_close: Int is extern "file_NativeFile_NativeFile_io_close_0" fun file_stat: FileStat is extern "file_NativeFile_NativeFile_file_stat_0" fun fileno: Int `{ return fileno(recv); `} + # Flushes the buffer, forcing the write operation + fun flush: Int is extern "fflush" + # Used to specify how the buffering will be handled for the current stream. + fun set_buffering_type(buf_length: Int, mode: Int): Int is extern "file_NativeFile_NativeFile_set_buffering_type_0" new io_open_read(path: NativeString) is extern "file_NativeFileCapable_NativeFileCapable_io_open_read_1" new io_open_write(path: NativeString) is extern "file_NativeFileCapable_NativeFileCapable_io_open_write_1" @@ -627,6 +716,10 @@ end redef class Sys + init do + if stdout isa FStream then stdout.as(FStream).set_buffering_mode(256, buffer_mode_line) + end + # Standard input var stdin: PollableIStream = new Stdin is protected writable @@ -636,6 +729,89 @@ redef class Sys # Standard output for errors var stderr: OStream = new Stderr is protected writable + # Enumeration for buffer mode full (flushes when buffer is full) + fun buffer_mode_full: Int is extern "file_Sys_Sys_buffer_mode_full_0" + # Enumeration for buffer mode line (flushes when a `\n` is encountered) + fun buffer_mode_line: Int is extern "file_Sys_Sys_buffer_mode_line_0" + # Enumeration for buffer mode none (flushes ASAP when something is written) + fun buffer_mode_none: Int is extern "file_Sys_Sys_buffer_mode_none_0" + + # returns first available stream to read or write to + # return null on interruption (possibly a signal) + protected fun poll( streams : Sequence[FStream] ) : nullable FStream + do + var in_fds = new Array[Int] + var out_fds = new Array[Int] + var fd_to_stream = new HashMap[Int,FStream] + for s in streams do + var fd = s.fd + if s isa IFStream then in_fds.add( fd ) + if s isa OFStream then out_fds.add( fd ) + + fd_to_stream[fd] = s + end + + var polled_fd = intern_poll( in_fds, out_fds ) + + if polled_fd == null then + return null + else + return fd_to_stream[polled_fd] + end + end + + private fun intern_poll(in_fds: Array[Int], out_fds: Array[Int]) : nullable Int is extern import Array[Int].length, Array[Int].[], Int.as(nullable Int) `{ + int in_len, out_len, total_len; + struct pollfd *c_fds; + sigset_t sigmask; + int i; + int first_polled_fd = -1; + int result; + + in_len = Array_of_Int_length( in_fds ); + out_len = Array_of_Int_length( out_fds ); + total_len = in_len + out_len; + c_fds = malloc( sizeof(struct pollfd) * total_len ); + + /* input streams */ + for ( i=0; i 0 ) { + /* analyse results */ + for ( i=0; i 0; } + +FILE* file_int_fdtostream(int fd, char* mode){ + return fdopen(fd, mode); +} + +int file_NativeFile_NativeFile_set_buffering_type_0(FILE* f, int buf_sz, int mode){ + return setvbuf(f, NULL, mode, buf_sz); +} diff --git a/lib/standard/file_nit.h b/lib/standard/file_nit.h index 1f5b183..d8d9b4b 100644 --- a/lib/standard/file_nit.h +++ b/lib/standard/file_nit.h @@ -24,6 +24,8 @@ extern int string_NativeString_NativeString_file_exists_0(char *f); extern void *string_NativeString_NativeString_file_stat_0(char *f); extern void *file_NativeFile_NativeFile_file_stat_0(FILE *f); extern int string_NativeString_NativeString_file_delete_0(char *f); +FILE* file_int_fdtostream(int fd, char* mode); +int file_NativeFile_NativeFile_set_buffering_type_0(FILE* f, int buf_sz, int mode); #define file_NativeFile_NativeFile_io_read_2(p, b, l) fread((b), 1, (l), (FILE*)(p)) #define file_NativeFile_NativeFile_io_write_2(p, b, l) fwrite((b), 1, (l), (FILE*)(p)) @@ -40,6 +42,9 @@ extern int string_NativeString_NativeString_file_delete_0(char *f); #define file_FileStat_FileStat_ctime_0(self) (((struct stat*)self)->st_ctime) #define file_FileStat_FileStat_mtime_0(self) (((struct stat*)self)->st_mtime) #define file_FileStat_FileStat_size_0(self) (((struct stat*)self)->st_size) +#define file_Sys_Sys_buffer_mode_full_0(self) _IOFBF +#define file_Sys_Sys_buffer_mode_line_0(self) _IOLBF +#define file_Sys_Sys_buffer_mode_none_0(self) _IONBF #define string_NativeString_NativeString_file_mkdir_0(p) (mkdir(p, 0777)) #define string_NativeString_NativeString_file_getcwd_0(p) (getcwd(NULL, 0)) diff --git a/lib/standard/stream.nit b/lib/standard/stream.nit index 4139e45..933523a 100644 --- a/lib/standard/stream.nit +++ b/lib/standard/stream.nit @@ -12,23 +12,35 @@ module stream intrude import ropes +import error in "C" `{ #include - #include - #include #include #include `} +# Any kind of error that could be produced by an operation on Streams +class IOError + super Error +end + # Abstract stream class -interface IOS +abstract class IOS + # Error produced by the file stream + # + # var ifs = new IFStream.open("donotmakethisfile.binx") + # ifs.read_all + # ifs.close + # assert ifs.last_error != null + var last_error: nullable IOError = null + # close the stream fun close is abstract end # Abstract input streams -interface IStream +abstract class IStream super IOS # Read a character. Return its ASCII value, -1 on EOF or timeout fun read_char: Int is abstract @@ -36,6 +48,7 @@ interface IStream # Read at most i bytes fun read(i: Int): String do + if last_error != null then return "" var s = new FlatBuffer.with_capacity(i) while i > 0 and not eof do var c = read_char @@ -74,6 +87,7 @@ interface IStream # NOTE: Only LINE FEED (`\n`) is considered to delimit the end of lines. fun read_line: String do + if last_error != null then return "" assert not eof var s = new FlatBuffer append_line_to(s) @@ -106,6 +120,7 @@ interface IStream # Read all the stream until the eof. fun read_all: String do + if last_error != null then return "" var s = new FlatBuffer while not eof do var c = read_char @@ -119,6 +134,7 @@ interface IStream # SEE: `read_line` for details. fun append_line_to(s: Buffer) do + if last_error != null then return loop var x = read_char if x == -1 then @@ -137,7 +153,7 @@ interface IStream end # IStream capable of declaring if readable without blocking -interface PollableIStream +abstract class PollableIStream super IStream # Is there something to read? (without blocking) @@ -146,7 +162,7 @@ interface PollableIStream end # Abstract output stream -interface OStream +abstract class OStream super IOS # write a string fun write(s: Text) is abstract @@ -189,7 +205,8 @@ abstract class BufferedIStream super IStream redef fun read_char do - assert not eof + if last_error != null then return 0 + if eof then last_error = new IOError("Stream has reached eof") if _buffer_pos >= _buffer.length then fill_buffer end @@ -203,6 +220,7 @@ abstract class BufferedIStream redef fun read(i) do + if last_error != null then return "" if _buffer.length == _buffer_pos then if not eof then fill_buffer @@ -221,6 +239,7 @@ abstract class BufferedIStream redef fun read_all do + if last_error != null then return "" var s = new FlatBuffer while not eof do var j = _buffer_pos @@ -294,140 +313,11 @@ abstract class BufferedIStream end # An Input/Output Stream -interface IOStream +abstract class IOStream super IStream super OStream end -##############################################################" - -# A File Descriptor Stream. -abstract class FDStream - super IOS - # File description - var fd: Int - - redef fun close do native_close(fd) - - private fun native_close(i: Int): Int is extern "stream_FDStream_FDStream_native_close_1" - private fun native_read_char(i: Int): Int is extern "stream_FDStream_FDStream_native_read_char_1" - private fun native_read(i: Int, buf: NativeString, len: Int): Int is extern "stream_FDStream_FDStream_native_read_3" - private fun native_write(i: Int, buf: NativeString, len: Int): Int is extern "stream_FDStream_FDStream_native_write_3" - private fun native_write_char(i: Int, c: Char): Int is extern "stream_FDStream_FDStream_native_write_char_2" -end - -# An Input File Descriptor Stream. -class FDIStream - super FDStream - super IStream - redef var eof: Bool = false - - redef fun read_char - do - var nb = native_read_char(fd) - if nb == -1 then eof = true - return nb - end -end - -# An Output File Descriptor Stream. -class FDOStream - super FDStream - super OStream - redef var is_writable = true - - redef fun write(s) - do - var nb = native_write(fd, s.to_cstring, s.length) - if nb < s.length then is_writable = false - end -end - -# An Input/Output File Descriptor Stream. -class FDIOStream - super FDIStream - super FDOStream - super IOStream -end - -redef interface Object - # returns first available stream to read or write to - # return null on interruption (possibly a signal) - protected fun poll( streams : Sequence[FDStream] ) : nullable FDStream - do - var in_fds = new Array[Int] - var out_fds = new Array[Int] - var fd_to_stream = new HashMap[Int,FDStream] - for s in streams do - var fd = s.fd - if s isa FDIStream then in_fds.add( fd ) - if s isa FDOStream then out_fds.add( fd ) - - fd_to_stream[fd] = s - end - - var polled_fd = intern_poll( in_fds, out_fds ) - - if polled_fd == null then - return null - else - return fd_to_stream[polled_fd] - end - end - - private fun intern_poll(in_fds: Array[Int], out_fds: Array[Int]) : nullable Int is extern import Array[Int].length, Array[Int].[], Int.as(nullable Int) `{ - int in_len, out_len, total_len; - struct pollfd *c_fds; - sigset_t sigmask; - int i; - int first_polled_fd = -1; - int result; - - in_len = Array_of_Int_length( in_fds ); - out_len = Array_of_Int_length( out_fds ); - total_len = in_len + out_len; - c_fds = malloc( sizeof(struct pollfd) * total_len ); - - /* input streams */ - for ( i=0; i 0 ) { - /* analyse results */ - for ( i=0; i - * - * This file is free software, which comes along with NIT. This software is - * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. You can modify it is you want, provided this header - * is kept unaltered, and a notification of the changes is added. - * You are allowed to redistribute it and sell it, alone or is a part of - * another product. - */ - -#include "stream_nit.h" - -int stream_FDStream_FDStream_native_read_char_1(void *s, int fd) { - int result; - char buf; - ssize_t r = read(fd, &buf, 1); - if (r == 0) - result = -1; - else - result = buf; - return result; -} diff --git a/lib/standard/stream_nit.h b/lib/standard/stream_nit.h deleted file mode 100644 index 3a4d51e..0000000 --- a/lib/standard/stream_nit.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef __STREAM_NIT_H -#define __STREAM_NIT_H -/* This file is part of NIT ( http://www.nitlanguage.org ). - * - * Copyright 2004-2008 Jean Privat - * - * This file is free software, which comes along with NIT. This software is - * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. You can modify it is you want, provided this header - * is kept unaltered, and a notification of the changes is added. - * You are allowed to redistribute it and sell it, alone or is a part of - * another product. - */ - -#include - -int stream_FDStream_FDStream_native_read_char_1(void *s, int fd); - -#define stream_FDStream_FDStream_native_close_1(self, p0) (close(p0)) -#define stream_FDStream_FDStream_native_read_3(s, i, b, l) read((i), ((b)), ((l))) -#define stream_FDStream_FDStream_native_write_3(s, i, b, l) write((i), ((b)), ((l))) -#define stream_FDStream_FDStream_native_write_char_2(s, i, c) write((i), (char[]){(c)}, 1 ) - -#endif diff --git a/src/interpreter/naive_interpreter.nit b/src/interpreter/naive_interpreter.nit index e3cc1ca..064395d 100644 --- a/src/interpreter/naive_interpreter.nit +++ b/src/interpreter/naive_interpreter.nit @@ -21,6 +21,7 @@ import literal import semantize private import parser::tables import mixin +import primitive_types redef class ToolContext # --discover-call-trace @@ -796,6 +797,12 @@ redef class AMethPropdef else if pname == "exit" then exit(args[1].to_i) abort + else if pname == "buffer_mode_full" then + return v.int_instance(sys.buffer_mode_full) + else if pname == "buffer_mode_line" then + return v.int_instance(sys.buffer_mode_line) + else if pname == "buffer_mode_none" then + return v.int_instance(sys.buffer_mode_none) else if pname == "sys" then return v.mainobj else if cname == "Int" then @@ -1013,43 +1020,51 @@ redef class AMethPropdef end else if cname == "NativeFile" then if pname == "native_stdout" then - var instance = new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdout) + var inst = new PrimitiveNativeFile.native_stdout + var instance = new PrimitiveInstance[PrimitiveNativeFile](mpropdef.mclassdef.mclass.mclass_type, inst) v.init_instance_primitive(instance) return instance else if pname == "native_stdin" then - var instance = new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdin) + var inst = new PrimitiveNativeFile.native_stdin + var instance = new PrimitiveInstance[PrimitiveNativeFile](mpropdef.mclassdef.mclass.mclass_type, inst) v.init_instance_primitive(instance) return instance else if pname == "native_stderr" then - var instance = new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stderr) + var inst = new PrimitiveNativeFile.native_stderr + var instance = new PrimitiveInstance[PrimitiveNativeFile](mpropdef.mclassdef.mclass.mclass_type, inst) v.init_instance_primitive(instance) return instance else if pname == "io_open_read" then var a1 = args[1].val.as(Buffer) - var instance = new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, new IFStream.open(a1.to_s)) + var inst = new PrimitiveNativeFile.io_open_read(a1.to_s) + var instance = new PrimitiveInstance[PrimitiveNativeFile](mpropdef.mclassdef.mclass.mclass_type, inst) v.init_instance_primitive(instance) return instance else if pname == "io_open_write" then var a1 = args[1].val.as(Buffer) - var instance = new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, new OFStream.open(a1.to_s)) + var inst = new PrimitiveNativeFile.io_open_write(a1.to_s) + var instance = new PrimitiveInstance[PrimitiveNativeFile](mpropdef.mclassdef.mclass.mclass_type, inst) v.init_instance_primitive(instance) return instance end var recvval = args.first.val if pname == "io_write" then var a1 = args[1].val.as(Buffer) - recvval.as(OStream).write(a1.substring(0, args[2].to_i).to_s) - return args[2] + return v.int_instance(recvval.as(PrimitiveNativeFile).io_write(a1.to_cstring, args[2].to_i)) else if pname == "io_read" then - var str = recvval.as(IStream).read(args[2].to_i) var a1 = args[1].val.as(Buffer) - new FlatBuffer.from(str).copy(0, str.length, a1.as(FlatBuffer), 0) - return v.int_instance(str.length) + var ns = new NativeString(a1.length) + var len = recvval.as(PrimitiveNativeFile).io_read(ns, args[2].to_i) + a1.clear + a1.append(ns.to_s_with_length(len)) + return v.int_instance(len) + else if pname == "flush" then + recvval.as(PrimitiveNativeFile).flush + return null else if pname == "io_close" then - recvval.as(IOS).close - return v.int_instance(0) - else if pname == "address_is_null" then - return v.false_instance + return v.int_instance(recvval.as(PrimitiveNativeFile).io_close) + else if pname == "set_buffering_type" then + return v.int_instance(recvval.as(PrimitiveNativeFile).set_buffering_type(args[1].to_i, args[2].to_i)) end else if pname == "calloc_array" then var recvtype = args.first.mtype.as(MClassType) @@ -1095,6 +1110,10 @@ redef class AMethPropdef else if pname == "errno" then return v.int_instance(sys.errno) else if pname == "address_is_null" then + var recv = args[0] + if recv isa PrimitiveInstance[PrimitiveNativeFile] then + return v.bool_instance(recv.val.address_is_null) + end return v.false_instance end return v.error_instance diff --git a/src/interpreter/primitive_types.nit b/src/interpreter/primitive_types.nit new file mode 100644 index 0000000..8fe483d --- /dev/null +++ b/src/interpreter/primitive_types.nit @@ -0,0 +1,61 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# This file is free software, which comes along with NIT. This software is +# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. You can modify it is you want, provided this header +# is kept unaltered, and a notification of the changes is added. +# You are allowed to redistribute it and sell it, alone or is a part of +# another product. + +# Encapsulates all primitive data types of nit +# +# Ensures that the use in the interpreter is independant of the +# underlying implementation and that the services are semantically correct. +module primitive_types + +intrude import standard::file + +# Wrapper for `NativeFile` +class PrimitiveNativeFile + + var file: FStream + + init native_stdin do + file = new IFStream.from_fd(0) + end + + init native_stdout do + file = new OFStream.from_fd(1) + end + + init native_stderr do + file = new OFStream.from_fd(2) + end + + init io_open_read(path: String) do + file = new IFStream.open(path.to_s) + end + + init io_open_write(path: String) do + file = new OFStream.open(path.to_s) + end + + fun address_is_null: Bool do return file._file.address_is_null + + fun io_read(buf: NativeString, len: Int): Int do return file._file.io_read(buf, len) + + fun io_write(buf: NativeString, len: Int): Int do return file._file.io_write(buf, len) + + fun io_close: Int do return file._file.io_close + + fun file_stat: FileStat do return file._file.file_stat + + fun fileno: Int do return file._file.fileno + + fun flush: Int do return file._file.flush + + fun set_buffering_type(size, mode: Int): Int do + return file._file.set_buffering_type(size, mode) + end +end diff --git a/tests/sav/nitserial_args1.res b/tests/sav/nitserial_args1.res index e95605c..62be912 100644 --- a/tests/sav/nitserial_args1.res +++ b/tests/sav/nitserial_args1.res @@ -8,10 +8,10 @@ import serialization redef class Deserializer redef fun deserialize_class(name) do + if name == "Array[Object]" then return new Array[Object].from_deserializer(self) if name == "Array[nullable Object]" then return new Array[nullable Object].from_deserializer(self) if name == "Array[Serializable]" then return new Array[Serializable].from_deserializer(self) if name == "Array[String]" then return new Array[String].from_deserializer(self) - if name == "Array[Object]" then return new Array[Object].from_deserializer(self) return super end end diff --git a/tests/sav/test_exec.res b/tests/sav/test_exec.res index 2529d3a..5f9676c 100644 --- a/tests/sav/test_exec.res +++ b/tests/sav/test_exec.res @@ -1,4 +1,4 @@ A hello world! -C hello world! B hello world! +C hello world! D hello world! diff --git a/tests/sav/test_ffi_java_callbacks.res b/tests/sav/test_ffi_java_callbacks.res index 144fa53..58b56d8 100644 --- a/tests/sav/test_ffi_java_callbacks.res +++ b/tests/sav/test_ffi_java_callbacks.res @@ -1,4 +1,4 @@ -777 From Nit +777 11 12346 diff --git a/tests/sav/test_ffi_java_generics.res b/tests/sav/test_ffi_java_generics.res index 514b4d6..6803f77 100644 --- a/tests/sav/test_ffi_java_generics.res +++ b/tests/sav/test_ffi_java_generics.res @@ -4,9 +4,9 @@ c d e f -e -f remove: a remove: b remove: c remove: d +e +f diff --git a/tests/sav/test_ffi_java_string.res b/tests/sav/test_ffi_java_string.res index e11e7e7..fb6d6df 100644 --- a/tests/sav/test_ffi_java_string.res +++ b/tests/sav/test_ffi_java_string.res @@ -1,4 +1,4 @@ Created in Nit -Also created in Nit Created in Java +Also created in Nit Also created in Java diff --git a/tests/sav/test_ffi_java_use_module.res b/tests/sav/test_ffi_java_use_module.res index f9585e2..de3915e 100644 --- a/tests/sav/test_ffi_java_use_module.res +++ b/tests/sav/test_ffi_java_use_module.res @@ -1,5 +1,5 @@ -777 -asdf From Nit +777 11 12346 +asdf diff --git a/tests/sav/test_file_open_fail.res b/tests/sav/test_file_open_fail.res new file mode 100644 index 0000000..613542b --- /dev/null +++ b/tests/sav/test_file_open_fail.res @@ -0,0 +1,2 @@ +Error: Opening file at 'donotcreate.bing' failed with 'No such file or directory' +Error: Opening file at 'donotcreate.bing' failed with 'No such file or directory' diff --git a/tests/sav/test_jvm.res b/tests/sav/test_jvm.res index 2972528..9fb5305 100644 --- a/tests/sav/test_jvm.res +++ b/tests/sav/test_jvm.res @@ -1,14 +1,14 @@ +Compilation des classes Java ... +Initialisation de la JVM ... +---------------------Test 1---------------------- From java, pushing premier From java, pushing deuxi?me From java, pushing troisi?me From java, popping premier -From java, popping deuxi?me -From java, popping troisi?me -Compilation des classes Java ... -Initialisation de la JVM ... ----------------------Test 1---------------------- premier +From java, popping deuxi?me deuxième +From java, popping troisi?me troisième --------------------Test 2--------------------- true diff --git a/tests/test_fdstream.nit b/tests/test_fdstream.nit index c1e3e84..6de686a 100644 --- a/tests/test_fdstream.nit +++ b/tests/test_fdstream.nit @@ -14,15 +14,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -import stream +import file -var fd_in = new FDIStream(0) -var fd_out = new FDOStream(1) -var fd_err = new FDOStream(2) +var fd_in = new IFStream.from_fd(0) +var fd_out = new OFStream.from_fd(1) +var fd_err = new OFStream.from_fd(2) fd_out.write("Hello\n") var s = fd_in.read_line fd_out.write(s) +fd_out.write("\n") fd_err.write("World\n") diff --git a/tests/test_file_open_fail.nit b/tests/test_file_open_fail.nit new file mode 100644 index 0000000..f71ed82 --- /dev/null +++ b/tests/test_file_open_fail.nit @@ -0,0 +1,29 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +var ifs = new IFStream.open("donotcreate.bing") + +var s = ifs.read_all + +ifs.close + +if ifs.last_error != null then print ifs.last_error.as(not null) + +ifs.reopen + +s = ifs.read_all + +ifs.close + +if ifs.last_error != null then print ifs.last_error.as(not null) diff --git a/tests/test_stream_poll.nit b/tests/test_stream_poll.nit index a893976..7981d06 100644 --- a/tests/test_stream_poll.nit +++ b/tests/test_stream_poll.nit @@ -25,7 +25,7 @@ p1 = new IProcess( "sleep", "0.2" ) p2 = new IProcess( "sleep", "0.1" ) p3 = new IProcess( "sleep", "0.4" ) -var order = new Array[FDStream] +var order = new Array[FStream] var streams = [p1.stream_in, p2.stream_in, p3.stream_in] while not streams.is_empty do @@ -33,7 +33,7 @@ while not streams.is_empty do if s == null then continue # may have been interrupted order.add( s ) - streams.remove( s.as(FDIStream ) ) + streams.remove( s.as(IFStream ) ) end print order[0] == p2.stream_in