# 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
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
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)
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
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("<project>")
+ antfile.write(" <target name=\"compile\">")
+ antfile.write(" <mkdir dir=\"classes\"/>")
+ antfile.write(" <javac includes=\"{compiler.mainmodule.jname}_Main.java {jfiles.join(" ")}\" srcdir=\".\" destdir=\"classes\"/>")
+ antfile.write(" </target>")
+ antfile.write(" <target name=\"jar\" depends=\"compile\">")
+ antfile.write(" <jar destfile=\"{outpath}.jar\" basedir=\"classes\">")
+ antfile.write(" <manifest>")
+ antfile.write(" <attribute name=\"Main-Class\" value=\"{jname}_Main\"/>")
+ antfile.write(" </manifest>")
+ antfile.write(" </jar>")
+ antfile.write(" </target>")
+ antfile.write("</project>")
+ 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
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)
# 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})\");")
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
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
redef class AClassdef
private fun compile_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable]) do
- if mpropdef == self.mfree_init then
- assert mpropdef.mproperty.is_root_init
+ if mpropdef.mproperty.is_root_init then
if not mpropdef.is_intro then
v.supercall(mpropdef, arguments.first.mtype.as(MClassType), arguments)
end
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
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
end
end
-redef class AIntExpr
- redef fun expr(v) do return v.int_instance(self.value.as(not null))
-end
-
-redef class AByteExpr
- redef fun expr(v) do return v.byte_instance(self.value.as(not null))
+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
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