Merge: Floats in exponent notation
authorJean Privat <jean@pryen.org>
Thu, 4 Jun 2015 10:35:10 +0000 (06:35 -0400)
committerJean Privat <jean@pryen.org>
Thu, 4 Jun 2015 10:35:10 +0000 (06:35 -0400)
As a new addition to the parser, as requested in #1261, literal floating-point values in exponent notation.

Pull-Request: #1427
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>
Reviewed-by: Jean Privat <jean@pryen.org>
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>

21 files changed:
lib/android/bundle/bundle.nit
lib/android/intent/intent_api10.nit
lib/binary/binary.nit
lib/cpp.nit
lib/mnit_android/android_assets.nit
lib/socket/socket.nit
lib/socket/socket_c.nit
share/man/nitc.md
src/compiler/abstract_compiler.nit
src/compiler/compiler_ffi/light.nit
src/compiler/separate_compiler.nit
src/ffi/java.nit
src/ffi/light_ffi_base.nit
src/mkcsrc
src/nitni/nitni_base.nit
src/parser/parser_nodes.nit
src/parser/parser_work.nit
tests/sav/neo_doxygen_dump_args4.res
tests/sav/neo_doxygen_dump_args5.res
tests/test_ffi_cpp_duplicated_callback_a.nit
tests/test_ffi_cpp_duplicated_callback_b.nit

index edb0c88..76babb4 100644 (file)
@@ -63,7 +63,7 @@ extern class NativeBundle in "Java" `{ android.os.Bundle `}
        `}
        # FIXME: Java's `char` are encoded on 16-bits whereas Nit's are on 8-bits.
        fun put_char(key: JavaString, value: Char) in "Java" `{
-               self.putChar(key, value);
+               self.putChar(key, (char)value);
        `}
        fun put_short(key: JavaString, value: Int) in "Java" `{
                self.putShort(key, (short) value);
@@ -148,7 +148,7 @@ extern class NativeBundle in "Java" `{ android.os.Bundle `}
                char[] java_array = new char[(int)Array_of_Char_length(value)];
 
                for(int i=0; i < java_array.length; ++i)
-                       java_array[i] = Array_of_Char__index(value, i);
+                       java_array[i] = (char)Array_of_Char__index(value, i);
 
                self.putCharArray(key, java_array);
        `}
@@ -218,10 +218,10 @@ extern class NativeBundle in "Java" `{ android.os.Bundle `}
                return self.getByte(key, (byte) def_value);
        `}
        # FIXME: Java's `char` are encoded on 16-bits whereas Nit's are on 8-bits.
-       fun get_char(key: JavaString): Char in "Java" `{ return self.getChar(key); `}
+       fun get_char(key: JavaString): Char in "Java" `{ return (int)self.getChar(key); `}
        # FIXME: Java's `char` are encoded on 16-bits whereas Nit's are on 8-bits.
        fun get_char_with_def_value(key: JavaString, def_value: Char): Char in "Java" `{
-               return self.getChar(key, def_value);
+               return (int)self.getChar(key, (char)def_value);
        `}
        fun get_short(key: JavaString): Int in "Java" `{ return (short) self.getShort(key); `}
        fun get_short_with_def_value(key: JavaString, def_value: Int): Int in "Java" `{
@@ -335,7 +335,7 @@ extern class NativeBundle in "Java" `{ android.os.Bundle `}
                if (java_array == null) return nit_array;
 
                for(int i=0; i < java_array.length; ++i)
-                       Array_of_Char_add(nit_array, java_array[i]);
+                       Array_of_Char_add(nit_array, (int)java_array[i]);
 
                return nit_array;
        `}
index 2d536fd..8c6a928 100644 (file)
@@ -81,7 +81,7 @@ extern class NativeIntent in "Java" `{ android.content.Intent `}
        `}
        # FIXME: Java's `char` are encoded on 16-bits whereas Nit's are on 8-bits.
        fun char_extra(name: JavaString, def_value: Char): Char in "Java" `{
-               return self.getCharExtra(name, def_value);
+               return (int)self.getCharExtra(name, (char)def_value);
        `}
        fun char_sequence_array_extra(name: JavaString): Array[String]
          import StringCopyArray, StringCopyArray.add, StringCopyArray.collection in "Java" `{
@@ -244,7 +244,7 @@ extern class NativeIntent in "Java" `{ android.content.Intent `}
                char[] java_array = new char[(int)Array_of_Char_length(value)];
 
                for (int i=0; i < java_array.length; ++i)
-                       java_array[i] = Array_of_Char__index(value, i);
+                       java_array[i] = (char)Array_of_Char__index(value, i);
 
                return self.putExtra(name, java_array);
        `}
index 59ec88d..f4be1eb 100644 (file)
@@ -45,10 +45,13 @@ in "C" `{
        #include <endian.h>
 
        // Android compatibility
+       #ifndef be32toh
+               #define be32toh(val) betoh32(val)
+               #define le32toh(val) letoh32(val)
+       #endif
+
        #ifndef be64toh
                #define be64toh(val) betoh64(val)
-       #endif
-       #ifndef le64toh
                #define le64toh(val) letoh64(val)
        #endif
 `}
@@ -148,11 +151,15 @@ redef abstract class Reader
        super BinaryStream
 
        # Read a single byte and return `true` if its value is different than 0
+       #
+       # Returns `false` when an error is pending (`last_error != null`).
        fun read_bool: Bool do return read_byte != 0
 
        # Get an `Array` of 8 `Bool` by reading a single byte
        #
        # To be used with `BinaryWriter::write_bits`.
+       #
+       # Returns an array of `false` when an error is pending (`last_error != null`).
        fun read_bits: Array[Bool]
        do
                var int = read_byte
@@ -163,12 +170,14 @@ redef abstract class Reader
        # Read a null terminated string
        #
        # To be used with `Writer::write_string`.
+       #
+       # Returns a truncated string when an error is pending (`last_error != null`).
        fun read_string: String
        do
                var buf = new FlatBuffer
                loop
                        var byte = read_byte
-                       if byte == 0x00 then return buf.to_s
+                       if byte == null or byte == 0x00 then return buf.to_s
                        buf.chars.add byte.ascii
                end
        end
@@ -176,6 +185,8 @@ redef abstract class Reader
        # Read the length as a 64 bits integer, then the content of the block
        #
        # To be used with `Writer::write_block`.
+       #
+       # Returns a truncated string when an error is pending (`last_error != null`).
        fun read_block: String
        do
                var length = read_int64
@@ -187,6 +198,8 @@ redef abstract class Reader
        #
        # Using this format may result in a loss of precision as it uses less bits
        # than Nit `Float`.
+       #
+       # Returns `0.0` when an error is pending (`last_error != null`).
        fun read_float: Float
        do
                if last_error != null then return 0.0
@@ -223,6 +236,8 @@ redef abstract class Reader
        `}
 
        # Read a floating point on 64 bits and return it as a `Float`
+       #
+       # Returns `0.0` when an error is pending (`last_error != null`).
        fun read_double: Float
        do
                if last_error != null then return 0.0
@@ -271,6 +286,8 @@ redef abstract class Reader
        #
        # Using this format may result in a loss of precision as the length of a
        # Nit `Int` may be less than 64 bits on some platforms.
+       #
+       # Returns `0` when an error is pending (`last_error != null`).
        fun read_int64: Int
        do
                if last_error != null then return 0
index a2896d3..c64ae33 100644 (file)
@@ -31,6 +31,6 @@ end
 redef class NativeString
        # Get `self` as a `CppString`
        fun to_cpp_string(length: Int): CppString in "C++" `{
-               return new std::string(self, length);
+               return new std::string(reinterpret_cast<char*>(self), length);
        `}
 end
index 51e1ec8..6531035 100644 (file)
@@ -231,7 +231,7 @@ redef universal Int
        # The first power of `exp` greater or equal to `self`
        private fun next_pow(exp: Int): Int
        do
-               var p = 0
+               var p = 1
                while p < self do p = p*exp
                return p
        end
index 4885805..a40cc5d 100644 (file)
@@ -71,14 +71,29 @@ class TCPStream
                        closed = true
                        return
                end
-               var hostname = socket.gethostbyname(host)
-               addrin = new NativeSocketAddrIn.with_hostent(hostname, port)
 
+               var hostname = sys.gethostbyname(host.to_cstring)
+               if hostname.address_is_null then
+                       # Error in name lookup
+                       var err = sys.h_errno
+                       last_error = new IOError(err.to_s)
+
+                       closed = true
+                       end_reached = true
+
+                       return
+               end
+
+               addrin = new NativeSocketAddrIn.with_hostent(hostname, port)
                address = addrin.address
                init(addrin.port, hostname.h_name)
 
                closed = not internal_connect
                end_reached = closed
+               if closed then
+                       # Connection failed
+                       last_error = new IOError(errno.strerror)
+               end
        end
 
        # Creates a client socket, this is meant to be used by accept only
index d9056d6..94eecd7 100644 (file)
@@ -121,8 +121,6 @@ extern class NativeSocket `{ int* `}
 
        fun descriptor: Int `{ return *self; `}
 
-       fun gethostbyname(n: String): NativeSocketHostent import String.to_cstring `{ return gethostbyname(String_to_cstring(n)); `}
-
        fun connect(addrIn: NativeSocketAddrIn): Int `{
                return connect(*self, (struct sockaddr*)addrIn, sizeof(*addrIn));
        `}
@@ -482,3 +480,52 @@ extern class NativeSocketPollValues `{ int `}
                return self | other;
        `}
 end
+
+redef class Sys
+       # Get network host entry
+       fun gethostbyname(name: NativeString): NativeSocketHostent `{
+               return gethostbyname(name);
+       `}
+
+       # Last error raised by `gethostbyname`
+       fun h_errno: HErrno `{ return h_errno; `}
+end
+
+# Error code of `Sys::h_errno`
+extern class HErrno `{ int `}
+       # The specified host is unknown
+       fun host_not_found: Bool `{ return self == HOST_NOT_FOUND; `}
+
+       # The requested name is valid but does not have an IP address
+       #
+       # Same as `no_data`.
+       fun no_address: Bool `{ return self == NO_ADDRESS; `}
+
+       # The requested name is valid byt does not have an IP address
+       #
+       # Same as `no_address`.
+       fun no_data: Bool `{ return self == NO_DATA; `}
+
+       # A nonrecoverable name server error occurred
+       fun no_recovery: Bool `{ return self == NO_RECOVERY; `}
+
+       # A temporary error occurred on an authoritative name server, try again later
+       fun try_again: Bool `{ return self == TRY_AGAIN; `}
+
+       redef fun to_s
+       do
+               if host_not_found then
+                       return "The specified host is unknown"
+               else if no_address then
+                       return "The requested name is valid but does not have an IP address"
+               else if no_recovery then
+                       return "A nonrecoverable name server error occurred"
+               else if try_again then
+                       return "A temporary error occurred on an authoritative name server, try again later"
+               else
+                       # This may happen if another call was made to `gethostbyname`
+                       # before we fetch the error code.
+                       return "Unknown error on `gethostbyname`"
+               end
+       end
+end
index 91e8d8c..9e0fbf5 100644 (file)
@@ -404,8 +404,18 @@ They are useless for a normal user.
 `--no-main`
 :   Do not generate main entry point.
 
-`--stacktrace`
-:   Control the generation of stack traces.
+`--no-stacktrace`
+:   The compiled program will not display stack traces on runtime errors.
+
+    Because stack traces rely on libunwind, this option might be useful in order to generate more portable binaries
+    since libunwind might be non available on the runtime system (or available with an ABI incompatible version).
+
+    The generated C is API-portable and can be reused, distributed and compiled on any supported system.
+    If the option `--no-stacktrace` is not used but the development files of the library `libunwind` are not available, then a warning will be displayed
+    and stack trace will be disabled.
+
+    Note that the `--no-stacktrace` option (or this absence) can be toggled manually in the generated Makefile (search `NO_STACKTRACE` in the Makefile).
+    Moreover, the environment variable `NIT_NO_STACK` (see bellow) can also be used at runtime to disable stack traces.
 
 `--max-c-lines`
 :   Maximum number of lines in generated C files. Use 0 for unlimited.
@@ -481,6 +491,20 @@ This option is used to test the robustness of the tools by allowing phases to pr
     * large: disable the GC and just allocate a large memory area to use for all instantiation.
     * help: show the list of available options.
 
+`NIT_NO_STACK`
+:   Runtime control of stack traces.
+
+    By default, stack traces are printed when a runtime errors occurs during the execution of a compiled program.
+    When setting this environment variable to a non empty value, such stack traces are disabled.
+
+    The environment variable is used when programs are executed, not when they are compiled.
+    Thus, you do not need to recompile programs in order to disable generated stack traces.
+
+    Note that stack traces require that, during the compilation, development files of the library `libunwind` are available.
+    If they are not available, then programs are compiled without any stack trace support.
+
+    To completely disable stack traces, see the option `--no-stacktrace`.
+
 # SEE ALSO
 
 The Nit language documentation and the source code of its tools and libraries may be downloaded from <http://nitlanguage.org>
index 2cf47e2..a095201 100644 (file)
@@ -63,8 +63,8 @@ redef class ToolContext
        var opt_invocation_metrics = new OptionBool("Enable static and dynamic count of all method invocations", "--invocation-metrics")
        # --isset-checks-metrics
        var opt_isset_checks_metrics = new OptionBool("Enable static and dynamic count of isset checks before attributes access", "--isset-checks-metrics")
-       # --stacktrace
-       var opt_stacktrace = new OptionString("Control the generation of stack traces", "--stacktrace")
+       # --no-stacktrace
+       var opt_no_stacktrace = new OptionBool("Disable the generation of stack traces", "--no-stacktrace")
        # --no-gcc-directives
        var opt_no_gcc_directive = new OptionArray("Disable a advanced gcc directives for optimization", "--no-gcc-directive")
        # --release
@@ -76,7 +76,7 @@ redef class ToolContext
                self.option_context.add_option(self.opt_output, self.opt_dir, self.opt_no_cc, self.opt_no_main, self.opt_make_flags, self.opt_compile_dir, self.opt_hardening)
                self.option_context.add_option(self.opt_no_check_covariance, self.opt_no_check_attr_isset, self.opt_no_check_assert, self.opt_no_check_autocast, self.opt_no_check_null, self.opt_no_check_all)
                self.option_context.add_option(self.opt_typing_test_metrics, self.opt_invocation_metrics, self.opt_isset_checks_metrics)
-               self.option_context.add_option(self.opt_stacktrace)
+               self.option_context.add_option(self.opt_no_stacktrace)
                self.option_context.add_option(self.opt_no_gcc_directive)
                self.option_context.add_option(self.opt_release)
                self.option_context.add_option(self.opt_max_c_lines, self.opt_group_c_files)
@@ -88,17 +88,6 @@ redef class ToolContext
        do
                super
 
-               var st = opt_stacktrace.value
-               if st == "none" or st == "libunwind" or st == "nitstack" then
-                       # Fine, do nothing
-               else if st == "auto" or st == null then
-                       # Default is nitstack
-                       opt_stacktrace.value = "nitstack"
-               else
-                       print "Option Error: unknown value `{st}` for --stacktrace. Use `none`, `libunwind`, `nitstack` or `auto`."
-                       exit(1)
-               end
-
                if opt_output.value != null and opt_dir.value != null then
                        print "Option Error: cannot use both --dir and --output"
                        exit(1)
@@ -212,7 +201,7 @@ class MakefileToolchain
        fun write_files(compile_dir: String, cfiles: Array[String])
        do
                var platform = compiler.target_platform
-               if self.toolcontext.opt_stacktrace.value == "nitstack" and platform.supports_libunwind then compiler.build_c_to_nit_bindings
+               if platform.supports_libunwind then compiler.build_c_to_nit_bindings
                var cc_opt_with_libgc = "-DWITH_LIBGC"
                if not platform.supports_libgc then cc_opt_with_libgc = ""
 
@@ -355,25 +344,50 @@ class MakefileToolchain
 
                makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g -O2 -Wno-unused-value -Wno-switch -Wno-attributes\nCINCL =\nLDFLAGS ?= \nLDLIBS  ?= -lm {linker_options.join(" ")}\n\n")
 
-               var ost = toolcontext.opt_stacktrace.value
-               if (ost == "libunwind" or ost == "nitstack") and platform.supports_libunwind then makefile.write("NEED_LIBUNWIND := YesPlease\n")
+               makefile.write "\n# SPECIAL CONFIGURATION FLAGS\n"
+               if platform.supports_libunwind then
+                       if toolcontext.opt_no_stacktrace.value then
+                               makefile.write "NO_STACKTRACE=True"
+                       else
+                               makefile.write "NO_STACKTRACE= # Set to `True` to enable"
+                       end
+               end
 
                # Dynamic adaptations
                # While `platform` enable complex toolchains, they are statically applied
                # For a dynamic adaptsation of the compilation, the generated Makefile should check and adapt things itself
+               makefile.write "\n\n"
 
                # Check and adapt the targeted system
                makefile.write("uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')\n")
-               makefile.write("ifeq ($(uname_S),Darwin)\n")
-               # remove -lunwind since it is already included on macosx
-               makefile.write("\tNEED_LIBUNWIND :=\n")
-               makefile.write("endif\n\n")
 
                # Check and adapt for the compiler used
                # clang need an additionnal `-Qunused-arguments`
                makefile.write("clang_check := $(shell sh -c '$(CC) -v 2>&1 | grep -q clang; echo $$?')\nifeq ($(clang_check), 0)\n\tCFLAGS += -Qunused-arguments\nendif\n")
 
-               makefile.write("ifdef NEED_LIBUNWIND\n\tLDLIBS += -lunwind\nendif\n")
+               if platform.supports_libunwind then
+                       makefile.write """
+ifneq ($(NO_STACKTRACE), True)
+  # Check and include lib-unwind in a portable way
+  ifneq ($(uname_S),Darwin)
+    # already included on macosx, but need to get the correct flags in other supported platforms.
+    ifeq ($(shell pkg-config --exists 'libunwind'; echo $$?), 0)
+      LDLIBS += `pkg-config --libs libunwind`
+      CFLAGS += `pkg-config --cflags libunwind`
+    else
+      $(warning "[_] stack-traces disabled. Please install libunwind-dev.")
+      CFLAGS += -D NO_STACKTRACE
+    endif
+  endif
+else
+  # Stacktraces disabled
+  CFLAGS += -D NO_STACKTRACE
+endif
+
+"""
+               else
+                       makefile.write("CFLAGS += -D NO_STACKTRACE\n\n")
+               end
 
                makefile.write("all: {outpath}\n")
                if outpath != real_outpath then
@@ -623,6 +637,7 @@ abstract class AbstractCompiler
                self.header.add_decl("#include <string.h>")
                self.header.add_decl("#include <sys/types.h>\n")
                self.header.add_decl("#include <unistd.h>\n")
+               self.header.add_decl("#include <stdint.h>\n")
                self.header.add_decl("#include \"gc_chooser.h\"")
                self.header.add_decl("#ifdef ANDROID")
                self.header.add_decl("  #include <android/log.h>")
@@ -730,19 +745,16 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
        do
                var v = self.new_visitor
                v.add_decl("#include <signal.h>")
-               var ost = modelbuilder.toolcontext.opt_stacktrace.value
                var platform = target_platform
 
-               if not platform.supports_libunwind then ost = "none"
-
                var no_main = platform.no_main or modelbuilder.toolcontext.opt_no_main.value
 
-               if ost == "nitstack" or ost == "libunwind" then
+               if platform.supports_libunwind then
+                       v.add_decl("#ifndef NO_STACKTRACE")
                        v.add_decl("#define UNW_LOCAL_ONLY")
                        v.add_decl("#include <libunwind.h>")
-                       if ost == "nitstack" then
-                               v.add_decl("#include \"c_functions_hash.h\"")
-                       end
+                       v.add_decl("#include \"c_functions_hash.h\"")
+                       v.add_decl("#endif")
                end
                v.add_decl("int glob_argc;")
                v.add_decl("char **glob_argv;")
@@ -776,7 +788,8 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
                end
 
                v.add_decl("static void show_backtrace(void) \{")
-               if ost == "nitstack" or ost == "libunwind" then
+               if platform.supports_libunwind then
+                       v.add_decl("#ifndef NO_STACKTRACE")
                        v.add_decl("char* opt = getenv(\"NIT_NO_STACK\");")
                        v.add_decl("unw_cursor_t cursor;")
                        v.add_decl("if(opt==NULL)\{")
@@ -790,20 +803,17 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
                        v.add_decl("PRINT_ERROR(\"-------------------------------------------------\\n\");")
                        v.add_decl("while (unw_step(&cursor) > 0) \{")
                        v.add_decl("    unw_get_proc_name(&cursor, procname, 100, &ip);")
-                       if ost == "nitstack" then
                        v.add_decl("    const char* recv = get_nit_name(procname, strlen(procname));")
                        v.add_decl("    if (recv != NULL)\{")
                        v.add_decl("            PRINT_ERROR(\"` %s\\n\", recv);")
                        v.add_decl("    \}else\{")
                        v.add_decl("            PRINT_ERROR(\"` %s\\n\", procname);")
                        v.add_decl("    \}")
-                       else
-                       v.add_decl("    PRINT_ERROR(\"` %s \\n\",procname);")
-                       end
                        v.add_decl("\}")
                        v.add_decl("PRINT_ERROR(\"-------------------------------------------------\\n\");")
                        v.add_decl("free(procname);")
                        v.add_decl("\}")
+                       v.add_decl("#endif /* NO_STACKTRACE */")
                end
                v.add_decl("\}")
 
@@ -1860,13 +1870,13 @@ redef class MClassType
                else if mclass.name == "Bool" then
                        return "short int"
                else if mclass.name == "Char" then
-                       return "char"
+                       return "uint32_t"
                else if mclass.name == "Float" then
                        return "double"
                else if mclass.name == "Byte" then
                        return "unsigned char"
                else if mclass.name == "NativeString" then
-                       return "char*"
+                       return "unsigned char*"
                else if mclass.name == "NativeArray" then
                        return "val*"
                else
@@ -2131,12 +2141,12 @@ redef class AMethPropdef
                                v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
                                return true
                        else if pname == "ascii" then
-                               v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
+                               v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null)))
                                return true
                        end
                else if cname == "Char" then
                        if pname == "output" then
-                               v.add("printf(\"%c\", {arguments.first});")
+                               v.add("printf(\"%c\", ((unsigned char){arguments.first}));")
                                return true
                        else if pname == "object_id" then
                                v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
@@ -2170,7 +2180,7 @@ redef class AMethPropdef
                                v.ret(v.new_expr("{arguments[0]}-'0'", ret.as(not null)))
                                return true
                        else if pname == "ascii" then
-                               v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
+                               v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
                                return true
                        end
                else if cname == "Byte" then
@@ -2310,10 +2320,10 @@ redef class AMethPropdef
                        end
                else if cname == "NativeString" then
                        if pname == "[]" then
-                               v.ret(v.new_expr("{arguments[0]}[{arguments[1]}]", ret.as(not null)))
+                               v.ret(v.new_expr("(uint32_t){arguments[0]}[{arguments[1]}]", ret.as(not null)))
                                return true
                        else if pname == "[]=" then
-                               v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
+                               v.add("{arguments[0]}[{arguments[1]}]=(unsigned char){arguments[2]};")
                                return true
                        else if pname == "copy_to" then
                                v.add("memmove({arguments[1]}+{arguments[4]},{arguments[0]}+{arguments[3]},{arguments[2]});")
@@ -2325,7 +2335,7 @@ redef class AMethPropdef
                                v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
                                return true
                        else if pname == "new" then
-                               v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null)))
+                               v.ret(v.new_expr("(unsigned char*)nit_alloc({arguments[1]})", ret.as(not null)))
                                return true
                        end
                else if cname == "NativeArray" then
@@ -2339,7 +2349,7 @@ redef class AMethPropdef
                        v.ret(v.new_expr("glob_sys", ret.as(not null)))
                        return true
                else if pname == "calloc_string" then
-                       v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null)))
+                       v.ret(v.new_expr("(unsigned char*)nit_alloc({arguments[1]})", ret.as(not null)))
                        return true
                else if pname == "calloc_array" then
                        v.calloc_array(ret.as(not null), arguments)
index 01579b0..1f59771 100644 (file)
@@ -43,6 +43,7 @@ redef class MModule
                ensure_compile_nitni_base(v)
 
                nitni_ccu.header_c_types.add("#include \"{c_name}._ffi.h\"\n")
+               nitni_ccu.header_c_types.add("#include <stdint.h>\n")
                nitni_ccu.header_c_types.add """
 extern void nitni_global_ref_incr(void*);
 extern void nitni_global_ref_decr(void*);
index 31a4f20..f50a2a7 100644 (file)
@@ -1193,7 +1193,7 @@ class SeparateCompilerVisitor
                                if mtype.name == "Int" then
                                        return self.new_expr("(long)({value})>>2", mtype)
                                else if mtype.name == "Char" then
-                                       return self.new_expr("(char)((long)({value})>>2)", mtype)
+                                       return self.new_expr("(uint32_t)((long)({value})>>2)", mtype)
                                else if mtype.name == "Bool" then
                                        return self.new_expr("(short int)((long)({value})>>2)", mtype)
                                else
index 3f2a21e..d5852f6 100644 (file)
@@ -480,7 +480,7 @@ redef class MClassType
                if ftype isa ForeignJavaType then return ftype.java_type.
                        replace('/', ".").replace('$', ".").replace(' ', "").replace('\n',"")
                if mclass.name == "Bool" then return "boolean"
-               if mclass.name == "Char" then return "char"
+               if mclass.name == "Char" then return "int"
                if mclass.name == "Int" then return "long"
                if mclass.name == "Float" then return "double"
                if mclass.name == "Byte" then return "byte"
@@ -492,7 +492,7 @@ redef class MClassType
                var ftype = mclass.ftype
                if ftype isa ForeignJavaType then return "jobject"
                if mclass.name == "Bool" then return "jboolean"
-               if mclass.name == "Char" then return "jchar"
+               if mclass.name == "Char" then return "jint"
                if mclass.name == "Int" then return "jlong"
                if mclass.name == "Float" then return "jdouble"
                if mclass.name == "Byte" then return "jbyte"
@@ -552,7 +552,7 @@ redef class MClassType
                        return "L{jni_type};"
                end
                if mclass.name == "Bool" then return "Z"
-               if mclass.name == "Char" then return "C"
+               if mclass.name == "Char" then return "I"
                if mclass.name == "Int" then return "J"
                if mclass.name == "Float" then return "D"
                if mclass.name == "Byte" then return "B"
@@ -565,7 +565,7 @@ redef class MClassType
 
                if ftype isa ForeignJavaType then return "Object"
                if mclass.name == "Bool" then return "Boolean"
-               if mclass.name == "Char" then return "Char"
+               if mclass.name == "Char" then return "Int"
                if mclass.name == "Int" then return "Long"
                if mclass.name == "Float" then return "Double"
                if mclass.name == "Byte" then return "Byte"
index 6791e5c..3385301 100644 (file)
@@ -161,10 +161,10 @@ redef class CCompilationUnit
 
                var h_file = "{base_name}.h"
                var guard = "{mmodule.c_name.to_upper}_NIT_H"
-               write_header_to_file(mmodule, "{compdir}/{h_file}", new Array[String], guard)
+               write_header_to_file(mmodule, "{compdir}/{h_file}", ["<stdint.h>"], guard)
 
                var c_file = "{base_name}.c"
-               write_body_to_file(mmodule, "{compdir}/{c_file}", ["<stdlib.h>", "<stdio.h>", "\"{h_file}\""])
+               write_body_to_file(mmodule, "{compdir}/{c_file}", ["<stdlib.h>", "<stdio.h>", "<stdint.h>", "\"{h_file}\""])
 
                files.add( "{compdir}/{c_file}" )
        end
index e1f43cc..de71f37 100755 (executable)
@@ -3,7 +3,7 @@
 # Regeneration of c_src from the current nitc
 
 rm -r ../c_src
-./nitc nith.nit --stacktrace none --semi-global --compile-dir ../c_src --output ../c_src/nitg --no-cc
+./nitc nith.nit --semi-global --compile-dir ../c_src --output ../c_src/nitg --no-cc
 
 # Remove old compilation flags
 sed -i -e 's/OLDNITCOPT=.*/OLDNITCOPT=/' Makefile
index 7cf6bbc..cc30171 100644 (file)
@@ -89,11 +89,11 @@ redef class MClassType
        do
                var name = mclass.name
                if name == "Bool" then return "int"
-               if name == "Char" then return "char"
+               if name == "Char" then return "uint32_t"
                if name == "Float" then return "double"
                if name == "Int" then return "long"
                if name == "Byte" then return "unsigned char"
-               if name == "NativeString" then return "char*"
+               if name == "NativeString" then return "unsigned char*"
                if mclass.kind == extern_kind then
                        var ctype = mclass.ctype
                        assert ctype != null
@@ -105,11 +105,11 @@ redef class MClassType
        redef fun cname_blind do
                var name = mclass.name
                if name == "Bool" then return "int"
-               if name == "Char" then return "char"
+               if name == "Char" then return "uint32_t"
                if name == "Float" then return "double"
                if name == "Int" then return "long"
                if name == "Byte" then return "unsigned char"
-               if name == "NativeString" then return "char*"
+               if name == "NativeString" then return "unsigned char*"
                if mclass.kind == extern_kind then return "void*"
                return "struct nitni_instance *"
        end
index 6ec146f..9131c3e 100644 (file)
@@ -311,6 +311,35 @@ abstract class Token
        # May have disappeared in the AST
        var next_token: nullable Token = null
 
+       # Is `self` a token discarded from the AST?
+       #
+       # Loose tokens are not present in the AST.
+       # It means they were identified by the lexer but were discarded by the parser.
+       # It also means that they are not visited or manipulated by AST-related functions.
+       #
+       # Each loose token is attached to the non-loose token that precedes or follows it.
+       # The rules are the following:
+       #
+       # * tokens that follow a non-loose token on a same line are attached to it.
+       #   See `next_looses`.
+       # * other tokens, thus that precede a non-loose token on the same line or the next one,
+       # are attached to this one. See `prev_looses`.
+       #
+       # Loose tokens are mostly end of lines (`TEol`) and comments (`TComment`).
+       # Whitespace are ignored by the lexer, so they are not even considered as loose tokens.
+       # See `blank_before` to get the whitespace that separate tokens.
+       var is_loose = false
+
+       # Loose tokens that precede `self`.
+       #
+       # These tokens start the line or belong to a line with only loose tokens.
+       var prev_looses = new Array[Token] is lazy
+
+       # Loose tokens that follow `self`
+       #
+       # These tokens are on the same line than `self`.
+       var next_looses = new Array[Token] is lazy
+
        # The verbatim blank text between `prev_token` and `self`
        fun blank_before: String
        do
index c2eff11..a344fc7 100644 (file)
@@ -141,7 +141,8 @@ class Parser
                                var node1 = pop
                                assert node1 isa AModule
                                var node = new Start(node1, node2)
-                               (new ComputeProdLocationVisitor).enter_visit(node)
+                               node2.parent = node
+                               (new ComputeProdLocationVisitor(lexer.file.first_token)).enter_visit(node)
                                return node
                        else if action_type == 3 then # ERROR
                                # skip injected tokens
@@ -176,21 +177,55 @@ end
 # Uses existing token locations to infer location of productions.
 private class ComputeProdLocationVisitor
        super Visitor
+
+       # The current (or starting) cursor on the token sequence used to collect loose tokens
+       var token: nullable Token
+
        # Currently visited productions that need a first token
        var need_first_prods = new Array[Prod]
 
        # Already visited epsilon productions that waits something after them
        var need_after_epsilons = new Array[Prod]
 
-       # Location of the last visited token in the current production
-       var last_location: nullable Location = null
+       # The last visited token in the current production
+       var last_token: nullable Token = null
 
        redef fun visit(n: ANode)
        do
                if n isa Token then
+                       # Skip injected tokens
                        if not isset n._location then return
+
+                       # Collect loose tokens (not in the AST) and attach them to token in the AST
+                       var cursor = token
+                       if n != cursor then
+                               var lt = last_token
+                               # In order, we have the tokens:
+                               # * `lt` the previous visited token in the AST (if any)
+                               # * then `cursor` the loose tokens to attach
+                               # * then `n` the current visited token in the AST
+
+                               # In the following, we advance `cursor` to add them to `lt.next_looses` or to `n.prev_looses`.
+                               if lt != null then
+                                       var ltl = lt.location.line_end
+                                       # floating tokens on the same line of a AST-token follows it
+                                       while cursor != null and cursor != n and ltl == cursor.location.line_start do
+                                               cursor.is_loose = true
+                                               lt.next_looses.add cursor
+                                               cursor = cursor.next_token
+                                       end
+                               end
+                               # other loose tokens precede the next AST-token
+                               while cursor != null and cursor != n do
+                                       cursor.is_loose = true
+                                       n.prev_looses.add cursor
+                                       cursor = cursor.next_token
+                               end
+                       end
+                       token = n.next_token
+
                        var loc = n._location
-                       _last_location = loc
+                       _last_token = n
 
                        # Add a first token to productions that need one
                        if not _need_first_prods.is_empty then
@@ -217,8 +252,7 @@ private class ComputeProdLocationVisitor
                        var startl = n._first_location
                        if startl != null then
                                # Non-epsilon production
-                               var endl = _last_location
-                               assert endl != null
+                               var endl = _last_token.location
 
                                if startl == endl then
                                        n.location = startl
index 0d6a211..a732359 100644 (file)
@@ -1457,7 +1457,7 @@ Edge
 8:MPropDef
 13:MAttributeDef
 =properties=JsonObject(5):
-{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.","\u000e2\u00080\u0009c"],"is_intro":true}
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["“Answer to the Ultimate Question of Life, the Universe, and Everything.","“"],"is_intro":true}
 ----
 =to=Entity#0:
 =labels=Array(4):
@@ -1481,7 +1481,7 @@ Edge
 8:MPropDef
 13:MAttributeDef
 =properties=JsonObject(5):
-{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.","\u000e2\u00080\u0009c"],"is_intro":true}
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["“Answer to the Ultimate Question of Life, the Universe, and Everything.","“"],"is_intro":true}
 ----
 =to=Entity#0:
 =labels=Array(4):
@@ -1722,7 +1722,7 @@ Edge
 8:MPropDef
 13:MAttributeDef
 =properties=JsonObject(5):
-{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.","\u000e2\u00080\u0009c"],"is_intro":true}
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["“Answer to the Ultimate Question of Life, the Universe, and Everything.","“"],"is_intro":true}
 
 
 Edge
index 70cda4d..5e63fb7 100644 (file)
@@ -1457,7 +1457,7 @@ Edge
 8:MPropDef
 13:MAttributeDef
 =properties=JsonObject(5):
-{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.","\u000e2\u00080\u0009c"],"is_intro":true}
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["“Answer to the Ultimate Question of Life, the Universe, and Everything.","“"],"is_intro":true}
 ----
 =to=Entity#0:
 =labels=Array(4):
@@ -1481,7 +1481,7 @@ Edge
 8:MPropDef
 13:MAttributeDef
 =properties=JsonObject(5):
-{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.","\u000e2\u00080\u0009c"],"is_intro":true}
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["“Answer to the Ultimate Question of Life, the Universe, and Everything.","“"],"is_intro":true}
 ----
 =to=Entity#0:
 =labels=Array(4):
@@ -1722,7 +1722,7 @@ Edge
 8:MPropDef
 13:MAttributeDef
 =properties=JsonObject(5):
-{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.","\u000e2\u00080\u0009c"],"is_intro":true}
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["“Answer to the Ultimate Question of Life, the Universe, and Everything.","“"],"is_intro":true}
 
 
 Edge
index 76c1172..16375e3 100644 (file)
@@ -17,7 +17,7 @@ in "C++ Header" `{
 `}
 
 fun print_a(str: String) import String.to_cstring in "C++" `{
-       puts(String_to_cstring(str));
+       puts(reinterpret_cast<char*>(String_to_cstring(str)));
 `}
 
 print_a "Hello from `a`."
index 01eb25c..e4631dc 100644 (file)
@@ -19,7 +19,7 @@ in "C++ header" `{
 `}
 
 fun print_b(str: String) import String.to_cstring in "C++" `{
-       puts(String_to_cstring(str));
+       puts(reinterpret_cast<char*>(String_to_cstring(str)));
 `}
 
 print_a "Hello from `a`."