X-Git-Url: http://nitlanguage.org diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index 2359c7d..101ff83 100644 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@ -63,12 +63,14 @@ redef class ToolContext 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 @@ -76,10 +78,11 @@ redef class ToolContext 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 @@ -88,17 +91,6 @@ redef class ToolContext 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) @@ -115,15 +107,12 @@ redef class ToolContext 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 @@ -145,14 +134,21 @@ class Toolchain # 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" + 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 @@ -163,14 +159,21 @@ class MakefileToolchain 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] @@ -192,6 +195,10 @@ class MakefileToolchain 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 @@ -200,7 +207,7 @@ class MakefileToolchain 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 = "" @@ -219,7 +226,7 @@ class MakefileToolchain # 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 @@ -327,7 +334,7 @@ class MakefileToolchain var outpath = real_outpath.escape_to_mk if outpath != real_outpath then # If the name is crazy and need escaping, we will do an indirection - # 1. generate the binary in the .nit_compile dir under an escaped name + # 1. generate the binary in the nit_compile dir under an escaped name # 2. copy the binary at the right place in the `all` goal. outpath = mainmodule.c_name end @@ -340,28 +347,63 @@ class MakefileToolchain 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 @@ -418,7 +460,7 @@ endif # 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) @@ -496,6 +538,11 @@ abstract class AbstractCompiler # 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 @@ -559,7 +606,7 @@ abstract class AbstractCompiler # 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 \n") @@ -606,6 +653,8 @@ abstract class AbstractCompiler self.header.add_decl("#include ") self.header.add_decl("#include \n") self.header.add_decl("#include \n") + self.header.add_decl("#include \n") + self.header.add_decl("#include \n") self.header.add_decl("#include \"gc_chooser.h\"") self.header.add_decl("#ifdef ANDROID") self.header.add_decl(" #include ") @@ -713,19 +762,16 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ); do var v = self.new_visitor v.add_decl("#include ") - 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 ") - 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;") @@ -759,7 +805,8 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ); 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)\{") @@ -773,20 +820,17 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ); 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("\}") @@ -815,7 +859,7 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ); 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();") @@ -1103,6 +1147,7 @@ abstract class AbstractCompilerVisitor fun compile_callsite(callsite: CallSite, arguments: Array[RuntimeVariable]): nullable RuntimeVariable do + if callsite.is_broken then return null var initializers = callsite.mpropdef.initializers if not initializers.is_empty then var recv = arguments.first @@ -1146,40 +1191,45 @@ abstract class AbstractCompilerVisitor # Evaluate `args` as expressions in the call of `mpropdef` on `recv`. # This method is used to manage varargs in signatures and returns the real array # of runtime variables to use in the call. - fun varargize(mpropdef: MMethodDef, recv: RuntimeVariable, args: SequenceRead[AExpr]): Array[RuntimeVariable] + fun varargize(mpropdef: MMethodDef, map: nullable SignatureMap, recv: RuntimeVariable, args: SequenceRead[AExpr]): Array[RuntimeVariable] do var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null) var res = new Array[RuntimeVariable] res.add(recv) - if args.is_empty then return res + if msignature.arity == 0 then return res - var vararg_rank = msignature.vararg_rank - var vararg_len = args.length - msignature.arity - if vararg_len < 0 then vararg_len = 0 + if map == null then + assert args.length == msignature.arity + for ne in args do + res.add self.expr(ne, null) + end + return res + end + + # Eval in order of arguments, not parameters + var exprs = new Array[RuntimeVariable].with_capacity(args.length) + for ne in args do + exprs.add self.expr(ne, null) + end + # Fill `res` with the result of the evaluation according to the mapping for i in [0..msignature.arity[ do - if i == vararg_rank then - var ne = args[i] - if ne isa AVarargExpr then - var e = self.expr(ne.n_expr, null) - res.add(e) - continue - end - var vararg = new Array[RuntimeVariable] - for j in [vararg_rank..vararg_rank+vararg_len] do - var e = self.expr(args[j], null) - vararg.add(e) - end - var elttype = msignature.mparameters[vararg_rank].mtype + var param = msignature.mparameters[i] + var j = map.map.get_or_null(i) + if j == null then + # default value + res.add(null_instance) + continue + end + if param.is_vararg and map.vararg_decl > 0 then + var vararg = exprs.sub(j, map.vararg_decl) + var elttype = param.mtype var arg = self.vararg_instance(mpropdef, recv, vararg, elttype) res.add(arg) - else - var j = i - if i > vararg_rank then j += vararg_len - var e = self.expr(args[j], null) - res.add(e) + continue end + res.add exprs[j] end return res end @@ -1450,12 +1500,64 @@ abstract class AbstractCompilerVisitor 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 @@ -1497,8 +1599,9 @@ abstract class AbstractCompilerVisitor 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 @@ -1558,12 +1661,12 @@ abstract class AbstractCompilerVisitor 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 @@ -1574,7 +1677,7 @@ abstract class AbstractCompilerVisitor 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 @@ -1630,10 +1733,11 @@ abstract class AbstractCompilerVisitor fun stmt(nexpr: nullable AExpr) do if nexpr == null then return - if nexpr.mtype == null and not nexpr.is_typed then + if nexpr.is_broken 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 @@ -1655,16 +1759,27 @@ abstract class AbstractCompilerVisitor # `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) @@ -1830,9 +1945,21 @@ redef class MClassType 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 @@ -1863,6 +1990,18 @@ redef class MClassType 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 @@ -2065,12 +2204,6 @@ redef class AMethPropdef 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 @@ -2090,18 +2223,30 @@ redef class AMethPropdef 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 @@ -2132,8 +2277,74 @@ redef class AMethPropdef 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 @@ -2204,13 +2415,31 @@ redef class AMethPropdef 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]});") @@ -2228,6 +2457,441 @@ redef class AMethPropdef 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]});") @@ -2341,7 +3005,7 @@ redef class AAttrPropdef 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 @@ -2369,7 +3033,7 @@ redef class AAttrPropdef 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)) @@ -2391,11 +3055,11 @@ redef class AAttrPropdef 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 @@ -2776,8 +3440,18 @@ redef class AOrElseExpr 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 @@ -2915,7 +3589,9 @@ redef class AIsaExpr 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 @@ -2975,7 +3651,8 @@ redef class ASendExpr do var recv = v.expr(self.n_expr, null) var callsite = self.callsite.as(not null) - var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments) + 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) end end @@ -2985,7 +3662,8 @@ redef class ASendReassignFormExpr do var recv = v.expr(self.n_expr, null) var callsite = self.callsite.as(not null) - var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments) + if callsite.is_broken then return + var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.raw_arguments) var value = v.expr(self.n_value, null) @@ -3007,26 +3685,34 @@ redef class ASuperExpr var callsite = self.callsite if callsite != null then - var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs) + if callsite.is_broken then return null + var args - # Add additional arguments for the super init call - if args.length == 1 then + if self.n_args.n_exprs.is_empty then + # Add automatic arguments for the super init call + args = [recv] for i in [0..callsite.msignature.arity[ do args.add(v.frame.arguments[i+1]) end + else + args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs) end + # Super init call var res = v.compile_callsite(callsite, args) return res end var mpropdef = self.mpropdef.as(not null) - var args = v.varargize(mpropdef, recv, self.n_args.n_exprs) - if args.length == 1 then + + var args + if self.n_args.n_exprs.is_empty then args = v.frame.arguments + else + args = v.varargize(mpropdef, signaturemap, recv, self.n_args.n_exprs) end - # stantard call-next-method + # Standard call-next-method return v.supercall(mpropdef, recv.mtype.as(MClassType), args) end end @@ -3049,8 +3735,9 @@ redef class ANewExpr var callsite = self.callsite if callsite == null then return recv + if callsite.is_broken then return null - var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs) + var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs) var res2 = v.compile_callsite(callsite, args) if res2 != null then #self.debug("got {res2} from {mproperty}. drop {recv}") @@ -3102,6 +3789,20 @@ redef class AIssetAttrExpr end end +redef class AVarargExpr + redef fun expr(v) + do + return v.expr(self.n_expr, null) + end +end + +redef class ANamedargExpr + redef fun expr(v) + do + return v.expr(self.n_expr, null) + end +end + redef class ADebugTypeExpr redef fun stmt(v) do @@ -3174,7 +3875,12 @@ end # Here we load an process all modules passed on the command line var mmodules = modelbuilder.parse(arguments) -if mmodules.is_empty then return +if mmodules.is_empty then + toolcontext.check_errors + toolcontext.errors_info + if toolcontext.error_count > 0 then exit(1) else exit(0) +end + modelbuilder.run_phases for mmodule in mmodules do