X-Git-Url: http://nitlanguage.org diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index 81c640c..31795fc 100644 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@ -31,6 +31,8 @@ redef class ToolContext var opt_output = new OptionString("Filename of the generated executable", "-o", "--output") # --dir var opt_dir = new OptionString("Output directory", "--dir") + # --run + var opt_run = new OptionBool("Execute the binary after the compilation", "--run") # --no-cc var opt_no_cc = new OptionBool("Do not invoke the C compiler", "--no-cc") # --no-main @@ -75,7 +77,7 @@ redef class ToolContext redef init do super - 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_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_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) @@ -199,6 +201,14 @@ class MakefileToolchain sys.system("rm -r -- '{root_compile_dir.escape_to_sh}/'") end + if toolcontext.opt_run.value then + var mainmodule = compiler.mainmodule + var out = outfile(mainmodule) + var cmd = ["."/out] + cmd.append toolcontext.option_context.rest + toolcontext.exec_and_check(cmd, "--run") + end + time1 = get_time self.toolcontext.info("*** END COMPILING C: {time1-time0} ***", 2) end @@ -349,14 +359,21 @@ 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 -Wno-trigraphs\nCINCL =\nLDFLAGS ?= \nLDLIBS ?= -lm {linker_options.join(" ")}\n\n") + makefile.write """ +CC ?= ccache cc +CXX ?= ccache c++ +CFLAGS ?= -g {{{if not debug then "-O2" else ""}}} -Wno-unused-value -Wno-switch -Wno-attributes -Wno-trigraphs +CINCL = +LDFLAGS ?= +LDLIBS ?= -lm {{{linker_options.join(" ")}}} +\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" + makefile.write "NO_STACKTRACE ?= True" else - makefile.write "NO_STACKTRACE= # Set to `True` to enable" + makefile.write "NO_STACKTRACE ?= # Set to `True` to enable" end end @@ -403,6 +420,18 @@ ifeq ($(uname_S),Darwin) LDLIBS := $(filter-out -lrt,$(LDLIBS)) endif +# Special configuration for Windows under mingw64 +ifneq ($(findstring MINGW64,$(uname_S)),) + # Use the pcreposix regex library + LDLIBS += -lpcreposix + + # Remove POSIX flag -lrt + LDLIBS := $(filter-out -lrt,$(LDLIBS)) + + # Silence warnings when storing Int, Char and Bool as pointer address + CFLAGS += -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast +endif + """ makefile.write("all: {outpath}\n") @@ -510,8 +539,10 @@ endif self.toolcontext.info(command, 2) var res - if self.toolcontext.verbose_level >= 3 or is_windows then + if self.toolcontext.verbose_level >= 3 then res = sys.system("{command} 2>&1") + else if is_windows then + res = sys.system("{command} 2>&1 >nul") else res = sys.system("{command} 2>&1 >/dev/null") end @@ -1429,7 +1460,7 @@ abstract class AbstractCompilerVisitor # Checks # Can value be null? (according to current knowledge) - fun maybenull(value: RuntimeVariable): Bool + fun maybe_null(value: RuntimeVariable): Bool do return value.mcasttype isa MNullableType or value.mcasttype isa MNullType end @@ -1439,7 +1470,7 @@ abstract class AbstractCompilerVisitor do if self.compiler.modelbuilder.toolcontext.opt_no_check_null.value then return - if maybenull(recv) then + if maybe_null(recv) then self.add("if (unlikely({recv} == NULL)) \{") self.add_abort("Receiver is null") self.add("\}") @@ -1491,7 +1522,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 @@ -1610,7 +1641,7 @@ abstract class AbstractCompilerVisitor fun int8_instance(value: Int8): RuntimeVariable do var t = mmodule.int8_type - var res = new RuntimeVariable("((int8_t){value.to_s})", t, t) + var res = new RuntimeVariable("INT8_C({value.to_s})", t, t) return res end @@ -1618,7 +1649,7 @@ abstract class AbstractCompilerVisitor fun int16_instance(value: Int16): RuntimeVariable do var t = mmodule.int16_type - var res = new RuntimeVariable("((int16_t){value.to_s})", t, t) + var res = new RuntimeVariable("INT16_C({value.to_s})", t, t) return res end @@ -1626,7 +1657,7 @@ abstract class AbstractCompilerVisitor fun uint16_instance(value: UInt16): RuntimeVariable do var t = mmodule.uint16_type - var res = new RuntimeVariable("((uint16_t){value.to_s})", t, t) + var res = new RuntimeVariable("UINT16_C({value.to_s})", t, t) return res end @@ -1634,7 +1665,7 @@ abstract class AbstractCompilerVisitor fun int32_instance(value: Int32): RuntimeVariable do var t = mmodule.int32_type - var res = new RuntimeVariable("((int32_t){value.to_s})", t, t) + var res = new RuntimeVariable("INT32_C({value.to_s})", t, t) return res end @@ -1642,7 +1673,7 @@ abstract class AbstractCompilerVisitor fun uint32_instance(value: UInt32): RuntimeVariable do var t = mmodule.uint32_type - var res = new RuntimeVariable("((uint32_t){value.to_s})", t, t) + var res = new RuntimeVariable("UINT32_C({value.to_s})", t, t) return res end @@ -1684,9 +1715,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 @@ -1706,12 +1737,12 @@ 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) var unilen = self.int_instance(string.length) - self.add("{res} = {self.send(self.get_property("to_s_full", native_mtype), [nat, byte_length, unilen]).as(not null)};") + self.add("{res} = {self.send(self.get_property("to_s_unsafe", native_mtype), [nat, byte_length, unilen, value_instance(false), value_instance(false)]).as(not null)};") self.add("{name} = {res};") self.add("\}") return res @@ -1804,17 +1835,30 @@ abstract class AbstractCompilerVisitor # used by aborts, asserts, casts, etc. fun add_abort(message: String) do + add_raw_throw + self.add("PRINT_ERROR(\"Runtime error: %s\", \"{message.escape_to_c}\");") + add_raw_abort + end + + # Generate a long jump if there is a catch block. + # + # This method should be called before the error messages and before a `add_raw_abort`. + fun add_raw_throw + do self.add("if(catchStack.cursor >= 0)\{") self.add("longjmp(catchStack.envs[catchStack.cursor], 1);") self.add("\}") - self.add("PRINT_ERROR(\"Runtime error: %s\", \"{message.escape_to_c}\");") - add_raw_abort end + # Generate abort without a message. + # + # Used when one need a more complex message. + # Do not forget to call `add_raw_abort` before the display of a custom user message. fun add_raw_abort do - if self.current_node != null and self.current_node.location.file != null and - self.current_node.location.file.mmodule != null then + var current_node = self.current_node + if current_node != null and current_node.location.file != null and + current_node.location.file.mmodule != null then var f = "FILE_{self.current_node.location.file.mmodule.c_name}" self.require_declaration(f) self.add("PRINT_ERROR(\" (%s:%d)\\n\", {f}, {current_node.location.line_start});") @@ -1829,6 +1873,7 @@ abstract class AbstractCompilerVisitor do var res = self.type_test(value, mtype, tag) self.add("if (unlikely(!{res})) \{") + self.add_raw_throw var cn = self.class_name_string(value) self.add("PRINT_ERROR(\"Runtime error: Cast failed. Expected `%s`, got `%s`\", \"{mtype.to_s.escape_to_c}\", {cn});") self.add_raw_abort @@ -2073,7 +2118,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*" @@ -2115,7 +2160,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}*" @@ -2158,6 +2203,7 @@ redef class MMethodDef var node = modelbuilder.mpropdef2node(self) if is_abstract then + v.add_raw_throw var cn = v.class_name_string(arguments.first) v.current_node = node v.add("PRINT_ERROR(\"Runtime error: Abstract method `%s` called on `%s`\", \"{mproperty.name.escape_to_c}\", {cn});") @@ -2269,6 +2315,7 @@ redef class AMethPropdef end # We have a problem + v.add_raw_throw var cn = v.class_name_string(arguments.first) v.add("PRINT_ERROR(\"Runtime error: uncompiled method `%s` called on `%s`. NOT YET IMPLEMENTED\", \"{mpropdef.mproperty.name.escape_to_c}\", {cn});") v.add_raw_abort @@ -2584,7 +2631,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 @@ -2608,14 +2655,14 @@ redef class AMethPropdef v.ret(v.new_expr("!{res}", ret.as(not null))) return true else if pname == "new" then - var alloc = v.nit_alloc(arguments[1].to_s, "NativeString") + 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))) + v.ret(v.new_expr("*((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))) + v.ret(v.new_expr("(uint32_t)be32toh(*((uint32_t*)({arguments[0]} + {arguments[1]})))", ret.as(not null))) return true end else if cname == "NativeArray" then @@ -3057,7 +3104,7 @@ redef class AMethPropdef end end if pname == "exit" then - v.add("exit({arguments[1]});") + v.add("exit((int){arguments[1]});") return true else if pname == "sys" then v.ret(v.new_expr("glob_sys", ret.as(not null))) @@ -3190,7 +3237,7 @@ redef class AAttrPropdef assert arguments.length == 2 var recv = arguments.first var arg = arguments[1] - if is_optional and v.maybenull(arg) then + if is_optional and v.maybe_null(arg) 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)) @@ -3624,7 +3671,7 @@ redef class AOrElseExpr var res = v.new_var(self.mtype.as(not null)) var i1 = v.expr(self.n_expr, null) - if not v.maybenull(i1) then return i1 + if not v.maybe_null(i1) then return i1 v.add("if ({i1}!=NULL) \{") v.assign(res, i1) @@ -3726,7 +3773,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 @@ -3800,7 +3847,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 @@ -3877,7 +3924,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 not v.maybenull(i) then return i + if not v.maybe_null(i) then return i v.add("if (unlikely({i} == NULL)) \{") v.add_abort("Cast failed") @@ -4157,6 +4204,10 @@ var model = new Model var modelbuilder = new ModelBuilder(model, toolcontext) var arguments = toolcontext.option_context.rest +if toolcontext.opt_run.value then + # When --run, only the first is the program, the rest is the run arguments + arguments = [toolcontext.option_context.rest.shift] +end if arguments.length > 1 and toolcontext.opt_output.value != null then print "Option Error: --output needs a single source file. Do you prefer --dir?" exit 1