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
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)
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
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 """
+ifeq ($(origin CC), default)
+ CC = ccache cc
+endif
+ifeq ($(origin CXX), default)
+ CXX = ccache c++
+endif
+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
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")
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
# 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
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("\}")
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
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
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
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
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
end
# Generates a CString instance fully escaped in C-style \xHH fashion
- fun native_string_instance(ns: CString, len: Int): RuntimeVariable do
- var mtype = mmodule.native_string_type
+ 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
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
# 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});")
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
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});")
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
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
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)))
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))
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)
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
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
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")
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