X-Git-Url: http://nitlanguage.org diff --git a/src/compiler/java_compiler.nit b/src/compiler/java_compiler.nit index dfdff67..7b83104 100644 --- a/src/compiler/java_compiler.nit +++ b/src/compiler/java_compiler.nit @@ -25,6 +25,7 @@ module java_compiler import rapid_type_analysis +import transform import frontend redef class ToolContext @@ -35,9 +36,12 @@ redef class ToolContext # Where to output tmp files var opt_compile_dir = new OptionString("Directory used to generate temporary files", "--compile-dir") + # Compile using ant instead of make (faster, but no error display) + var opt_ant = new OptionBool("Batch with ant (faster, but no error display)", "--ant") + redef init do super - option_context.add_option(opt_output, opt_compile_dir) + option_context.add_option(opt_output, opt_compile_dir, opt_ant) end end @@ -71,7 +75,11 @@ redef class ModelBuilder time0 = time1 toolcontext.info("*** COMPILING JAVA ***", 1) - build_with_make(compiler, jfiles) + if toolcontext.opt_ant.value then + build_with_ant(compiler, jfiles) + else + build_with_make(compiler, jfiles) + end write_shell_script(compiler) time1 = get_time @@ -82,14 +90,32 @@ redef class ModelBuilder fun write_java_files(compiler: JavaCompiler): Array[String] do var jfiles = new Array[String] for f in compiler.files do - var file = new FileWriter.open("{compiler.compile_dir}/{f.filename}") + var filepath = "{compiler.compile_dir}/{f.filename}" + var file = cache_file(filepath) for line in f.lines do file.write(line) - file.close + close_cache(filepath, file) jfiles.add(f.filename) end return jfiles end + # Cache a file as `{filepath}.tmp` and replace the original if different + private fun cache_file(filepath: String): FileWriter do + if toolcontext.opt_ant.value and filepath.file_exists then + return new FileWriter.open("{filepath}.tmp") + else + return new FileWriter.open(filepath) + end + end + + # Close the writer and move tmp file to original if modified + private fun close_cache(filepath: String, file: FileWriter) do + file.close + if "{filepath}.tmp".file_exists then + sys.system("if ! diff {filepath}.tmp {filepath} > /dev/null; then mv {filepath}.tmp {filepath}; else rm {filepath}.tmp; fi") + end + end + # Compile Java generated files using `make` fun build_with_make(compiler: JavaCompiler, jfiles: Array[String]) do write_manifest(compiler) @@ -106,6 +132,23 @@ redef class ModelBuilder if res != 0 then toolcontext.error(null, "make failed! Error code: {res}.") end + # Compile Java sources using `ant` + fun build_with_ant(compiler: JavaCompiler, jfiles: Array[String]) do + compile_antfile(compiler, jfiles) + var outname = compiler.outname.to_path.filename + var antpath = "{compiler.compile_dir}/{outname}.xml" + self.toolcontext.info("ant jar -f {antpath}", 2) + var res + if self.toolcontext.verbose_level >= 3 then + res = sys.system("ant jar -f {antpath} 2>&1") + else + res = sys.system("ant jar -f {antpath} 2>&1 > /dev/null") + end + if res != 0 then + toolcontext.error(null, "ant compile failed! Error code: {res}.") + end + end + # Write the Makefile used to compile Java generated files into an executable jar fun write_makefile(compiler: JavaCompiler, jfiles: Array[String]) do # list class files from jfiles @@ -136,6 +179,31 @@ redef class ModelBuilder toolcontext.info("Generated makefile: {makename}", 2) end + # The Ant `build.xml` script used to compile build the final jar + fun compile_antfile(compiler: JavaCompiler, jfiles: Array[String]) do + var compile_dir = compiler.compile_dir + var outname = compiler.outname.to_path.filename + var outpath = (sys.getcwd / compiler.outname).simplify_path + var antname = "{compile_dir}/{outname}.xml" + var antfile = new FileWriter.open(antname) + var jname = compiler.mainmodule.jname + antfile.write("") + antfile.write(" ") + antfile.write(" ") + antfile.write(" ") + antfile.write(" ") + antfile.write(" ") + antfile.write(" ") + antfile.write(" ") + antfile.write(" ") + antfile.write(" ") + antfile.write(" ") + antfile.write(" ") + antfile.write("") + antfile.close + toolcontext.info("Generated antfile: {antname}", 2) + end + # Write the Java manifest file private fun write_manifest(compiler: JavaCompiler) do var compile_dir = compiler.compile_dir @@ -266,8 +334,21 @@ class JavaCompiler var v = new_visitor("{mainmodule.jname}_Main.java") v.add("public class {mainmodule.jname}_Main \{") v.add(" public static void main(String[] args) \{") - modelbuilder.toolcontext.info("NOT YET IMPLEMENTED", 0) - # TODO compile call to Sys::main + + var main_type = mainmodule.sys_type + if main_type != null then + var mainmodule = v.compiler.mainmodule + var glob_sys = v.init_instance(main_type) + var main_init = mainmodule.try_get_primitive_method("init", main_type.mclass) + if main_init != null then + v.send(main_init, [glob_sys]) + end + var main_method = mainmodule.try_get_primitive_method("run", main_type.mclass) or else + mainmodule.try_get_primitive_method("main", main_type.mclass) + if main_method != null then + v.send(main_method, [glob_sys]) + end + end v.add(" \}") v.add("\}") end @@ -311,6 +392,26 @@ class JavaCompilerVisitor end end + # Return an unique and stable identifier associated with an escapemark + fun escapemark_name(e: nullable EscapeMark): String do + assert e != null + var frame = self.frame + assert frame != null + if frame.escapemark_names.has_key(e) then return frame.escapemark_names[e] + var name = e.name + if name == null then name = "label" + name = get_name(name) + frame.escapemark_names[e] = name + return name + end + + # Insert a C label for associated with an escapemark + fun add_escape_label(e: nullable EscapeMark) do + if e == null then return + if e.escapes.is_empty then return + add("BREAK_{escapemark_name(e)}: ") + end + # Variables handling # Registered variables @@ -396,7 +497,7 @@ class JavaCompilerVisitor # 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, map: nullable SignatureMap, recv: RuntimeVariable, args: SequenceRead[AExpr]): Array[RuntimeVariable] do - var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null) + var msignature = mpropdef.msignature.as(not null) var res = new Array[RuntimeVariable] res.add(recv) @@ -425,8 +526,8 @@ class JavaCompilerVisitor res.add(null_instance) continue end - if param.is_vararg and map.vararg_decl > 0 then - var vararg = exprs.sub(j, map.vararg_decl) + if param.is_vararg and args[i].vararg_decl > 0 then + var vararg = exprs.sub(j, args[i].vararg_decl) var elttype = param.mtype var arg = self.vararg_instance(mpropdef, recv, vararg, elttype) res.add(arg) @@ -577,6 +678,11 @@ class JavaCompilerVisitor return res end + # Generate a super call from a method definition + fun supercall(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable do + return table_send(m, args) + end + # Generate a monomorphic send for the method `m`, the type `t` and the arguments `args` fun monomorphic_send(m: MMethod, t: MType, args: Array[RuntimeVariable]): nullable RuntimeVariable do assert t isa MClassType @@ -595,6 +701,14 @@ class JavaCompilerVisitor # Compile a statement (if any) fun stmt(nexpr: nullable AExpr) do if nexpr == null then return + if nexpr.mtype == null and not nexpr.is_typed then + # Untyped expression. + # Might mean dead code or invalid code + # so aborts + add_abort("FATAL: bad statement executed.") + return + end + var old = self.current_node current_node = nexpr nexpr.stmt(self) @@ -612,6 +726,19 @@ class JavaCompilerVisitor res = nexpr.expr(self) end + if res == null then + # Untyped expression. + # 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 + res = null_instance + + self.current_node = old + return res + end + if mtype != null then mtype = anchor(mtype) res = autobox(res, mtype) @@ -621,6 +748,11 @@ class JavaCompilerVisitor return res end + # Alias for `self.expr(nexpr, self.bool_type)` + fun expr_bool(nexpr: AExpr): RuntimeVariable do + return expr(nexpr, compiler.mainmodule.bool_type) + end + # Correctly assign a left and a right value # Boxing and unboxing is performed if required fun assign(left, right: RuntimeVariable) do @@ -652,6 +784,13 @@ class JavaCompilerVisitor # Used by aborts, asserts, casts, etc. fun add_abort(message: String) do add("System.err.print(\"Runtime error: {message}\");") + add_raw_abort + end + + # Abort without displaying the cause. + # + # Used to customizable errors. + private fun add_raw_abort do var node = current_node if node != null then add("System.err.print(\" ({node.location.short_location})\");") @@ -660,6 +799,15 @@ class JavaCompilerVisitor add("System.exit(1);") end + # Add a dynamic cast + fun add_cast(value: RuntimeVariable, mtype: MType) do + var res = type_test(value, mtype) + add("if (!{res}) \{") + add("System.err.print(\"Runtime error: Cast failed. Expected `{mtype.to_s.escape_to_c}`, got `\" + {value}.rtclass.class_name + \"`\");") + add_raw_abort + add("\}") + end + # Types handling # Anchor a type to the main module and the current receiver @@ -717,6 +865,34 @@ class JavaCompilerVisitor return k == interface_kind or t.is_java_primitive end + # Generate a polymorphic subtype test + fun type_test(value: RuntimeVariable, mtype: MType): RuntimeVariable do + add("/* {value.inspect} isa {mtype} */") + var res = self.new_var(compiler.mainmodule.bool_type) + + # check color is in table + var maybenull = (value.mcasttype isa MNullableType or value.mcasttype isa MNullType) + if maybenull then + add("if({value} == null || {value}.is_null()) \{") + add("{res} = true && {mtype isa MNullableType};") + add("\} else \{") + end + if mtype isa MNullableType then mtype = mtype.mtype + var mclass = mtype.as(MClassType).mclass + add("{res} = {value}.rtclass.supers.get(\"{mclass.jname}\") == {mclass.rt_name}.get{mclass.rt_name}();") + if maybenull then + add("\}") + end + return res + end + + # Generate the code required to dynamically check if 2 objects share the same runtime type + fun is_same_type_test(value1, value2: RuntimeVariable): RuntimeVariable do + var res = self.new_var(compiler.mainmodule.bool_type) + add("{res} = {value1}.rtclass == {value2}.rtclass;") + return res + end + # Native instances # Generate an integer value @@ -902,6 +1078,24 @@ class JavaCompilerVisitor # Attributes + # Generate a polymorphic attribute is_set test + fun isset_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable do + # TODO self.check_recv_notnull(recv) + var res = new_var(compiler.mainmodule.bool_type) + + # What is the declared type of the attribute? + var mtype = a.intro.static_mtype.as(not null) + var intromclassdef = a.intro.mclassdef + mtype = mtype.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true) + + if mtype isa MNullableType then + add("{res} = true; /* easy isset: {a} on {recv.inspect} */") + return res + end + add("{res} = {recv}.attrs.get(\"{a.jname}\") != null; /* {a} on {recv.inspect} */") + return res + end + # Generate a polymorphic attribute read fun read_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable do # TODO check_recv_notnull(recv) @@ -911,6 +1105,9 @@ class JavaCompilerVisitor var intromclassdef = a.intro.mclassdef ret = ret.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true) + # Check for Uninitialized attribute + if not ret isa MNullableType then check_attribute(a, recv) + return new_expr("{recv}.attrs.get(\"{a.jname}\")", ret) end @@ -920,6 +1117,13 @@ class JavaCompilerVisitor add "{recv}.attrs.put(\"{a.jname}\", {autobox(value, compiler.mainmodule.object_type)});" end + # Check uninitialized attribute + fun check_attribute(a: MAttribute, recv: RuntimeVariable) do + add "if({recv}.attrs.get(\"{a.jname}\") == null) \{" + add_abort "Uninitialized attribute {a.name}" + add "\}" + end + # Utils # Display a info message @@ -1076,6 +1280,10 @@ class JavaStaticFrame # The label at the end of the property var returnlabel: nullable String = null is writable + + # Labels associated to a each escapemarks. + # Because of inlinings, escape-marks must be associated to their context (the frame) + private var escapemark_names = new HashMap[EscapeMark, String] end redef class Location @@ -1093,7 +1301,7 @@ redef class MType # Is the associated Java type a primitive one? # - # ENSURE `result == (java_type != "Object")` + # ENSURE `result == (java_type != "RTVal")` var is_java_primitive: Bool is lazy do return java_type != "RTVal" end @@ -1110,7 +1318,7 @@ redef class MClassType return "double" else if mclass.name == "Byte" then return "byte" - else if mclass.name == "NativeString" then + else if mclass.name == "CString" then return "String" else if mclass.name == "NativeArray" then return "Array" @@ -1122,7 +1330,7 @@ end redef class MClass # Runtime name - private fun rt_name: String do return "RTClass_{intro.mmodule.jname}_{jname}" + private fun rt_name: String do return "RTClass_{intro_mmodule.jname}_{jname}" # Generate a Java RTClass for a Nit MClass fun compile_to_java(v: JavaCompilerVisitor) do @@ -1219,99 +1427,116 @@ redef class MMethodDef var modelbuilder = v.compiler.modelbuilder var node = modelbuilder.mpropdef2node(self) + var recv = mclassdef.bound_mtype + var arguments = new Array[RuntimeVariable] + var frame = new JavaStaticFrame(v, self, recv, arguments) + v.frame = frame + + var selfvar = v.decl_var("self", recv) + arguments.add(selfvar) + var boxed = v.new_expr("args[0]", v.compiler.mainmodule.object_type) + v.add "{selfvar} = {v.autobox(boxed, recv)};" + + var msignature = self.msignature + var ret = null + if msignature != null then + ret = msignature.return_mtype + if ret != null then + var retvar = v.decl_var("ret", ret) + if ret.name == "Int" then v.add "{retvar} = 0;" + if ret.name == "Float" then v.add "{retvar} = 0.0;" + if ret.name == "Bool" then v.add "{retvar} = false;" + if ret.name == "Char" then v.add "{retvar} = 0;" + if ret.name == "Byte" then v.add "{retvar} = 0;" + frame.returnvar = retvar + end + end + frame.returnlabel = v.get_name("RET_LABEL") + + v.current_node = node if is_abstract then v.add_abort("Abstract method `{mproperty.name}` called on `\" + {selfvar}.rtclass.class_name +\"`") v.add("return null;") return end + v.current_node = null + + v.add("{frame.returnlabel.as(not null)}: \{") if node isa APropdef then - node.compile_to_java(v, self) + node.compile_to_java(v, self, arguments) else if node isa AClassdef then - node.compile_to_java(v, self) + node.compile_to_java(v, self, arguments) else abort end + + v.add("\}") + if ret != null then + v.add("return {v.autobox(frame.returnvar.as(not null), v.compiler.mainmodule.object_type)};") + else + v.add("return null;") + end end end redef class AClassdef - private fun compile_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef) do - if mpropdef == self.mfree_init then - assert mpropdef.mproperty.is_root_init + private fun compile_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable]) do + if mpropdef.mproperty.is_root_init then if not mpropdef.is_intro then - # TODO v.supercall(mpropdef, arguments.first.mtype.as(MClassType), arguments) + v.supercall(mpropdef, arguments.first.mtype.as(MClassType), arguments) end else abort end - v.add("return null;") end end redef class APropdef # Compile that property definition to java code - fun compile_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef) do + fun compile_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable]) do v.info("NOT YET IMPLEMENTED {class_name}::compile_to_java") - v.add("return null;") end end redef class AMethPropdef - redef fun compile_to_java(v, mpropdef) do - # TODO Call the implicit super-init - - var recv = mpropdef.mclassdef.bound_mtype - var arguments = new Array[RuntimeVariable] - var frame = new JavaStaticFrame(v, mpropdef, recv, arguments) - v.frame = frame - - var selfvar = v.decl_var("self", recv) - arguments.add(selfvar) - var boxed = v.new_expr("args[0];", v.compiler.mainmodule.object_type) - v.add "{selfvar} = {v.unbox(boxed, recv)};" - - var msignature = mpropdef.msignature - var ret = null - if msignature != null then - ret = msignature.return_mtype - if ret != null then frame.returnvar = v.new_var(ret) - end - frame.returnlabel = v.get_name("RET_LABEL") - - if not mpropdef.is_intern and msignature != null then + redef fun compile_to_java(v, mpropdef, arguments) do + if mpropdef.msignature != null then var i = 0 - for mparam in msignature.mparameters do + for mparam in mpropdef.msignature.as(not null).mparameters do var variable = n_signature.as(not null).n_params[i].variable if variable == null then continue var argvar = v.variable(variable) - boxed = v.new_expr("args[{i + 1}];", v.compiler.mainmodule.object_type) - v.add "{argvar} = {v.unbox(boxed, mparam.mtype)};" + v.assign(argvar, v.new_expr("args[{i + 1}]", v.compiler.mainmodule.object_type)) arguments.add(argvar) i += 1 end end - v.add("{frame.returnlabel.as(not null)}: \{") - compile_inside_to_java(v, mpropdef) - v.add("\}") - - if ret != null then - if ret.is_java_primitive then - boxed = v.box(frame.returnvar.as(not null), v.compiler.mainmodule.object_type) - v.add("return {boxed};") - else - v.add("return {frame.returnvar.as(not null)};") + # Call the implicit super-init + var auto_super_inits = self.auto_super_inits + if auto_super_inits != null then + var args = [arguments.first] + for auto_super_init in auto_super_inits do + assert auto_super_init.mproperty != mpropdef.mproperty + args.clear + for i in [0..auto_super_init.msignature.arity+1[ do + args.add(arguments[i]) + end + assert auto_super_init.mproperty != mpropdef.mproperty + v.compile_callsite(auto_super_init, args) end - else - v.add("return null;") end - v.frame = null + if auto_super_call then + v.supercall(mpropdef, arguments.first.mtype.as(MClassType), arguments) + end + + compile_inside_to_java(v, mpropdef, arguments) end # Compile the inside of the method body - private fun compile_inside_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef) do + private fun compile_inside_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable]) do # Compile intern methods if mpropdef.is_intern then if compile_intern_to_java(v, mpropdef, arguments) then return @@ -1362,10 +1587,10 @@ 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 + else if pname == "<<" then v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null))) return true - else if pname == "rshift" then + else if pname == ">>" then v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null))) return true else if pname == "==" then @@ -1466,10 +1691,10 @@ redef class AMethPropdef else if pname == "%" then v.ret(v.new_expr("(byte)({arguments[0]} % {arguments[1]})", ret.as(not null))) return true - else if pname == "lshift" then + else if pname == "<<" then v.ret(v.new_expr("(byte)({arguments[0]} << {arguments[1]})", ret.as(not null))) return true - else if pname == "rshift" then + else if pname == ">>" then v.ret(v.new_expr("(byte)({arguments[0]} >> {arguments[1]})", ret.as(not null))) return true else if pname == "==" then @@ -1662,9 +1887,8 @@ redef class AAttrPropdef value = v.new_var(mtype) frame.returnvar = value frame.returnlabel = v.get_name("RET_LABEL") - v.add("\{") + v.add("{frame.returnlabel.as(not null)}: \{") v.stmt(nblock) - v.add("{frame.returnlabel.as(not null)}:(void)0;") v.add("\}") else abort @@ -1739,6 +1963,46 @@ redef class ANewExpr end end +redef class ASuperExpr + redef fun expr(v) + do + var frame = v.frame + assert frame != null + var recv = frame.arguments.first + + var callsite = self.callsite + if callsite != null then + var args + + 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(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 + if self.n_args.n_exprs.is_empty then + args = frame.arguments + else + args = v.varargize(mpropdef, signaturemap, recv, self.n_args.n_exprs) + end + + # Standard call-next-method + return v.supercall(mpropdef, recv.mtype.as(MClassType), args) + end +end + redef class ASelfExpr redef fun expr(v) do return v.frame.as(not null).arguments.first end @@ -1747,6 +2011,44 @@ redef class AImplicitSelfExpr redef fun expr(v) do return v.frame.as(not null).arguments.first end +redef class AAttrExpr + redef fun expr(v) do + var recv = v.expr(self.n_expr, null) + var mproperty = self.mproperty.as(not null) + return v.read_attribute(mproperty, recv) + end +end + +redef class AAttrAssignExpr + redef fun expr(v) do + var recv = v.expr(self.n_expr, null) + var i = v.expr(self.n_value, null) + var mproperty = self.mproperty.as(not null) + v.write_attribute(mproperty, recv, i) + return i + end +end + +redef class AAttrReassignExpr + redef fun stmt(v) do + var recv = v.expr(self.n_expr, null) + var value = v.expr(self.n_value, null) + var mproperty = self.mproperty.as(not null) + var attr = v.read_attribute(mproperty, recv) + var res = v.compile_callsite(self.reassign_callsite.as(not null), [attr, value]) + assert res != null + v.write_attribute(mproperty, recv, res) + end +end + +redef class AIssetAttrExpr + redef fun expr(v) do + var recv = v.expr(self.n_expr, null) + var mproperty = self.mproperty.as(not null) + return v.isset_attribute(mproperty, recv) + end +end + redef class AReturnExpr redef fun stmt(v) do var nexpr = self.n_expr @@ -1760,6 +2062,66 @@ redef class AReturnExpr end end +redef class AIfExpr + redef fun stmt(v) do + var cond = v.expr_bool(self.n_expr) + v.add("if ({cond})\{") + v.stmt(self.n_then) + v.add("\} else \{") + v.stmt(self.n_else) + v.add("\}") + end + + redef fun expr(v) do + var res = v.new_var(self.mtype.as(not null)) + var cond = v.expr_bool(self.n_expr) + v.add("if ({cond})\{") + v.assign(res, v.expr(self.n_then.as(not null), null)) + v.add("\} else \{") + v.assign(res, v.expr(self.n_else.as(not null), null)) + v.add("\}") + return res + end +end + +redef class ADoExpr + redef fun stmt(v) + do + v.add_escape_label(break_mark) + v.add "\{" + v.stmt(self.n_block) + v.add "\}" + end +end + +redef class AWhileExpr + redef fun stmt(v) + do + v.add_escape_label(break_mark) + v.add_escape_label(continue_mark) + v.add("for(;;) \{") + var cond = v.expr_bool(self.n_expr) + v.add("if (!{cond}) break;") + v.stmt(self.n_block) + v.add("\}") + end +end + +redef class ALoopExpr + redef fun stmt(v) + do + v.add_escape_label(break_mark) + v.add_escape_label(continue_mark) + v.add("for(;;) \{") + v.stmt(self.n_block) + v.add("\}") + end +end + +redef class AEscapeExpr + redef fun stmt(v) do v.add("break BREAK_{v.escapemark_name(escapemark)};") +end + redef class AVardeclExpr redef fun stmt(v) do var variable = self.variable.as(not null) @@ -1787,12 +2149,97 @@ redef class AVarAssignExpr end end -redef class AIntExpr - redef fun expr(v) do return v.int_instance(self.value.as(not null)) + +redef class AAssertExpr + redef fun stmt(v) do + var cond = v.expr_bool(self.n_expr) + v.add("if (!{cond}) \{") + v.stmt(self.n_else) + var nid = self.n_id + if nid != null then + v.add_abort("Assert '{nid.text}' failed") + else + v.add_abort("Assert failed") + end + v.add("\}") + end end -redef class AByteExpr - redef fun expr(v) do return v.byte_instance(self.value.as(not null)) +redef class AImpliesExpr + redef fun expr(v) do + var res = v.new_var(mtype.as(not null)) + var i1 = v.expr_bool(n_expr) + v.add("if (!{i1}) \{") + v.add("{res} = true;") + v.add("\} else \{") + var i2 = v.expr_bool(n_expr2) + v.add("{res} = {i2};") + v.add("\}") + return res + end +end + +redef class AOrElseExpr + redef fun expr(v) + do + var res = v.new_var(self.mtype.as(not null)) + var i1 = v.expr(self.n_expr, null) + v.add("if ({i1} != null && !{i1}.is_null()) \{") + v.assign(res, i1) + v.add("\} else \{") + var i2 = v.expr(self.n_expr2, null) + v.assign(res, i2) + v.add("\}") + return res + end +end + +redef class AOrExpr + redef fun expr(v) do + var res = v.new_var(self.mtype.as(not null)) + var i1 = v.expr_bool(self.n_expr) + v.add("if ({i1}) \{") + v.add("{res} = true;") + v.add("\} else \{") + var i2 = v.expr_bool(self.n_expr2) + v.add("{res} = {i2};") + v.add("\}") + return res + end +end + +redef class AAndExpr + redef fun expr(v) do + var res = v.new_var(self.mtype.as(not null)) + var i1 = v.expr_bool(self.n_expr) + v.add("if (!{i1}) \{") + v.add("{res} = false;") + v.add("\} else \{") + var i2 = v.expr_bool(self.n_expr2) + v.add("{res} = {i2};") + v.add("\}") + return res + end +end + +redef class ANotExpr + redef fun expr(v) do + var cond = v.expr_bool(self.n_expr) + return v.new_expr("!{cond}", self.mtype.as(not null)) + end +end + +redef class AIntegerExpr + redef fun expr(v) do + if value isa Int then + return v.int_instance(self.value.as(Int)) + else if value isa Byte then + return v.byte_instance(self.value.as(Byte)) + else + # Should not happen + abort + end + end end redef class AFloatExpr @@ -1815,6 +2262,41 @@ redef class ANullExpr redef fun expr(v) do return v.null_instance end +redef class AAsCastExpr + redef fun expr(v) + do + var i = v.expr(n_expr, null) + v.add_cast(i, mtype.as(not null)) + return i + end +end + +redef class AAsNotnullExpr + redef fun expr(v) do + var i = v.expr(n_expr, null) + if i.mtype.is_java_primitive then return i + + v.add("if ({i} == null || {i}.is_null()) \{") + v.add_abort("Cast failed") + v.add("\}") + return i + end +end + +redef class AIsaExpr + redef fun expr(v) + do + var i = v.expr(self.n_expr, null) + 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) + end +end + +redef class AParExpr + redef fun expr(v) do return v.expr(self.n_expr, null) +end + redef class AAbortExpr redef fun stmt(v) do v.add_abort("Aborted") end