compiler: compile ASuperstringExpr using `native_to_s`
[nit.git] / src / compiler / abstract_compiler.nit
index 4dc34c8..522230f 100644 (file)
@@ -603,9 +603,9 @@ abstract class AbstractCompiler
                var gccd_disable = modelbuilder.toolcontext.opt_no_gcc_directive.value
                if gccd_disable.has("noreturn") or gccd_disable.has("all") then
                        # Signal handler function prototype
-                       self.header.add_decl("void show_backtrace(int);")
+                       self.header.add_decl("void fatal_exit(int);")
                else
-                       self.header.add_decl("void show_backtrace(int) __attribute__ ((noreturn));")
+                       self.header.add_decl("void fatal_exit(int) __attribute__ ((noreturn));")
                end
 
                if gccd_disable.has("likely") or gccd_disable.has("all") then
@@ -741,12 +741,7 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
                        v.compiler.header.add_decl("extern long count_isset_checks;")
                end
 
-               v.add_decl("void sig_handler(int signo)\{")
-               v.add_decl("PRINT_ERROR(\"Caught signal : %s\\n\", strsignal(signo));")
-               v.add_decl("show_backtrace(signo);")
-               v.add_decl("\}")
-
-               v.add_decl("void show_backtrace (int signo) \{")
+               v.add_decl("static void show_backtrace(void) \{")
                if ost == "nitstack" or ost == "libunwind" then
                        v.add_decl("char* opt = getenv(\"NIT_NO_STACK\");")
                        v.add_decl("unw_cursor_t cursor;")
@@ -776,7 +771,19 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
                        v.add_decl("free(procname);")
                        v.add_decl("\}")
                end
-               v.add_decl("exit(signo);")
+               v.add_decl("\}")
+
+               v.add_decl("void sig_handler(int signo)\{")
+               v.add_decl("PRINT_ERROR(\"Caught signal : %s\\n\", strsignal(signo));")
+               v.add_decl("show_backtrace();")
+               # rethrows
+               v.add_decl("signal(signo, SIG_DFL);")
+               v.add_decl("kill(getpid(), signo);")
+               v.add_decl("\}")
+
+               v.add_decl("void fatal_exit(int status) \{")
+               v.add_decl("show_backtrace();")
+               v.add_decl("exit(status);")
                v.add_decl("\}")
 
                if no_main then
@@ -1119,6 +1126,14 @@ abstract class AbstractCompilerVisitor
 
        fun native_array_def(pname: String, ret_type: nullable MType, arguments: Array[RuntimeVariable]) is abstract
 
+       # Return an element of a native array.
+       # The method is unsafe and is just a direct wrapper for the specific implementation of native arrays
+       fun native_array_get(native_array: RuntimeVariable, index: Int): RuntimeVariable is abstract
+
+       # Store an element in a native array.
+       # 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
+
        # 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.
@@ -1392,7 +1407,7 @@ abstract class AbstractCompilerVisitor
                var recv
                var ctype = mtype.ctype
                assert mtype.mclass.name != "NativeArray"
-               if ctype == "val*" then
+               if not mtype.is_c_primitive then
                        recv = init_instance(mtype)
                else if ctype == "char*" then
                        recv = new_expr("NULL/*special!*/", mtype)
@@ -1581,7 +1596,7 @@ abstract class AbstractCompilerVisitor
                else
                        self.add("PRINT_ERROR(\"\\n\");")
                end
-               self.add("show_backtrace(1);")
+               self.add("fatal_exit(1);")
        end
 
        # Add a dynamic cast
@@ -1778,12 +1793,16 @@ redef class MType
 
        # Short name of the `ctype` to use in unions
        fun ctypename: String do return "val"
+
+       # Is the associated C type a primitive one?
+       #
+       # ENSURE `result == (ctype != "val*")`
+       fun is_c_primitive: Bool do return false
 end
 
 redef class MClassType
 
-       redef fun ctype: String
-       do
+       redef var ctype is lazy do
                if mclass.name == "Int" then
                        return "long"
                else if mclass.name == "Bool" then
@@ -1801,6 +1820,8 @@ redef class MClassType
                end
        end
 
+       redef var is_c_primitive is lazy do return ctype != "val*"
+
        redef fun ctype_extern: String
        do
                if mclass.kind == extern_kind then
@@ -2290,7 +2311,7 @@ redef class AAttrPropdef
                        if is_lazy then
                                var set
                                var ret = self.mpropdef.static_mtype
-                               var useiset = ret.ctype == "val*" and not ret isa MNullableType
+                               var useiset = not ret.is_c_primitive and not ret isa MNullableType
                                var guard = self.mlazypropdef.mproperty
                                if useiset then
                                        set = v.isset_attribute(self.mpropdef.mproperty, recv)
@@ -2318,7 +2339,7 @@ redef class AAttrPropdef
                        v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1])
                        if is_lazy then
                                var ret = self.mpropdef.static_mtype
-                               var useiset = ret.ctype == "val*" and not ret isa MNullableType
+                               var useiset = not ret.is_c_primitive and not ret isa MNullableType
                                if not useiset then
                                        v.write_attribute(self.mlazypropdef.mproperty, arguments.first, v.bool_instance(true))
                                end
@@ -2754,14 +2775,35 @@ end
 redef class ASuperstringExpr
        redef fun expr(v)
        do
-               var array = new Array[RuntimeVariable]
+               var type_string = mtype.as(not null)
+
+               # Collect elements of the superstring
+               var array = new Array[AExpr]
                for ne in self.n_exprs do
+                       # Drop literal empty string.
+                       # They appears in things like "{a}" that is ["", a, ""]
                        if ne isa AStringFormExpr and ne.value == "" then continue # skip empty sub-strings
-                       var i = v.expr(ne, null)
-                       array.add(i)
+                       array.add(ne)
                end
-               var a = v.array_instance(array, v.object_type)
-               var res = v.send(v.get_property("to_s", a.mtype), [a])
+
+               # The native array that will contains the elements to_s-ized.
+               # For fast concatenation.
+               var a = v.native_array_instance(type_string, v.int_instance(array.length))
+
+               # Stringify the elements and put them in the native array
+               var to_s_method = v.get_property("to_s", v.object_type)
+               for i in [0..array.length[ do
+                       var ne = array[i]
+                       var e = v.expr(ne, null)
+                       # Skip the `to_s` if the element is already a String
+                       if not e.mcasttype.is_subtype(v.compiler.mainmodule, null, type_string) then
+                               e = v.send(to_s_method, [e]).as(not null)
+                       end
+                       v.native_array_set(a, i, e)
+               end
+
+               # Fast join the native string to get the result
+               var res = v.send(v.get_property("native_to_s", a.mtype), [a])
                return res
        end
 end
@@ -2827,7 +2869,7 @@ redef class AAsNotnullExpr
                var i = v.expr(self.n_expr, null)
                if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return i
 
-               if i.mtype.ctype != "val*" then return i
+               if i.mtype.is_c_primitive then return i
 
                v.add("if (unlikely({i} == NULL)) \{")
                v.add_abort("Cast failed")