var opt_invocation_metrics = new OptionBool("Enable static and dynamic count of all method invocations", "--invocation-metrics")
# --isset-checks-metrics
var opt_isset_checks_metrics = new OptionBool("Enable static and dynamic count of isset checks before attributes access", "--isset-checks-metrics")
- # --stacktrace
- var opt_stacktrace = new OptionString("Control the generation of stack traces", "--stacktrace")
+ # --no-stacktrace
+ var opt_no_stacktrace = new OptionBool("Disable the generation of stack traces", "--no-stacktrace")
# --no-gcc-directives
var opt_no_gcc_directive = new OptionArray("Disable a advanced gcc directives for optimization", "--no-gcc-directive")
# --release
var opt_release = new OptionBool("Compile in release mode and finalize application", "--release")
+ # -g
+ var opt_debug = new OptionBool("Compile in debug mode (no C-side optimization)", "--debug", "-g")
redef init
do
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_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_stacktrace)
+ self.option_context.add_option(self.opt_no_stacktrace)
self.option_context.add_option(self.opt_no_gcc_directive)
self.option_context.add_option(self.opt_release)
self.option_context.add_option(self.opt_max_c_lines, self.opt_group_c_files)
+ self.option_context.add_option(self.opt_debug)
opt_no_main.hidden = true
end
do
super
- var st = opt_stacktrace.value
- if st == "none" or st == "libunwind" or st == "nitstack" then
- # Fine, do nothing
- else if st == "auto" or st == null then
- # Default is nitstack
- opt_stacktrace.value = "nitstack"
- else
- print "Option Error: unknown value `{st}` for --stacktrace. Use `none`, `libunwind`, `nitstack` or `auto`."
- exit(1)
- end
-
if opt_output.value != null and opt_dir.value != null then
print "Option Error: cannot use both --dir and --output"
exit(1)
end
redef class ModelBuilder
- # The compilation directory
- var compile_dir: String
-
# Simple indirection to `Toolchain::write_and_make`
protected fun write_and_make(compiler: AbstractCompiler)
do
var platform = compiler.target_platform
var toolchain = platform.toolchain(toolcontext, compiler)
- compile_dir = toolchain.compile_dir
+ compiler.toolchain = toolchain
toolchain.write_and_make
end
end
# Compiler of the target program
var compiler: AbstractCompiler
- # Directory where to generate all C files
- fun compile_dir: String
+ # Directory where to generate all files
+ #
+ # The option `--compile_dir` change this directory.
+ fun root_compile_dir: String
do
var compile_dir = toolcontext.opt_compile_dir.value
if compile_dir == null then compile_dir = "nit_compile"
return compile_dir
end
+ # Directory where to generate all C files
+ #
+ # By default it is `root_compile_dir` but some platform may require that it is a subdirectory.
+ fun compile_dir: String do return root_compile_dir
+
# Write all C files and compile them
fun write_and_make is abstract
end
redef fun write_and_make
do
+ var debug = toolcontext.opt_debug.value
var compile_dir = compile_dir
+ # Remove the compilation directory unless explicitly set
+ var auto_remove = toolcontext.opt_compile_dir.value == null
+ # If debug flag is set, do not remove sources
+ if debug then auto_remove = false
+
# Generate the .h and .c files
# A single C file regroups many compiled rumtime functions
# Note that we do not try to be clever an a small change in a Nit source file may change the content of all the generated .c files
var time0 = get_time
self.toolcontext.info("*** WRITING C ***", 1)
+ root_compile_dir.mkdir
compile_dir.mkdir
var cfiles = new Array[String]
compile_c_code(compile_dir)
+ if auto_remove then
+ sys.system("rm -r -- '{root_compile_dir.escape_to_sh}/'")
+ end
+
time1 = get_time
self.toolcontext.info("*** END COMPILING C: {time1-time0} ***", 2)
end
fun write_files(compile_dir: String, cfiles: Array[String])
do
var platform = compiler.target_platform
- if self.toolcontext.opt_stacktrace.value == "nitstack" and platform.supports_libunwind then compiler.build_c_to_nit_bindings
+ if platform.supports_libunwind then compiler.build_c_to_nit_bindings
var cc_opt_with_libgc = "-DWITH_LIBGC"
if not platform.supports_libgc then cc_opt_with_libgc = ""
# Copy original .[ch] files to compile_dir
for src in compiler.files_to_copy do
- var basename = src.basename("")
+ var basename = src.basename
var dst = "{compile_dir}/{basename}"
src.file_copy_to dst
end
var libs = m.collect_linker_libs
if libs != null then linker_options.add_all(libs)
end
+ var debug = toolcontext.opt_debug.value
- makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g -O2 -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\nCINCL =\nLDFLAGS ?= \nLDLIBS ?= -lm {linker_options.join(" ")}\n\n")
- var ost = toolcontext.opt_stacktrace.value
- if (ost == "libunwind" or ost == "nitstack") and platform.supports_libunwind then makefile.write("NEED_LIBUNWIND := YesPlease\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"
+ else
+ makefile.write "NO_STACKTRACE= # Set to `True` to enable"
+ end
+ end
# Dynamic adaptations
# While `platform` enable complex toolchains, they are statically applied
# For a dynamic adaptsation of the compilation, the generated Makefile should check and adapt things itself
+ makefile.write "\n\n"
# Check and adapt the targeted system
makefile.write("uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')\n")
- makefile.write("ifeq ($(uname_S),Darwin)\n")
- # remove -lunwind since it is already included on macosx
- makefile.write("\tNEED_LIBUNWIND :=\n")
- makefile.write("endif\n\n")
# Check and adapt for the compiler used
# clang need an additionnal `-Qunused-arguments`
makefile.write("clang_check := $(shell sh -c '$(CC) -v 2>&1 | grep -q clang; echo $$?')\nifeq ($(clang_check), 0)\n\tCFLAGS += -Qunused-arguments\nendif\n")
- makefile.write("ifdef NEED_LIBUNWIND\n\tLDLIBS += -lunwind\nendif\n")
+ if platform.supports_libunwind then
+ makefile.write """
+ifneq ($(NO_STACKTRACE), True)
+ # Check and include lib-unwind in a portable way
+ ifneq ($(uname_S),Darwin)
+ # already included on macosx, but need to get the correct flags in other supported platforms.
+ ifeq ($(shell pkg-config --exists 'libunwind'; echo $$?), 0)
+ LDLIBS += `pkg-config --libs libunwind`
+ CFLAGS += `pkg-config --cflags libunwind`
+ else
+ $(warning "[_] stack-traces disabled. Please install libunwind-dev.")
+ CFLAGS += -D NO_STACKTRACE
+ endif
+ endif
+else
+ # Stacktraces disabled
+ CFLAGS += -D NO_STACKTRACE
+endif
+
+"""
+ else
+ makefile.write("CFLAGS += -D NO_STACKTRACE\n\n")
+ end
+
+ makefile.write """
+# Special configuration for Darwin
+ifeq ($(uname_S),Darwin)
+ # Remove POSIX flag -lrt
+ LDLIBS := $(filter-out -lrt,$(LDLIBS))
+endif
+
+"""
makefile.write("all: {outpath}\n")
if outpath != real_outpath then
# Compile each required extern body into a specific .o
for f in compiler.extern_bodies do
var o = f.makefile_rule_name
- var ff = f.filename.basename("")
+ var ff = f.filename.basename
makefile.write("{o}: {ff}\n")
makefile.write("\t{f.makefile_rule_content}\n\n")
dep_rules.add(f.makefile_rule_name)
# The modelbuilder used to know the model and the AST
var modelbuilder: ModelBuilder is protected writable
+ # The associated toolchain
+ #
+ # Set by `modelbuilder.write_and_make` and permit sub-routines to access the current toolchain if required.
+ var toolchain: Toolchain is noinit
+
# Is hardening asked? (see --hardening)
fun hardening: Bool do return self.modelbuilder.toolcontext.opt_hardening.value
# Binds the generated C function names to Nit function names
fun build_c_to_nit_bindings
do
- var compile_dir = modelbuilder.compile_dir
+ var compile_dir = toolchain.compile_dir
var stream = new FileWriter.open("{compile_dir}/c_functions_hash.c")
stream.write("#include <string.h>\n")
self.header.add_decl("#include <string.h>")
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("#include <inttypes.h>\n")
self.header.add_decl("#include \"gc_chooser.h\"")
self.header.add_decl("#ifdef ANDROID")
self.header.add_decl(" #include <android/log.h>")
do
var v = self.new_visitor
v.add_decl("#include <signal.h>")
- var ost = modelbuilder.toolcontext.opt_stacktrace.value
var platform = target_platform
- if not platform.supports_libunwind then ost = "none"
-
var no_main = platform.no_main or modelbuilder.toolcontext.opt_no_main.value
- if ost == "nitstack" or ost == "libunwind" then
+ if platform.supports_libunwind then
+ v.add_decl("#ifndef NO_STACKTRACE")
v.add_decl("#define UNW_LOCAL_ONLY")
v.add_decl("#include <libunwind.h>")
- if ost == "nitstack" then
- v.add_decl("#include \"c_functions_hash.h\"")
- end
+ v.add_decl("#include \"c_functions_hash.h\"")
+ v.add_decl("#endif")
end
v.add_decl("int glob_argc;")
v.add_decl("char **glob_argv;")
end
v.add_decl("static void show_backtrace(void) \{")
- if ost == "nitstack" or ost == "libunwind" then
+ if platform.supports_libunwind then
+ v.add_decl("#ifndef NO_STACKTRACE")
v.add_decl("char* opt = getenv(\"NIT_NO_STACK\");")
v.add_decl("unw_cursor_t cursor;")
v.add_decl("if(opt==NULL)\{")
v.add_decl("PRINT_ERROR(\"-------------------------------------------------\\n\");")
v.add_decl("while (unw_step(&cursor) > 0) \{")
v.add_decl(" unw_get_proc_name(&cursor, procname, 100, &ip);")
- if ost == "nitstack" then
v.add_decl(" const char* recv = get_nit_name(procname, strlen(procname));")
v.add_decl(" if (recv != NULL)\{")
v.add_decl(" PRINT_ERROR(\"` %s\\n\", recv);")
v.add_decl(" \}else\{")
v.add_decl(" PRINT_ERROR(\"` %s\\n\", procname);")
v.add_decl(" \}")
- else
- v.add_decl(" PRINT_ERROR(\"` %s \\n\",procname);")
- end
v.add_decl("\}")
v.add_decl("PRINT_ERROR(\"-------------------------------------------------\\n\");")
v.add_decl("free(procname);")
v.add_decl("\}")
+ v.add_decl("#endif /* NO_STACKTRACE */")
end
v.add_decl("\}")
v.add("signal(SIGINT, sig_handler);")
v.add("signal(SIGTERM, sig_handler);")
v.add("signal(SIGSEGV, sig_handler);")
- v.add("signal(SIGPIPE, sig_handler);")
+ v.add("signal(SIGPIPE, SIG_IGN);")
v.add("glob_argc = argc; glob_argv = argv;")
v.add("initialize_gc_option();")
return res
end
+ # Generate a byte value
+ fun byte_instance(value: Byte): RuntimeVariable
+ do
+ var t = mmodule.byte_type
+ var res = new RuntimeVariable("((unsigned char){value.to_s})", t, t)
+ return res
+ end
+
+ # Generate an int8 value
+ fun int8_instance(value: Int8): RuntimeVariable
+ do
+ var t = mmodule.int8_type
+ var res = new RuntimeVariable("((int8_t){value.to_s})", t, t)
+ return res
+ end
+
+ # Generate an int16 value
+ fun int16_instance(value: Int16): RuntimeVariable
+ do
+ var t = mmodule.int16_type
+ var res = new RuntimeVariable("((int16_t){value.to_s})", t, t)
+ return res
+ end
+
+ # Generate a uint16 value
+ fun uint16_instance(value: UInt16): RuntimeVariable
+ do
+ var t = mmodule.uint16_type
+ var res = new RuntimeVariable("((uint16_t){value.to_s})", t, t)
+ return res
+ end
+
+ # Generate an int32 value
+ fun int32_instance(value: Int32): RuntimeVariable
+ do
+ var t = mmodule.int32_type
+ var res = new RuntimeVariable("((int32_t){value.to_s})", t, t)
+ return res
+ end
+
+ # Generate a uint32 value
+ fun uint32_instance(value: UInt32): RuntimeVariable
+ do
+ var t = mmodule.uint32_type
+ var res = new RuntimeVariable("((uint32_t){value.to_s})", t, t)
+ return res
+ end
+
# Generate a char value
fun char_instance(value: Char): RuntimeVariable
do
var t = mmodule.char_type
- var res = new RuntimeVariable("'{value.to_s.escape_to_c}'", t, t)
- return res
+
+ if value.code_point < 128 then
+ return new RuntimeVariable("'{value.to_s.escape_to_c}'", t, t)
+ else
+ return new RuntimeVariable("{value.code_point}", t, t)
+ end
end
# Generate a float value
var native_mtype = mmodule.native_string_type
var nat = self.new_var(native_mtype)
self.add("{nat} = \"{string.escape_to_c}\";")
- var length = self.int_instance(string.length)
- self.add("{res} = {self.send(self.get_property("to_s_with_length", native_mtype), [nat, length]).as(not null)};")
+ var bytelen = self.int_instance(string.bytelen)
+ var unilen = self.int_instance(string.length)
+ self.add("{res} = {self.send(self.get_property("to_s_full", native_mtype), [nat, bytelen, unilen]).as(not null)};")
self.add("{name} = {res};")
self.add("\}")
return res
file = file.strip_extension(".nit")
var tryfile = file + ".nit.h"
if tryfile.file_exists then
- self.declare_once("#include \"{tryfile.basename("")}\"")
+ self.declare_once("#include \"{tryfile.basename}\"")
self.compiler.files_to_copy.add(tryfile)
end
tryfile = file + "_nit.h"
if tryfile.file_exists then
- self.declare_once("#include \"{tryfile.basename("")}\"")
+ self.declare_once("#include \"{tryfile.basename}\"")
self.compiler.files_to_copy.add(tryfile)
end
tryfile = file + "_nit.c"
if not tryfile.file_exists then return
end
- var f = new ExternCFile(tryfile.basename(""), "")
+ var f = new ExternCFile(tryfile.basename, "")
self.compiler.extern_bodies.add(f)
self.compiler.files_to_copy.add(tryfile)
end
if nexpr == null then return
if nexpr.mtype == null and not nexpr.is_typed then
# Untyped expression.
- # Might mean dead code
- # So just return
+ # Might mean dead code or invalid code
+ # so aborts
+ add_abort("FATAL: bad statement executed.")
return
end
# `mtype` is the expected return type, pass null if no specific type is expected.
fun expr(nexpr: AExpr, mtype: nullable MType): RuntimeVariable
do
- if nexpr.mtype == null then
+ var old = self.current_node
+ self.current_node = nexpr
+
+ var res = null
+ if nexpr.mtype != null then
+ res = nexpr.expr(self)
+ end
+
+ if res == null then
# Untyped expression.
- # Might mean dead code
- # so return a placebo result
+ # Might mean dead code or invalid code.
+ # so aborts
+ add_abort("FATAL: bad expression executed.")
+ # and return a placebo result to please the C compiler
if mtype == null then mtype = compiler.mainmodule.object_type
- return new_var(mtype)
+ res = new_var(mtype)
+
+ self.current_node = old
+ return res
end
- var old = self.current_node
- self.current_node = nexpr
- var res = nexpr.expr(self).as(not null)
+
if mtype != null then
mtype = self.anchor(mtype)
res = self.autobox(res, mtype)
else if mclass.name == "Bool" then
return "short int"
else if mclass.name == "Char" then
- return "char"
+ return "uint32_t"
else if mclass.name == "Float" then
return "double"
+ else if mclass.name == "Int8" then
+ return "int8_t"
+ else if mclass.name == "Byte" then
+ return "unsigned char"
+ else if mclass.name == "Int16" then
+ return "int16_t"
+ else if mclass.name == "UInt16" then
+ return "uint16_t"
+ else if mclass.name == "Int32" then
+ return "int32_t"
+ else if mclass.name == "UInt32" then
+ return "uint32_t"
else if mclass.name == "NativeString" then
return "char*"
else if mclass.name == "NativeArray" then
return "c"
else if mclass.name == "Float" then
return "d"
+ else if mclass.name == "Int8" then
+ return "i8"
+ else if mclass.name == "Byte" then
+ return "b"
+ else if mclass.name == "Int16" then
+ return "i16"
+ else if mclass.name == "UInt16" then
+ return "u16"
+ else if mclass.name == "Int32" then
+ return "i32"
+ else if mclass.name == "UInt32" then
+ return "u32"
else if mclass.name == "NativeString" then
return "str"
else if mclass.name == "NativeArray" then
else if pname == "%" then
v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null)))
return true
- else if pname == "lshift" then
- v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
- return true
- else if pname == "rshift" 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
v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
return true
+ else if pname == "to_i8" then
+ v.ret(v.new_expr("(int8_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_i16" then
+ v.ret(v.new_expr("(int16_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_u16" then
+ v.ret(v.new_expr("(uint16_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_i32" then
+ v.ret(v.new_expr("(int32_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_u32" then
+ v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null)))
+ return true
else if pname == "to_f" then
v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
return true
- else if pname == "ascii" then
- v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
+ else if pname == "to_b" then
+ v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
return true
end
else if cname == "Char" then
- if pname == "output" then
- v.add("printf(\"%c\", {arguments.first});")
- return true
- else if pname == "object_id" then
+ if pname == "object_id" then
v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
return true
else if pname == "successor" then
else if pname == "to_i" then
v.ret(v.new_expr("{arguments[0]}-'0'", ret.as(not null)))
return true
- else if pname == "ascii" then
- v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
+ end
+ else if cname == "Byte" then
+ if pname == "output" then
+ v.add("printf(\"%x\\n\", {arguments.first});")
+ return true
+ else if pname == "object_id" then
+ v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
+ return true
+ else if pname == "+" then
+ v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "-" then
+ v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "unary -" then
+ v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "unary +" then
+ v.ret(arguments[0])
+ return true
+ else if pname == "*" then
+ v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "/" then
+ v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "%" 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 == "<" then
+ v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == ">" then
+ v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "<=" then
+ v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == ">=" then
+ v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "to_i" then
+ v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_f" then
+ v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_i8" then
+ v.ret(v.new_expr("(int8_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_i16" then
+ v.ret(v.new_expr("(int16_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_u16" then
+ v.ret(v.new_expr("(uint16_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_i32" then
+ v.ret(v.new_expr("(int32_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_u32" then
+ v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null)))
return true
end
else if cname == "Bool" then
else if pname == "to_i" then
v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
return true
+ else if pname == "to_b" then
+ v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_i8" then
+ v.ret(v.new_expr("(int8_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_i16" then
+ v.ret(v.new_expr("(int16_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_u16" then
+ v.ret(v.new_expr("(uint16_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_i32" then
+ v.ret(v.new_expr("(int32_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_u32" then
+ v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null)))
+ return true
end
else if cname == "NativeString" then
if pname == "[]" then
- v.ret(v.new_expr("{arguments[0]}[{arguments[1]}]", ret.as(not null)))
+ v.ret(v.new_expr("(unsigned char)((int){arguments[0]}[{arguments[1]}])", ret.as(not null)))
return true
else if pname == "[]=" then
- v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
+ v.add("{arguments[0]}[{arguments[1]}]=(unsigned char){arguments[2]};")
return true
else if pname == "copy_to" then
v.add("memmove({arguments[1]}+{arguments[4]},{arguments[0]}+{arguments[3]},{arguments[2]});")
else if cname == "NativeArray" then
v.native_array_def(pname, ret, arguments)
return true
+ else if cname == "Int8" then
+ if pname == "output" then
+ v.add("printf(\"%\"PRIi8 \"\\n\", {arguments.first});")
+ return true
+ else if pname == "object_id" then
+ v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
+ return true
+ else if pname == "+" then
+ v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "-" then
+ v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "unary -" then
+ v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "unary +" then
+ v.ret(arguments[0])
+ return true
+ else if pname == "*" then
+ v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "/" then
+ v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "%" then
+ v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "<<" then
+ v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == ">>" 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 == "<" then
+ v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == ">" then
+ v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "<=" then
+ v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == ">=" then
+ v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "to_i" then
+ v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_b" then
+ v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_i16" then
+ v.ret(v.new_expr("(int16_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_u16" then
+ v.ret(v.new_expr("(uint16_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_i32" then
+ v.ret(v.new_expr("(int32_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_u32" then
+ v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_f" then
+ v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "&" then
+ v.ret(v.new_expr("{arguments[0]} & {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "|" then
+ v.ret(v.new_expr("{arguments[0]} | {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "^" then
+ v.ret(v.new_expr("{arguments[0]} ^ {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "unary ~" then
+ v.ret(v.new_expr("~{arguments[0]}", ret.as(not null)))
+ return true
+ end
+ else if cname == "Int16" then
+ if pname == "output" then
+ v.add("printf(\"%\"PRIi16 \"\\n\", {arguments.first});")
+ return true
+ else if pname == "object_id" then
+ v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
+ return true
+ else if pname == "+" then
+ v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "-" then
+ v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "unary -" then
+ v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "unary +" then
+ v.ret(arguments[0])
+ return true
+ else if pname == "*" then
+ v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "/" then
+ v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "%" then
+ v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "<<" then
+ v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == ">>" 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 == "<" then
+ v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == ">" then
+ v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "<=" then
+ v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == ">=" then
+ v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "to_i" then
+ v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_b" then
+ v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_i8" then
+ v.ret(v.new_expr("(int8_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_u16" then
+ v.ret(v.new_expr("(uint16_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_i32" then
+ v.ret(v.new_expr("(int32_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_u32" then
+ v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_f" then
+ v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "&" then
+ v.ret(v.new_expr("{arguments[0]} & {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "|" then
+ v.ret(v.new_expr("{arguments[0]} | {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "^" then
+ v.ret(v.new_expr("{arguments[0]} ^ {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "unary ~" then
+ v.ret(v.new_expr("~{arguments[0]}", ret.as(not null)))
+ return true
+ end
+ else if cname == "UInt16" then
+ if pname == "output" then
+ v.add("printf(\"%\"PRIu16 \"\\n\", {arguments.first});")
+ return true
+ else if pname == "object_id" then
+ v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
+ return true
+ else if pname == "+" then
+ v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "-" then
+ v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "unary -" then
+ v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "unary +" then
+ v.ret(arguments[0])
+ return true
+ else if pname == "*" then
+ v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "/" then
+ v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "%" then
+ v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "<<" then
+ v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == ">>" 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 == "<" then
+ v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == ">" then
+ v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "<=" then
+ v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == ">=" then
+ v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "to_i" then
+ v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_b" then
+ v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_i8" then
+ v.ret(v.new_expr("(int8_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_i16" then
+ v.ret(v.new_expr("(int16_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_i32" then
+ v.ret(v.new_expr("(int32_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_u32" then
+ v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_f" then
+ v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "&" then
+ v.ret(v.new_expr("{arguments[0]} & {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "|" then
+ v.ret(v.new_expr("{arguments[0]} | {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "^" then
+ v.ret(v.new_expr("{arguments[0]} ^ {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "unary ~" then
+ v.ret(v.new_expr("~{arguments[0]}", ret.as(not null)))
+ return true
+ end
+ else if cname == "Int32" then
+ if pname == "output" then
+ v.add("printf(\"%\"PRIi32 \"\\n\", {arguments.first});")
+ return true
+ else if pname == "object_id" then
+ v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
+ return true
+ else if pname == "+" then
+ v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "-" then
+ v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "unary -" then
+ v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "unary +" then
+ v.ret(arguments[0])
+ return true
+ else if pname == "*" then
+ v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "/" then
+ v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "%" then
+ v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "<<" then
+ v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == ">>" 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 == "<" then
+ v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == ">" then
+ v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "<=" then
+ v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == ">=" then
+ v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "to_i" then
+ v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_b" then
+ v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_i8" then
+ v.ret(v.new_expr("(int8_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_i16" then
+ v.ret(v.new_expr("(int16_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_u16" then
+ v.ret(v.new_expr("(uint16_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_u32" then
+ v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_f" then
+ v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "&" then
+ v.ret(v.new_expr("{arguments[0]} & {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "|" then
+ v.ret(v.new_expr("{arguments[0]} | {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "^" then
+ v.ret(v.new_expr("{arguments[0]} ^ {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "unary ~" then
+ v.ret(v.new_expr("~{arguments[0]}", ret.as(not null)))
+ return true
+ end
+ else if cname == "UInt32" then
+ if pname == "output" then
+ v.add("printf(\"%\"PRIu32 \"\\n\", {arguments.first});")
+ return true
+ else if pname == "object_id" then
+ v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
+ return true
+ else if pname == "+" then
+ v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "-" then
+ v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "unary -" then
+ v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "unary +" then
+ v.ret(arguments[0])
+ return true
+ else if pname == "*" then
+ v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "/" then
+ v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "%" then
+ v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "<<" then
+ v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == ">>" 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 == "<" then
+ v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == ">" then
+ v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "<=" then
+ v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == ">=" then
+ v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "to_i" then
+ v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_b" then
+ v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_i8" then
+ v.ret(v.new_expr("(int8_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_i16" then
+ v.ret(v.new_expr("(int16_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_u16" then
+ v.ret(v.new_expr("(uint16_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_i32" then
+ v.ret(v.new_expr("(int32_t){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "to_f" then
+ v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
+ return true
+ else if pname == "&" then
+ v.ret(v.new_expr("{arguments[0]} & {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "|" then
+ v.ret(v.new_expr("{arguments[0]} | {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "^" then
+ v.ret(v.new_expr("{arguments[0]} ^ {arguments[1]}", ret.as(not null)))
+ return true
+ else if pname == "unary ~" then
+ v.ret(v.new_expr("~{arguments[0]}", ret.as(not null)))
+ return true
+ end
end
if pname == "exit" then
v.add("exit({arguments[1]});")
var res
if is_lazy then
var set
- var ret = self.mpropdef.static_mtype
+ var ret = self.mtype
var useiset = not ret.is_c_primitive and not ret isa MNullableType
var guard = self.mlazypropdef.mproperty
if useiset then
assert arguments.length == 2
v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1])
if is_lazy then
- var ret = self.mpropdef.static_mtype
+ var ret = self.mtype
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))
var oldnode = v.current_node
v.current_node = self
var old_frame = v.frame
- var frame = new StaticFrame(v, self.mpropdef.as(not null), recv.mcasttype.undecorate.as(MClassType), [recv])
+ var frame = new StaticFrame(v, self.mreadpropdef.as(not null), recv.mcasttype.undecorate.as(MClassType), [recv])
v.frame = frame
var value
- var mtype = self.mpropdef.static_mtype
+ var mtype = self.mtype
assert mtype != null
var nexpr = self.n_expr
end
end
-redef class AIntExpr
- redef fun expr(v) do return v.int_instance(self.value.as(not null))
+redef class AIntegerExpr
+ redef fun expr(v) do
+ if value isa Int then return v.int_instance(value.as(Int))
+ if value isa Byte then return v.byte_instance(value.as(Byte))
+ if value isa Int8 then return v.int8_instance(value.as(Int8))
+ if value isa Int16 then return v.int16_instance(value.as(Int16))
+ if value isa UInt16 then return v.uint16_instance(value.as(UInt16))
+ if value isa Int32 then return v.int32_instance(value.as(Int32))
+ if value isa UInt32 then return v.uint32_instance(value.as(UInt32))
+ # Should never happen
+ abort
+ end
end
redef class AFloatExpr
redef fun expr(v)
do
var i = v.expr(self.n_expr, null)
- return v.type_test(i, self.cast_type.as(not null), "isa")
+ var cast_type = self.cast_type
+ if cast_type == null then return null # no-no on broken node
+ return v.type_test(i, cast_type, "isa")
end
end