update all indirect references to native strings
[nit.git] / src / compiler / abstract_compiler.nit
index 364c6be..96ae7a3 100644 (file)
@@ -510,7 +510,7 @@ endif
                self.toolcontext.info(command, 2)
 
                var res
-               if self.toolcontext.verbose_level >= 3 then
+               if self.toolcontext.verbose_level >= 3 or is_windows then
                        res = sys.system("{command} 2>&1")
                else
                        res = sys.system("{command} 2>&1 >/dev/null")
@@ -662,9 +662,14 @@ abstract class AbstractCompiler
                self.header.add_decl("#include <inttypes.h>\n")
                self.header.add_decl("#include \"gc_chooser.h\"")
                self.header.add_decl("#ifdef __APPLE__")
+               self.header.add_decl("  #include <TargetConditionals.h>")
+               self.header.add_decl("  #include <syslog.h>")
                self.header.add_decl("  #include <libkern/OSByteOrder.h>")
                self.header.add_decl("  #define be32toh(x) OSSwapBigToHostInt32(x)")
                self.header.add_decl("#endif")
+               self.header.add_decl("#ifdef _WIN32")
+               self.header.add_decl("  #define be32toh(val) _byteswap_ulong(val)")
+               self.header.add_decl("#endif")
                self.header.add_decl("#ifdef __pnacl__")
                self.header.add_decl("  #define be16toh(val) (((val) >> 8) | ((val) << 8))")
                self.header.add_decl("  #define be32toh(val) ((be16toh((val) << 16) | (be16toh((val) >> 16))))")
@@ -675,6 +680,8 @@ abstract class AbstractCompiler
                self.header.add_decl("  #endif")
                self.header.add_decl("  #include <android/log.h>")
                self.header.add_decl("  #define PRINT_ERROR(...) (void)__android_log_print(ANDROID_LOG_WARN, \"Nit\", __VA_ARGS__)")
+               self.header.add_decl("#elif TARGET_OS_IPHONE")
+               self.header.add_decl("  #define PRINT_ERROR(...) syslog(LOG_ERR, __VA_ARGS__)")
                self.header.add_decl("#else")
                self.header.add_decl("  #define PRINT_ERROR(...) fprintf(stderr, __VA_ARGS__)")
                self.header.add_decl("#endif")
@@ -779,6 +786,20 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
                v.add "\}"
        end
 
+       # Hook to add specif piece of code before the the main C function.
+       #
+       # Is called by `compile_main_function`
+       fun compile_before_main(v: VISITOR)
+       do
+       end
+
+       # Hook to add specif piece of code at the begin on the main C function.
+       #
+       # Is called by `compile_main_function`
+       fun compile_begin_main(v: VISITOR)
+       do
+       end
+
        # Generate the main C function.
        #
        # This function:
@@ -864,11 +885,17 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
                v.add_decl("\}")
 
                v.add_decl("void sig_handler(int signo)\{")
+               v.add_decl "#ifdef _WIN32"
+               v.add_decl "PRINT_ERROR(\"Caught signal : %s\\n\", signo);"
+               v.add_decl "#else"
                v.add_decl("PRINT_ERROR(\"Caught signal : %s\\n\", strsignal(signo));")
+               v.add_decl "#endif"
                v.add_decl("show_backtrace();")
                # rethrows
                v.add_decl("signal(signo, SIG_DFL);")
+               v.add_decl "#ifndef _WIN32"
                v.add_decl("kill(getpid(), signo);")
+               v.add_decl "#endif"
                v.add_decl("\}")
 
                v.add_decl("void fatal_exit(int status) \{")
@@ -876,12 +903,16 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
                v.add_decl("exit(status);")
                v.add_decl("\}")
 
+               compile_before_main(v)
+
                if no_main then
                        v.add_decl("int nit_main(int argc, char** argv) \{")
                else
                        v.add_decl("int main(int argc, char** argv) \{")
                end
 
+               compile_begin_main(v)
+
                v.add "#if !defined(__ANDROID__) && !defined(TARGET_OS_IPHONE)"
                v.add("signal(SIGABRT, sig_handler);")
                v.add("signal(SIGFPE, sig_handler);")
@@ -890,7 +921,9 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
                v.add("signal(SIGTERM, sig_handler);")
                v.add("signal(SIGSEGV, sig_handler);")
                v.add "#endif"
+               v.add "#ifndef _WIN32"
                v.add("signal(SIGPIPE, SIG_IGN);")
+               v.add "#endif"
 
                v.add("glob_argc = argc; glob_argv = argv;")
                v.add("catchStack.cursor = -1;")
@@ -1116,25 +1149,41 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ) {
        fun finalize_ffi_for_module(mmodule: MModule) do mmodule.finalize_ffi(self)
 end
 
-# A file unit (may be more than one file if
-# A file unit aim to be autonomous and is made or one or more `CodeWriter`s
+# C code file generated from the `writers` and the `required_declarations`
+#
+# A file unit aims to be autonomous and is made or one or more `CodeWriter`s.
 class CodeFile
+       # Basename of the file, will be appended by `.h` and `.c`
        var name: String
+
+       # `CodeWriter` used in sequence to fill the top of the body, then the bottom
        var writers = new Array[CodeWriter]
+
+       # Required declarations keys
+       #
+       # See: `provide_declaration`
        var required_declarations = new HashSet[String]
 end
 
-# Where to store generated lines
+# Store generated lines
+#
+# Instances are added to `file.writers` at construction.
 class CodeWriter
+       # Parent `CodeFile`
        var file: CodeFile
+
+       # Main lines of code (written at the bottom of the body)
        var lines = new Array[String]
+
+       # Lines of code for declarations (written at the top of the body)
        var decl_lines = new Array[String]
 
-       # Add a line in the main part of the generated C
+       # Add a line in the main lines of code (to `lines`)
        fun add(s: String) do self.lines.add(s)
 
-       # Add a line in the
-       # (used for local or global declaration)
+       # Add a declaration line (to `decl_lines`)
+       #
+       # Used for local and global declaration.
        fun add_decl(s: String) do self.decl_lines.add(s)
 
        init
@@ -1208,8 +1257,6 @@ abstract class AbstractCompilerVisitor
 
        fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable is abstract
 
-       fun calloc_array(ret_type: MType, arguments: Array[RuntimeVariable]) is abstract
-
        fun native_array_def(pname: String, ret_type: nullable MType, arguments: Array[RuntimeVariable]): Bool do return false
 
        # Return an element of a native array.
@@ -1220,6 +1267,16 @@ abstract class AbstractCompilerVisitor
        # The method is unsafe and is just a direct wrapper for the specific implementation of native arrays
        fun native_array_set(native_array: RuntimeVariable, index: Int, value: RuntimeVariable) is abstract
 
+       # Allocate `size` bytes with the low_level `nit_alloc` C function
+       #
+       # This method can be redefined to inject statistic or tracing code.
+       #
+       # `tag` if any, is used to mark the class of the allocated object.
+       fun nit_alloc(size: String, tag: nullable String): String
+       do
+               return "nit_alloc({size})"
+       end
+
        # Evaluate `args` as expressions in the call of `mpropdef` on `recv`.
        # This method is used to manage varargs in signatures and returns the real array
        # of runtime variables to use in the call.
@@ -1434,7 +1491,7 @@ abstract class AbstractCompilerVisitor
        end
 
        # Return a "const char*" variable associated to the classname of the dynamic type of an object
-       # NOTE: we do not return a `RuntimeVariable` "NativeString" as the class may not exist in the module/program
+       # NOTE: we do not return a `RuntimeVariable` "CString" as the class may not exist in the module/program
        fun class_name_string(value: RuntimeVariable): String is abstract
 
        # Variables handling
@@ -1627,9 +1684,9 @@ abstract class AbstractCompilerVisitor
                return res
        end
 
-       # Generates a NativeString instance fully escaped in C-style \xHH fashion
-       fun native_string_instance(ns: NativeString, len: Int): RuntimeVariable do
-               var mtype = mmodule.native_string_type
+       # Generates a CString instance fully escaped in C-style \xHH fashion
+       fun c_string_instance(ns: CString, len: Int): RuntimeVariable do
+               var mtype = mmodule.c_string_type
                var nat = new_var(mtype)
                var byte_esc = new Buffer.with_cap(len * 4)
                for i in [0 .. len[ do
@@ -1649,7 +1706,7 @@ abstract class AbstractCompilerVisitor
                self.add("if (likely({name}!=NULL)) \{")
                self.add("{res} = {name};")
                self.add("\} else \{")
-               var native_mtype = mmodule.native_string_type
+               var native_mtype = mmodule.c_string_type
                var nat = self.new_var(native_mtype)
                self.add("{nat} = \"{string.escape_to_c}\";")
                var byte_length = self.int_instance(string.byte_length)
@@ -2016,7 +2073,7 @@ redef class MClassType
                        return "int32_t"
                else if mclass.name == "UInt32" then
                        return "uint32_t"
-               else if mclass.name == "NativeString" then
+               else if mclass.name == "CString" then
                        return "char*"
                else if mclass.name == "NativeArray" then
                        return "val*"
@@ -2058,7 +2115,7 @@ redef class MClassType
                        return "i32"
                else if mclass.name == "UInt32" then
                        return "u32"
-               else if mclass.name == "NativeString" then
+               else if mclass.name == "CString" then
                        return "str"
                else if mclass.name == "NativeArray" then
                        #return "{self.arguments.first.ctype}*"
@@ -2527,7 +2584,7 @@ redef class AMethPropdef
                                v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null)))
                                return true
                        end
-               else if cname == "NativeString" then
+               else if cname == "CString" then
                        if pname == "[]" then
                                v.ret(v.new_expr("(unsigned char)((int){arguments[0]}[{arguments[1]}])", ret.as(not null)))
                                return true
@@ -2551,7 +2608,8 @@ redef class AMethPropdef
                                v.ret(v.new_expr("!{res}", 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)))
+                               var alloc = v.nit_alloc(arguments[1].to_s, "CString")
+                               v.ret(v.new_expr("(char*){alloc}", ret.as(not null)))
                                return true
                        else if pname == "fetch_4_chars" then
                                v.ret(v.new_expr("(long)*((uint32_t*)({arguments[0]} + {arguments[1]}))", ret.as(not null)))
@@ -3004,9 +3062,6 @@ redef class AMethPropdef
                else if pname == "sys" then
                        v.ret(v.new_expr("glob_sys", ret.as(not null)))
                        return true
-               else if pname == "calloc_array" then
-                       v.calloc_array(ret.as(not null), arguments)
-                       return true
                else if pname == "object_id" then
                        v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
                        return true
@@ -3671,7 +3726,7 @@ redef class AStringExpr
                var s = v.string_instance(value)
                if is_string then return s
                if is_bytestring then
-                       var ns = v.native_string_instance(bytes.items, bytes.length)
+                       var ns = v.c_string_instance(bytes.items, bytes.length)
                        var ln = v.int_instance(bytes.length)
                        var cs = to_bytes_with_copy
                        assert cs != null
@@ -3745,7 +3800,7 @@ redef class ASuperstringExpr
                        v.native_array_set(a, i, e)
                end
 
-               # Fast join the native string to get the result
+               # Fast join the C string to get the result
                var res = v.send(v.get_property("native_to_s", a.mtype), [a])
                assert res != null