# 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.
-#
-# Targets the PNaCl platform
+
+# Provides PNaCl support for Nit.
#
# To use this module and compile for PNaCl, you must install the
# NaCl SDK (This file is based on Pepper 33).
# If NACL_SDK_ROOT is not set in your PATH, you have to work in
# 'nacl_sdk/pepper_your_pepper_version/getting_started/your_project_folder'.
-#
-# Provides PNaCl support for Nit.
module pnacl is platform
import standard
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
+ #include <poll.h>
#define MAX_DICTIONARY_QUEUE_SIZE 200
#define MAX_MESSAGE_QUEUE_SIZE 10
}
/* 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.
# Standard input and output can be handled through streams.
module exec
- import stream
+ import file
# Simple sub-process
class Process
var arguments: nullable Array[String]
# Launch a command with some arguments
- init(command: String, arguments: String...)
- do
+ init(command: String, arguments: String...) is old_style_init do
self.command = command
self.arguments = arguments
execute
class IProcess
super Process
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
redef fun execute
do
super
- stream_in = new FDIStream(data.out_fd)
+ stream_in = new IFStream.from_fd(data.out_fd)
end
end
class OProcess
super Process
super OStream
+
+ # File Descriptor used for the output.
var stream_out: OStream is noinit
redef fun close do stream_out.close
redef fun execute
do
super
- stream_out = new FDOStream(data.in_fd)
+ stream_out = new OFStream.from_fd(data.in_fd)
end
end
end
redef class NativeString
+ # Execute self as a shell command.
+ #
+ # See the posix function system(3).
fun system: Int is extern "string_NativeString_NativeString_system_0"
end
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
+ #include <poll.h>
+ #include <errno.h>
`}
# File Abstract Stream
# The FILE *.
private var file: nullable NativeFile = null
+ # The status of a file. see POSIX stat(2).
fun file_stat: FileStat do return _file.file_stat
# 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
# 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
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
_buffer.length = nb
_buffer_pos = 0
end
-
+
# End of file?
redef var end_reached: Bool = false
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
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
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.
class Stdin
super IFStream
redef fun poll_in: Bool is extern "file_stdin_poll_in"
end
+# Standard output stream.
class Stdout
super OFStream
init do
end
end
+# Standard error stream.
class Stderr
super OFStream
init do
end
# returns files contained within the directory represented by self
- fun files : Set[ String ] is extern import HashSet[String], HashSet[String].add, NativeString.to_s, String.to_cstring, HashSet[String].as(Set[String]) `{
+ fun files: Array[String] is extern import Array[String], Array[String].add, NativeString.to_s, String.to_cstring `{
char *dir_path;
DIR *dir;
}
else
{
- HashSet_of_String results;
+ Array_of_String results;
String file_name;
struct dirent *de;
- results = new_HashSet_of_String();
+ results = new_Array_of_String();
while ( ( de = readdir( dir ) ) != NULL )
if ( strcmp( de->d_name, ".." ) != 0 &&
strcmp( de->d_name, "." ) != 0 )
{
file_name = NativeString_to_s( strdup( de->d_name ) );
- HashSet_of_String_add( results, file_name );
+ Array_of_String_add( results, file_name );
}
closedir( dir );
- return HashSet_of_String_as_Set_of_String( results );
+ return results;
}
`}
end
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"
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
# 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<in_len; i ++ ) {
+ int fd;
+ fd = Array_of_Int__index( in_fds, i );
+
+ c_fds[i].fd = fd;
+ c_fds[i].events = POLLIN;
+ }
+
+ /* output streams */
+ for ( i=0; i<out_len; i ++ ) {
+ int fd;
+ fd = Array_of_Int__index( out_fds, i );
+
+ c_fds[i].fd = fd;
+ c_fds[i].events = POLLOUT;
+ }
+
+ /* poll all fds, unlimited timeout */
+ result = poll( c_fds, total_len, -1 );
+
+ if ( result > 0 ) {
+ /* analyse results */
+ for ( i=0; i<total_len; i++ )
+ if ( c_fds[i].revents & c_fds[i].events || /* awaited event */
+ c_fds[i].revents & POLLHUP ) /* closed */
+ {
+ first_polled_fd = c_fds[i].fd;
+ break;
+ }
+
+ return Int_as_nullable( first_polled_fd );
+ }
+ else if ( result < 0 )
+ fprintf( stderr, "Error in Stream:poll: %s\n", strerror( errno ) );
+
+ return null_Int();
+ `}
+
end
# Print `objects` on the standard output (`stdout`).
module stream
intrude import ropes
+ import error
in "C" `{
#include <unistd.h>
- #include <poll.h>
- #include <errno.h>
#include <string.h>
#include <signal.h>
`}
+ # 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
# 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
end
# Read a string until the end of the line.
+ #
+ # The line terminator '\n', if any, is preserved in each line.
+ # Use the method `Text::chomp` to safely remove it.
+ #
+ # ~~~
+ # var txt = "Hello\n\nWorld\n"
+ # var i = new StringIStream(txt)
+ # assert i.read_line == "Hello\n"
+ # assert i.read_line == "\n"
+ # assert i.read_line == "World\n"
+ # assert i.eof
+ # ~~~
+ #
+ # If `\n` is not present at the end of the result, it means that
+ # a non-eol terminated last line was returned.
+ #
+ # ~~~
+ # var i2 = new StringIStream("hello")
+ # assert not i2.eof
+ # assert i2.read_line == "hello"
+ # assert i2.eof
+ # ~~~
+ #
+ # 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)
return s.to_s
end
+ # Read all the lines until the eof.
+ #
+ # The line terminator '\n' is removed in each line,
+ #
+ # ~~~
+ # var txt = "Hello\n\nWorld\n"
+ # var i = new StringIStream(txt)
+ # assert i.read_lines == ["Hello", "", "World"]
+ # ~~~
+ #
+ # This method is more efficient that splitting
+ # the result of `read_all`.
+ #
+ # NOTE: Only LINE FEED (`\n`) is considered to delimit the end of lines.
+ fun read_lines: Array[String]
+ do
+ var res = new Array[String]
+ while not eof do
+ res.add read_line.chomp
+ end
+ return res
+ end
+
# 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
end
# Read a string until the end of the line and append it to `s`.
+ #
+ # 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
end
# IStream capable of declaring if readable without blocking
- interface PollableIStream
+ abstract class PollableIStream
super IStream
# Is there something to read? (without blocking)
end
# Abstract output stream
- interface OStream
+ abstract class OStream
super IOS
# write a string
fun write(s: Text) is abstract
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
redef fun read(i)
do
+ if last_error != null then return ""
if _buffer.length == _buffer_pos then
if not eof then
fill_buffer
redef fun read_all
do
+ if last_error != null then return ""
var s = new FlatBuffer
while not eof do
var j = _buffer_pos
end
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<in_len; i ++ ) {
- int fd;
- fd = Array_of_Int__index( in_fds, i );
-
- c_fds[i].fd = fd;
- c_fds[i].events = POLLIN;
- }
-
- /* output streams */
- for ( i=0; i<out_len; i ++ ) {
- int fd;
- fd = Array_of_Int__index( out_fds, i );
-
- c_fds[i].fd = fd;
- c_fds[i].events = POLLOUT;
- }
-
- /* poll all fds, unlimited timeout */
- result = poll( c_fds, total_len, -1 );
-
- if ( result > 0 ) {
- /* analyse results */
- for ( i=0; i<total_len; i++ )
- if ( c_fds[i].revents & c_fds[i].events || /* awaited event */
- c_fds[i].revents & POLLHUP ) /* closed */
- {
- first_polled_fd = c_fds[i].fd;
- break;
- }
-
- return Int_as_nullable( first_polled_fd );
- }
- else if ( result < 0 )
- fprintf( stderr, "Error in Stream:poll: %s\n", strerror( errno ) );
-
- return null_Int();
- `}
- end
-
# Stream to a String.
#
# Mainly used for compatibility with OStream type and tests.
content.add(str.to_s)
end
+ # Is the stream closed?
protected var closed = false
+
redef fun close do closed = true
end
import semantize
private import parser::tables
import mixin
+ import primitive_types
redef class ToolContext
# --discover-call-trace
init_instance_primitive(self.true_instance)
self.false_instance = new PrimitiveInstance[Bool](mainmodule.bool_type, false)
init_instance_primitive(self.false_instance)
- self.null_instance = new MutableInstance(mainmodule.model.null_type)
+ self.null_instance = new PrimitiveInstance[nullable Object](mainmodule.model.null_type, null)
end
# Starts the interpreter on the main module of a program
# Subtype test in the context of the mainmodule
fun is_subtype(sub, sup: MType): Bool
do
- return sub.is_subtype(self.mainmodule, self.frame.arguments.first.mtype.as(MClassType), sup)
+ return sub.is_subtype(self.mainmodule, current_receiver_class, sup)
end
+ # Get a primitive method in the context of the main module
fun force_get_primitive_method(name: String, recv: MType): MMethod
do
assert recv isa MClassType
- return self.modelbuilder.force_get_primitive_method(self.frame.current_node, name, recv.mclass, self.mainmodule)
+ return self.modelbuilder.force_get_primitive_method(current_node, name, recv.mclass, self.mainmodule)
end
# Is a return executed?
return res
end
+ # Return a instance associated to a primitive class
+ # Current primitive classes are `Int`, `Bool`, and `String`
fun value_instance(object: Object): Instance
do
if object isa Int then
return b.to_s
end
+ # The current node, used to print errors, debug and stack-traces
+ fun current_node: nullable ANode
+ do
+ if frames.is_empty then return null
+ return frames.first.current_node
+ end
+
+ # The dynamic type of the current `self`
+ fun current_receiver_class: MClassType
+ do
+ return frames.first.arguments.first.mtype.as(MClassType)
+ end
+
# Exit the program with a message
fun fatal(message: String)
do
- if frames.is_empty then
+ var node = current_node
+ if node == null then
print message
else
- self.frame.current_node.fatal(self, message)
+ node.fatal(self, message)
end
exit(1)
end
# Debug on the current node
fun debug(message: String)
do
- if frames.is_empty then
+ var node = current_node
+ if node == null then
print message
else
- self.frame.current_node.debug(message)
+ node.debug(message)
end
end
assert args.length == mpropdef.msignature.arity + 1 else debug("Invalid arity for {mpropdef}. {args.length} arguments given.")
# Look for the AST node that implements the property
- var mproperty = mpropdef.mproperty
var val = mpropdef.constant_value
- if self.modelbuilder.mpropdef2npropdef.has_key(mpropdef) then
- var npropdef = self.modelbuilder.mpropdef2npropdef[mpropdef]
- self.parameter_check(npropdef, mpropdef, args)
- return npropdef.call(self, mpropdef, args)
- else if mproperty.is_root_init then
- var nclassdef = self.modelbuilder.mclassdef2nclassdef[mpropdef.mclassdef]
- self.parameter_check(nclassdef, mpropdef, args)
- return nclassdef.call(self, mpropdef, args)
+
+ var node = modelbuilder.mpropdef2node(mpropdef)
+ if node isa APropdef then
+ self.parameter_check(node, mpropdef, args)
+ return node.call(self, mpropdef, args)
+ else if node isa AClassdef then
+ self.parameter_check(node, mpropdef, args)
+ return node.call(self, mpropdef, args)
+ else if node != null then
+ fatal("Fatal Error: method {mpropdef} associated to unexpected AST node {node.location}")
+ abort
else if val != null then
return value_instance(val)
else
end
end
- # Generate type checks in the C code to check covariant parameters
+ # Execute type checks of covariant parameters
fun parameter_check(node: ANode, mpropdef: MMethodDef, args: Array[Instance])
do
var msignature = mpropdef.msignature
var origmtype = mpropdef.mproperty.intro.msignature.mparameters[i].mtype
if not origmtype.need_anchor then continue
+ #print "{mpropdef}: {mpropdef.mproperty.intro.msignature.mparameters[i]}"
+
# get the parameter type
var mtype = msignature.mparameters[i].mtype
var anchor = args.first.mtype.as(MClassType)
self.send(p, args)
else if p isa MAttribute then
assert recv isa MutableInstance
- recv.attributes[p] = arguments[i]
+ write_attribute(p, recv, arguments[i])
i += 1
else abort
end
var cds = mtype.collect_mclassdefs(self.mainmodule).to_a
self.mainmodule.linearize_mclassdefs(cds)
for cd in cds do
- if not self.modelbuilder.mclassdef2nclassdef.has_key(cd) then continue
- var n = self.modelbuilder.mclassdef2nclassdef[cd]
- for npropdef in n.n_propdefs do
- if npropdef isa AAttrPropdef then
- res.add(npropdef)
- end
- end
+ res.add_all(modelbuilder.collect_attr_propdef(cd))
end
cache[mtype] = res
return mainmodule.get_primitive_class(name)
end
- # This function determine the correct type according the reciever of the current definition (self).
+ # This function determines the correct type according to the receiver of the current propdef (self).
fun unanchor_type(mtype: MType): MType
do
- return mtype.anchor_to(self.mainmodule, self.frame.arguments.first.mtype.as(MClassType))
+ return mtype.anchor_to(self.mainmodule, current_receiver_class)
end
# Placebo instance used to mark internal error result when `null` already have a meaning.
# The real value encapsulated if the instance is primitive.
# Else aborts.
- fun val: Object do abort
+ fun val: nullable Object do abort
end
# A instance with attribute (standards objects)
# Special instance to handle primitives values (int, bool, etc.)
# The trick it just to encapsulate the <<real>> value
-class PrimitiveInstance[E: Object]
+class PrimitiveInstance[E]
super Instance
# The real value encapsulated
redef fun ==(o)
do
- if not o isa PrimitiveInstance[Object] then return false
+ if not o isa PrimitiveInstance[nullable Object] then return false
return self.val == o.val
end
redef fun eq_is(o)
do
- if not o isa PrimitiveInstance[Object] then return false
+ if not o isa PrimitiveInstance[nullable Object] then return false
return self.val.is_same_instance(o.val)
end
- redef fun to_s do return "{mtype}#{val.object_id}({val})"
+ redef fun to_s do return "{mtype}#{val.object_id}({val or else "null"})"
redef fun to_i do return val.as(Int)
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
return v.bool_instance(args[0].to_f.is_nan)
else if pname == "is_inf_extern" then
return v.bool_instance(args[0].to_f.is_inf != 0)
+ else if pname == "round" then
+ return v.float_instance(args[0].to_f.round)
end
else if cname == "NativeString" then
if pname == "new" then
else if pname == "atof" then
return v.float_instance(recvval.to_f)
end
+ else if cname == "String" then
+ var cs = v.send(v.force_get_primitive_method("to_cstring", args.first.mtype), [args.first])
+ var str = cs.val.to_s
+ if pname == "files" then
+ var res = new Array[Instance]
+ for f in str.files do res.add v.string_instance(f)
+ return v.array_instance(res, v.get_primitive_class("String").mclass_type)
+ end
else if pname == "calloc_string" then
return v.native_string_instance("!" * args[1].to_i)
else if cname == "NativeArray" then
else if pname == "length" then
return v.int_instance(recvval.length)
else if pname == "copy_to" then
- recvval.copy(0, args[2].to_i, args[1].val.as(Array[Instance]), 0)
+ recvval.copy_to(0, args[2].to_i, args[1].val.as(Array[Instance]), 0)
return null
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)
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
end
end
-redef class AbstractArray[E]
- fun copy(start: Int, len: Int, dest: AbstractArray[E], new_start: Int)
- do
- self.copy_to(start, len, dest, new_start)
- end
-end
-
redef class AAttrPropdef
redef fun call(v, mpropdef, args)
do