Merge: Safe call operator
[nit.git] / src / compiler / abstract_compiler.nit
index b0cbd03..c74933c 100644 (file)
@@ -39,6 +39,8 @@ redef class ToolContext
        var opt_no_cc = new OptionBool("Do not invoke the C compiler", "--no-cc")
        # --no-main
        var opt_no_main = new OptionBool("Do not generate main entry point", "--no-main")
+       # --shared-lib
+       var opt_shared_lib = new OptionBool("Compile to a native shared library", "--shared-lib")
        # --make-flags
        var opt_make_flags = new OptionString("Additional options to the `make` command", "--make-flags")
        # --max-c-lines
@@ -81,7 +83,7 @@ redef class ToolContext
        redef init
        do
                super
-               self.option_context.add_option(self.opt_output, self.opt_dir, self.opt_run, 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_output, self.opt_dir, self.opt_run, self.opt_no_cc, self.opt_no_main, self.opt_shared_lib, 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_no_stacktrace)
@@ -92,6 +94,7 @@ redef class ToolContext
                self.option_context.add_option(self.opt_trace)
 
                opt_no_main.hidden = true
+               opt_shared_lib.hidden = true
        end
 
        redef fun process_options(args)
@@ -193,7 +196,7 @@ class MakefileToolchain
                var time1 = get_time
                self.toolcontext.info("*** END WRITING C: {time1-time0} ***", 2)
 
-               if not toolcontext.check_errors then return
+               toolcontext.check_errors
 
                # Execute the Makefile
 
@@ -391,6 +394,13 @@ LDLIBS  ?= -lm {{{linker_options.join(" ")}}}
 
                if self.toolcontext.opt_trace.value then makefile.write "LDLIBS += -llttng-ust -ldl\n"
 
+               if toolcontext.opt_shared_lib.value then
+                       makefile.write """
+CFLAGS += -fPIC
+LDFLAGS += -shared -Wl,-soname,{{{outname}}}
+"""
+               end
+
                makefile.write "\n# SPECIAL CONFIGURATION FLAGS\n"
                if platform.supports_libunwind then
                        if toolcontext.opt_no_stacktrace.value then
@@ -455,6 +465,13 @@ ifneq ($(findstring MINGW64,$(uname_S)),)
        CFLAGS += -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast
 endif
 
+# Add the compilation dir to the Java CLASSPATH
+ifeq ($(CLASSPATH),)
+       CLASSPATH := .
+else
+       CLASSPATH := $(CLASSPATH):.
+endif
+
 """
 
                makefile.write("all: {outpath}\n")
@@ -518,8 +535,7 @@ endif
                var java_files = new Array[ExternFile]
                for f in compiler.extern_bodies do
                        var o = f.makefile_rule_name
-                       var ff = f.filename.basename
-                       makefile.write("{o}: {ff}\n")
+                       makefile.write("{o}: {f.filename}\n")
                        makefile.write("\t{f.makefile_rule_content}\n\n")
                        dep_rules.add(f.makefile_rule_name)
 
@@ -546,9 +562,9 @@ endif
                end
                makefile.write("{outpath}: {dep_rules.join(" ")}\n\t$(CC) $(LDFLAGS) -o {outpath.escape_to_sh} {ofiles.join(" ")} $(LDLIBS) {pkg}\n\n")
                # Clean
-               makefile.write("clean:\n\trm {ofiles.join(" ")} 2>/dev/null\n")
+               makefile.write("clean:\n\trm -f {ofiles.join(" ")} 2>/dev/null\n")
                if outpath != real_outpath then
-                       makefile.write("\trm -- {outpath.escape_to_sh} 2>/dev/null\n")
+                       makefile.write("\trm -f -- {outpath.escape_to_sh} 2>/dev/null\n")
                end
                makefile.close
                self.toolcontext.info("Generated makefile: {makepath}", 2)
@@ -702,7 +718,7 @@ abstract class AbstractCompiler
                stream.write("const char* get_nit_name(register const char* procname, register unsigned int len);\n")
                stream.close
 
-               extern_bodies.add(new ExternCFile("{compile_dir}/c_functions_hash.c", ""))
+               extern_bodies.add(new ExternCFile("c_functions_hash.c", ""))
        end
 
        # Compile C headers
@@ -1789,7 +1805,7 @@ abstract class AbstractCompilerVisitor
                var nat = new_var(mtype)
                var byte_esc = new Buffer.with_cap(len * 4)
                for i in [0 .. len[ do
-                       byte_esc.append("\\x{ns[i].to_s.substring_from(2)}")
+                       byte_esc.append("\\x{ns[i].to_hex}")
                end
                self.add("{nat} = \"{byte_esc}\";")
                return nat
@@ -3809,8 +3825,9 @@ end
 
 redef class ACharExpr
        redef fun expr(v) do
-               if is_ascii then return v.byte_instance(value.as(not null).ascii)
-               if is_code_point then return v.int_instance(value.as(not null).code_point)
+               if is_code_point then
+                       return v.int_instance(value.as(not null).code_point)
+               end
                return v.char_instance(self.value.as(not null))
        end
 end
@@ -4068,10 +4085,24 @@ redef class ASendExpr
        redef fun expr(v)
        do
                var recv = v.expr(self.n_expr, null)
+               if is_safe then
+                       v.add "if ({recv}!=NULL) \{"
+               end
                var callsite = self.callsite.as(not null)
                if callsite.is_broken then return null
                var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.raw_arguments)
-               return v.compile_callsite(callsite, args)
+               var res = v.compile_callsite(callsite, args)
+               if is_safe then
+                       if res != null then
+                               var orig_res = res
+                               res = v.new_var(self.mtype.as(not null))
+                               v.add("{res} = {orig_res};")
+                               v.add("\} else \{")
+                               v.add("{res} = NULL;")
+                       end
+                       v.add("\}")
+               end
+               return res
        end
 end
 
@@ -4239,6 +4270,13 @@ redef class AVarargExpr
        end
 end
 
+redef class ASafeExpr
+       redef fun expr(v)
+       do
+               return v.expr(self.n_expr, null)
+       end
+end
+
 redef class ANamedargExpr
        redef fun expr(v)
        do