nitc/abscomp: add helper function maybenull to factorize code
[nit.git] / src / compiler / abstract_compiler.nit
index f0a05c9..47a0017 100644 (file)
@@ -349,7 +349,7 @@ class MakefileToolchain
                end
                var debug = toolcontext.opt_debug.value
 
-               makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g{ if not debug then " -O2 " else " "}-Wno-unused-value -Wno-switch -Wno-attributes\nCINCL =\nLDFLAGS ?= \nLDLIBS  ?= -lm {linker_options.join(" ")}\n\n")
+               makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g{ if not debug then " -O2 " else " "}-Wno-unused-value -Wno-switch -Wno-attributes -Wno-trigraphs\nCINCL =\nLDFLAGS ?= \nLDLIBS  ?= -lm {linker_options.join(" ")}\n\n")
 
                makefile.write "\n# SPECIAL CONFIGURATION FLAGS\n"
                if platform.supports_libunwind then
@@ -654,9 +654,23 @@ abstract class AbstractCompiler
                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("#ifdef __linux__")
+               self.header.add_decl("  #include <endian.h>")
+               self.header.add_decl("#endif")
                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 <libkern/OSByteOrder.h>")
+               self.header.add_decl("  #define be32toh(x) OSSwapBigToHostInt32(x)")
+               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))))")
+               self.header.add_decl("#endif")
                self.header.add_decl("#ifdef ANDROID")
+               self.header.add_decl("  #ifndef be32toh")
+               self.header.add_decl("          #define be32toh(val) betoh32(val)")
+               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("#else")
@@ -853,7 +867,7 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
                        v.add_decl("int main(int argc, char** argv) \{")
                end
 
-               v.add "#ifndef ANDROID"
+               v.add "#if !defined(__ANDROID__) && !defined(TARGET_OS_IPHONE)"
                v.add("signal(SIGABRT, sig_handler);")
                v.add("signal(SIGFPE, sig_handler);")
                v.add("signal(SIGILL, sig_handler);")
@@ -1337,13 +1351,18 @@ abstract class AbstractCompilerVisitor
 
        # Checks
 
+       # Can value be null? (according to current knowledge)
+       fun maybenull(value: RuntimeVariable): Bool
+       do
+               return value.mcasttype isa MNullableType or value.mcasttype isa MNullType
+       end
+
        # Add a check and an abort for a null receiver if needed
        fun check_recv_notnull(recv: RuntimeVariable)
        do
                if self.compiler.modelbuilder.toolcontext.opt_no_check_null.value then return
 
-               var maybenull = recv.mcasttype isa MNullableType or recv.mcasttype isa MNullType
-               if maybenull then
+               if maybenull(recv) then
                        self.add("if (unlikely({recv} == NULL)) \{")
                        self.add_abort("Receiver is null")
                        self.add("\}")
@@ -1659,7 +1678,7 @@ abstract class AbstractCompilerVisitor
        # This is used for the legacy FFI
        fun add_extern(mmodule: MModule)
        do
-               var file = mmodule.location.file.filename
+               var file = mmodule.filepath
                file = file.strip_extension(".nit")
                var tryfile = file + ".nit.h"
                if tryfile.file_exists then
@@ -2032,6 +2051,8 @@ redef class MMethodDef
                else if node isa AClassdef then
                        # Automatic free init is always inlined since it is empty or contains only attribtes assigments
                        return true
+               else if node == null then
+                       return true
                else
                        abort
                end
@@ -2135,7 +2156,8 @@ redef class AMethPropdef
                # Try special compilation
                if mpropdef.is_intern then
                        if compile_intern_to_c(v, mpropdef, arguments) then return
-               else if mpropdef.is_extern then
+               end
+               if mpropdef.is_extern then
                        if mpropdef.mproperty.is_init then
                                if compile_externinit_to_c(v, mpropdef, arguments) then return
                        else
@@ -2486,9 +2508,22 @@ redef class AMethPropdef
                        else if pname == "fast_cstring" then
                                v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
                                return true
+                       else if pname == "==" then
+                               v.ret(v.equal_test(arguments[0], arguments[1]))
+                               return true
+                       else if pname == "!=" then
+                               var res = v.equal_test(arguments[0], arguments[1])
+                               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)))
                                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)))
+                               return true
+                       else if pname == "fetch_4_hchars" then
+                               v.ret(v.new_expr("(long)be32toh(*((uint32_t*)({arguments[0]} + {arguments[1]})))", ret.as(not null)))
+                               return true
                        end
                else if cname == "NativeArray" then
                        return v.native_array_def(pname, ret, arguments)
@@ -3066,7 +3101,18 @@ redef class AAttrPropdef
                        v.assign(v.frame.returnvar.as(not null), res)
                else if mpropdef == mwritepropdef then
                        assert arguments.length == 2
-                       v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1])
+                       var recv = arguments.first
+                       var arg = arguments[1]
+                       if is_optional then
+                               var value = v.new_var(self.mpropdef.static_mtype.as(not null))
+                               v.add("if ({arg} == NULL) \{")
+                               v.assign(value, evaluate_expr(v, recv))
+                               v.add("\} else \{")
+                               v.assign(value, arg)
+                               v.add("\}")
+                               arg = value
+                       end
+                       v.write_attribute(self.mpropdef.mproperty, arguments.first, arg)
                        if is_lazy then
                                var ret = self.mtype
                                var useiset = not ret.is_c_primitive and not ret isa MNullableType
@@ -3141,8 +3187,7 @@ end
 redef class AClassdef
        private fun compile_to_c(v: AbstractCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
        do
-               if mpropdef == self.mfree_init then
-                       assert mpropdef.mproperty.is_root_init
+               if mpropdef.mproperty.is_root_init then
                        assert arguments.length == 1
                        if not mpropdef.is_intro then
                                v.supercall(mpropdef, arguments.first.mtype.as(MClassType), arguments)