model: use the robust `intro_mmodule` instead of `intro.mmodule`.
[nit.git] / src / compiler / java_compiler.nit
index 42d4c85..84b5a47 100644 (file)
@@ -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("<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
@@ -217,8 +285,8 @@ class JavaCompiler
                # compile method structures
                compile_mmethods_to_java
 
-               # TODO compile main
-               modelbuilder.toolcontext.info("NOT YET IMPLEMENTED", 0)
+               # compile main
+               compile_main_function
        end
 
        # Prepare the boxes used to represent Java primitive types
@@ -260,6 +328,30 @@ class JavaCompiler
                        end
                end
        end
+
+       # Generate Java main that call Sys.main
+       fun compile_main_function do
+               var v = new_visitor("{mainmodule.jname}_Main.java")
+               v.add("public class {mainmodule.jname}_Main \{")
+               v.add("  public static void main(String[] args) \{")
+
+               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
 end
 
 # The class visiting the AST
@@ -300,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
@@ -566,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
@@ -584,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)
@@ -601,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)
@@ -610,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
@@ -641,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})\");")
@@ -649,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
@@ -706,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
@@ -758,11 +945,21 @@ class JavaCompilerVisitor
 
        # Generate a alloc-instance + init-attributes
        fun init_instance(mtype: MClassType): RuntimeVariable do
-               var recv = new_recv(mtype)
-               var mclass = mtype.mclass
-               add("{recv} = new RTVal({mclass.rt_name}.get{mclass.rt_name}());")
-               # TODO init attributes
-               return recv
+               var rt_name = mtype.mclass.rt_name
+               var res = new_expr("new RTVal({rt_name}.get{rt_name}())", mtype)
+               generate_init_attr(self, res, mtype)
+               return res
+       end
+
+       # Generate code that initialize the attributes on a new instance
+       fun generate_init_attr(v: JavaCompilerVisitor, recv: RuntimeVariable, mtype: MClassType) do
+               var cds = mtype.collect_mclassdefs(v.compiler.mainmodule).to_a
+               v.compiler.mainmodule.linearize_mclassdefs(cds)
+               for cd in cds do
+                       for npropdef in v.compiler.modelbuilder.collect_attr_propdef(cd) do
+                               npropdef.init_expr(v, recv)
+                       end
+               end
        end
 
        #  Generate a Nit "is" for two runtime_variables
@@ -881,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)
@@ -890,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
 
@@ -899,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
@@ -1055,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
@@ -1101,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
@@ -1198,87 +1427,117 @@ 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
-                       # TODO compile attributes
-                       v.info("NOT YET IMPLEMENTED attribute handling")
+                       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, arguments: Array[RuntimeVariable]) do
+               if mpropdef == self.mfree_init then
+                       assert mpropdef.mproperty.is_root_init
+                       if not mpropdef.is_intro then
+                               v.supercall(mpropdef, arguments.first.mtype.as(MClassType), arguments)
+                       end
+               else
+                       abort
+               end
        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
@@ -1329,10 +1588,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
@@ -1433,10 +1692,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
@@ -1606,6 +1865,40 @@ redef class AAttrPropdef
                var recv = arguments.first
                v.ret v.read_attribute(self.mpropdef.as(not null).mproperty, recv)
        end
+
+       private fun init_expr(v: JavaCompilerVisitor, recv: RuntimeVariable) do
+               if has_value and not is_lazy and not n_expr isa ANullExpr then evaluate_expr(v, recv)
+       end
+
+       # Evaluate, store and return the default value of the attribute
+       private fun evaluate_expr(v: JavaCompilerVisitor, recv: RuntimeVariable): RuntimeVariable do
+               var old = v.frame
+               var frame = new JavaStaticFrame(v, self.mreadpropdef.as(not null), recv.mcasttype.undecorate.as(MClassType), [recv])
+               v.frame = frame
+
+               var value
+               var mtype = self.mtype
+               assert mtype != null
+
+               var nexpr = self.n_expr
+               var nblock = self.n_block
+               if nexpr != null then
+                       value = v.expr(nexpr, mtype)
+               else if nblock != null then
+                       value = v.new_var(mtype)
+                       frame.returnvar = value
+                       frame.returnlabel = v.get_name("RET_LABEL")
+                       v.add("{frame.returnlabel.as(not null)}: \{")
+                       v.stmt(nblock)
+                       v.add("\}")
+               else
+                       abort
+               end
+
+               v.write_attribute(self.mpropdef.as(not null).mproperty, recv, value)
+               v.frame = old
+               return value
+       end
 end
 
 redef class AExpr
@@ -1671,6 +1964,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
@@ -1679,6 +2012,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
@@ -1692,6 +2063,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)
@@ -1719,12 +2150,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 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 AByteExpr
-       redef fun expr(v) do return v.byte_instance(self.value.as(not null))
+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
@@ -1747,6 +2263,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