nitj: implement `self` accesses
[nit.git] / src / compiler / java_compiler.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Compile Nit code to Java code
16 #
17 # 3 runtime structures are used to represent Nit instance in Java generated code:
18 # * `RTClass` to represent a class, it's super-type table and its VFT
19 # * `RTMethod` to reprensent a compiled method definition
20 # * `RTVal` to reprensent a Nit instance, the null value or a native value
21 #
22 # More details are given in the documentation of these 3 classes.
23 #
24 # TODO Factorize with `abstract_compiler`
25 module java_compiler
26
27 import rapid_type_analysis
28 import frontend
29
30 redef class ToolContext
31
32 # Where to output the generated binary
33 var opt_output = new OptionString("Output file", "-o", "--output")
34
35 # Where to output tmp files
36 var opt_compile_dir = new OptionString("Directory used to generate temporary files", "--compile-dir")
37
38 redef init do
39 super
40 option_context.add_option(opt_output, opt_compile_dir)
41 end
42 end
43
44 redef class ModelBuilder
45
46 # Start the Java compiler
47 fun run_java_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis) do
48 var time0 = get_time
49 toolcontext.info("*** GENERATING JAVA ***", 1)
50
51 var compiler = new JavaCompiler(mainmodule, self, runtime_type_analysis)
52 compiler.do_compilation
53
54 var time1 = get_time
55 toolcontext.info("*** END GENERATING JAVA: {time1-time0} ***", 2)
56 write_and_make(compiler)
57 end
58
59 # Write Java code and compile it into an executable jar
60 fun write_and_make(compiler: JavaCompiler) do
61 var time0 = get_time
62 toolcontext.info("*** WRITING JAVA ***", 1)
63
64 compiler.compile_dir.mkdir
65
66 var jfiles = write_java_files(compiler)
67
68 var time1 = get_time
69 toolcontext.info("*** END WRITING JAVA: {time1-time0} ***", 2)
70
71 time0 = time1
72 toolcontext.info("*** COMPILING JAVA ***", 1)
73
74 build_with_make(compiler, jfiles)
75 write_shell_script(compiler)
76
77 time1 = get_time
78 toolcontext.info("*** END COMPILING JAVA: {time1-time0} ***", 2)
79 end
80
81 # Write files managed by `compiler` into concrete files
82 fun write_java_files(compiler: JavaCompiler): Array[String] do
83 var jfiles = new Array[String]
84 for f in compiler.files do
85 var file = new FileWriter.open("{compiler.compile_dir}/{f.filename}")
86 for line in f.lines do file.write(line)
87 file.close
88 jfiles.add(f.filename)
89 end
90 return jfiles
91 end
92
93 # Compile Java generated files using `make`
94 fun build_with_make(compiler: JavaCompiler, jfiles: Array[String]) do
95 write_manifest(compiler)
96 write_makefile(compiler, jfiles)
97 var compile_dir = compiler.compile_dir
98 var outname = compiler.outname.to_path.filename
99 toolcontext.info("make -N -C {compile_dir} -f {outname}.mk", 2)
100 var res
101 if toolcontext.verbose_level >= 3 then
102 res = sys.system("make -B -C {compile_dir} -f {outname}.mk 2>&1")
103 else
104 res = sys.system("make -B -C {compile_dir} -f {outname}.mk 2>&1 > /dev/null")
105 end
106 if res != 0 then toolcontext.error(null, "make failed! Error code: {res}.")
107 end
108
109 # Write the Makefile used to compile Java generated files into an executable jar
110 fun write_makefile(compiler: JavaCompiler, jfiles: Array[String]) do
111 # list class files from jfiles
112 var ofiles = new List[String]
113 for f in jfiles do ofiles.add(f.strip_extension(".java") + ".class")
114
115 var compile_dir = compiler.compile_dir
116 var outname = compiler.outname.to_path.filename
117 var outpath = (sys.getcwd / compiler.outname).simplify_path
118 var makename = "{compile_dir}/{outname}.mk"
119 var makefile = new FileWriter.open(makename)
120
121 makefile.write("JC = javac\n")
122 makefile.write("JAR = jar\n\n")
123
124 makefile.write("all: {outpath}.jar\n\n")
125
126 makefile.write("{outpath}.jar: {compiler.mainmodule.jname}_Main.class\n")
127 makefile.write("\t$(JAR) cfm {outpath}.jar {outname}.mf {ofiles.join(" ")}\n\n")
128
129 makefile.write("{compiler.mainmodule.jname}_Main.class:\n")
130 makefile.write("\t$(JC) {jfiles.join(" ")}\n\n")
131
132 makefile.write("clean:\n")
133 makefile.write("\trm {ofiles.join(" ")} 2>/dev/null\n\n")
134
135 makefile.close
136 toolcontext.info("Generated makefile: {makename}", 2)
137 end
138
139 # Write the Java manifest file
140 private fun write_manifest(compiler: JavaCompiler) do
141 var compile_dir = compiler.compile_dir
142 var outname = compiler.outname.to_path.filename
143 var maniffile = new FileWriter.open("{compile_dir}/{outname}.mf")
144 maniffile.write("Manifest-Version: 1.0\n")
145 maniffile.write("Main-Class: {compiler.mainmodule.jname}_Main\n")
146 maniffile.close
147 end
148
149 # Write a simple bash script that runs the jar like it was a binary generated by nitc
150 private fun write_shell_script(compiler: JavaCompiler) do
151 var outname = compiler.outname
152 var shfile = new FileWriter.open(outname)
153 shfile.write("#!/bin/bash\n")
154 shfile.write("java -jar {outname}.jar \"$@\"\n")
155 shfile.close
156 sys.system("chmod +x {outname}")
157 end
158 end
159
160 # Compiler that translates Nit code to Java code
161 class JavaCompiler
162 # The main module of the program currently compiled
163 var mainmodule: MModule
164
165 # Modelbuilder used to know the model and the AST
166 var modelbuilder: ModelBuilder
167
168 # The result of the RTA (used to know live types and methods)
169 var runtime_type_analysis: RapidTypeAnalysis
170
171 # Where to generate tmp files
172 var compile_dir: String is lazy do
173 var dir = modelbuilder.toolcontext.opt_compile_dir.value
174 if dir == null then dir = "nitj_compile"
175 return dir
176 end
177
178 # Name of the generated executable
179 var outname: String is lazy do
180 var name = modelbuilder.toolcontext.opt_output.value
181 if name == null then name = mainmodule.jname
182 return name
183 end
184
185 # The list of all associated files
186 # Used to generate .java files
187 var files: Array[JavaCodeFile] = new Array[JavaCodeFile]
188
189 # Force the creation of a new file
190 # The point is to avoid contamination between must-be-compiled-separately files
191 fun new_file(name: String): JavaCodeFile do
192 var file = new JavaCodeFile(name)
193 files.add(file)
194 return file
195 end
196
197 # Kind of visitor to use
198 type VISITOR: JavaCompilerVisitor
199
200 # Initialize a visitor specific for the compiler engine
201 fun new_visitor(filename: String): VISITOR do
202 return new JavaCompilerVisitor(self, new_file(filename))
203 end
204
205 # RuntimeModel representation
206 private var rt_model: JavaRuntimeModel is lazy do return new JavaRuntimeModel
207
208 # Compile Nit code to Java
209 fun do_compilation do
210 # compile java classes used to represents the runtime model of the program
211 rt_model.compile_rtmodel(self)
212
213 # compile class structures
214 compile_mclasses_to_java
215
216 # compile method structures
217 compile_mmethods_to_java
218
219 # TODO compile main
220 modelbuilder.toolcontext.info("NOT YET IMPLEMENTED", 0)
221 end
222
223 # Generate a `RTClass` for each `MClass` found in model
224 #
225 # This is a global phase because we need to know all the program to build
226 # attributes, fill vft and type table.
227 fun compile_mclasses_to_java do
228 for mclass in mainmodule.model.mclasses do
229 mclass.compile_to_java(new_visitor("{mclass.rt_name}.java"))
230 end
231 end
232
233 # Generate a `RTMethod` for each `MMethodDef` found in model
234 #
235 # This is a separate phase.
236 fun compile_mmethods_to_java do
237 for mmodule in mainmodule.in_importation.greaters do
238 for mclassdef in mmodule.mclassdefs do
239 for mdef in mclassdef.mpropdefs do
240 if mdef isa MMethodDef then
241 mdef.compile_to_java(new_visitor("{mdef.rt_name}.java"))
242 end
243 end
244 end
245 end
246 end
247 end
248
249 # The class visiting the AST
250 #
251 # A visitor is attached to one JavaCodeFile it writes into.
252 class JavaCompilerVisitor
253 super Visitor
254
255 # JavaCompiler used with this visitor
256 type COMPILER: JavaCompiler
257
258 # The associated compiler
259 var compiler: JavaCompiler
260
261 # The file to write generated code into
262 var file: JavaCodeFile
263
264 # Names handling
265
266 private var names = new HashSet[String]
267 private var last: Int = 0
268
269 # Return a new name based on `s` and unique in the visitor
270 fun get_name(s: String): String do
271 if not self.names.has(s) then
272 self.names.add(s)
273 return s
274 end
275 var i = self.last + 1
276 loop
277 var s2 = s + i.to_s
278 if not self.names.has(s2) then
279 self.last = i
280 self.names.add(s2)
281 return s2
282 end
283 i = i + 1
284 end
285 end
286
287 # Variables handling
288
289 # Registered variables
290 protected var variables = new HashMap[Variable, RuntimeVariable]
291
292 # Return the local RuntimeVariable associated to a Nit local variable
293 fun variable(variable: Variable): RuntimeVariable do
294 if variables.has_key(variable) then
295 return variables[variable]
296 else
297 var name = get_name("var_{variable.name}")
298 var mtype = variable.declared_type.as(not null)
299 # TODO mtype = self.anchor(mtype)
300 var res = decl_var(name, mtype)
301 variables[variable] = res
302 return res
303 end
304 end
305
306 # Return a new uninitialized local RuntimeVariable with `name`
307 fun decl_var(name: String, mtype: MType): RuntimeVariable do
308 var res = new RuntimeVariable(name, mtype, mtype)
309 add("{mtype.java_type} {name} /* : {mtype} */;")
310 return res
311 end
312
313 # Return a new uninitialized local RuntimeVariable
314 fun new_var(mtype: MType): RuntimeVariable do
315 # TODO mtype = self.anchor(mtype)
316 var name = self.get_name("var")
317 return decl_var(name, mtype)
318 end
319
320 # Calls handling
321
322 # The current `JavaStaticFrame`
323 var frame: nullable JavaStaticFrame = null is writable
324
325 # Return a new local RuntimeVariable initialized from `args[0]`
326 fun new_recv(mtype: MType): RuntimeVariable do
327 var res = new_var(mtype)
328 add("{res} = args[0];")
329 return res
330 end
331
332 # Code generation
333
334 # Add a line (will be suffixed by `\n`)
335 fun add(line: String) do file.lines.add("{line}\n")
336
337 # Add a new partial line (no `\n` suffix)
338 fun addn(line: String) do file.lines.add(line)
339
340 # Compile a statement (if any)
341 fun stmt(nexpr: nullable AExpr) do
342 if nexpr == null then return
343 var old = self.current_node
344 current_node = nexpr
345 nexpr.stmt(self)
346 current_node = old
347 end
348
349 # Compile an expression an return its result
350 # `mtype` is the expected return type, pass null if no specific type is expected.
351 fun expr(nexpr: AExpr, mtype: nullable MType): RuntimeVariable do
352 var old = current_node
353 current_node = nexpr
354
355 var res = null
356 if nexpr.mtype != null then
357 res = nexpr.expr(self)
358 end
359 assert res != null
360 current_node = old
361 return res
362 end
363
364 # Correctly assign a left and a right value
365 # Boxing and unboxing is performed if required
366 fun assign(left, right: RuntimeVariable) do
367 # TODO right = autobox(right, left.mtype)
368 add("{left} = {right};")
369 end
370
371 # Return a new local RuntimeVariable initialized with the Java expression `jexpr`.
372 #
373 # `mtype` is used for the Java return variable initialization.
374 fun new_expr(jexpr: String, mtype: MType): RuntimeVariable do
375 var res = new_var(mtype)
376 add("{res} = {jexpr};")
377 return res
378 end
379
380 # Generate generic abort
381 #
382 # Used by aborts, asserts, casts, etc.
383 fun add_abort(message: String) do
384 add("System.err.print(\"Runtime error: {message}\");")
385 var node = current_node
386 if node != null then
387 add("System.err.print(\" ({node.location.short_location})\");")
388 end
389 add("System.err.println(\"\");")
390 add("System.exit(1);")
391 end
392
393 # Display a info message
394 fun info(str: String) do compiler.modelbuilder.toolcontext.info(str, 0)
395 end
396
397 # A file containing Java code.
398 class JavaCodeFile
399
400 # File name
401 var filename: String
402
403 # Lines to write
404 var lines: List[String] = new List[String]
405 end
406
407 redef class MEntity
408 # A Java compatible name for `self`
409 private fun jname: String do return name.to_cmangle
410 end
411
412 # Handler for runtime classes generation
413 #
414 # We need 3 kinds of runtime structures:
415 # * `RTClass` to represent a global class
416 # * `RTMethod` to represent a method definition
417 # * `RTVal` to represent runtime variables
418 class JavaRuntimeModel
419
420 # Compile JavaRuntimeModel structures
421 fun compile_rtmodel(compiler: JavaCompiler) do
422 compile_rtclass(compiler)
423 compile_rtmethod(compiler)
424 compile_rtval(compiler)
425 end
426
427 # Compile the abstract runtime class structure
428 #
429 # Runtime classes have 3 attributes:
430 # * `class_name`: the class name as a String
431 # * `vft`: the virtual function table for the class (flattened)
432 # * `supers`: the super type table (used for type tests)
433 fun compile_rtclass(compiler: JavaCompiler) do
434 var v = compiler.new_visitor("RTClass.java")
435 v.add("import java.util.HashMap;")
436 v.add("public abstract class RTClass \{")
437 v.add(" public String class_name;")
438 v.add(" public HashMap<String, RTMethod> vft = new HashMap<>();")
439 v.add(" public HashMap<String, RTClass> supers = new HashMap<>();")
440 v.add(" protected RTClass() \{\}")
441 v.add("\}")
442 end
443
444 # Compile the abstract runtime method structure
445 #
446 # Method body is executed through the `exec` method:
447 # * `exec` always take an array of RTVal as arg, the first one must be the receiver
448 # * `exec` always returns a RTVal (or null if the Nit return type is void)
449 fun compile_rtmethod(compiler: JavaCompiler) do
450 var v = compiler.new_visitor("RTMethod.java")
451 v.add("public abstract class RTMethod \{")
452 v.add(" protected RTMethod() \{\}")
453 v.add(" public abstract RTVal exec(RTVal[] args);")
454 v.add("\}")
455 end
456
457 # Compile the runtime value structure
458 #
459 # RTVal both represents object instances and primitives values:
460 # * object instances:
461 # * `rtclass` the class of the RTVal is instance of
462 # * `attrs` contains the attributes of the instance
463 # * primitive values:
464 # * `rtclass` represents the class of the primitive value Nit type
465 # * `value` contains the primitive value of the instance
466 # * null values:
467 # * they must have both `rtclass` and `value` as null
468 fun compile_rtval(compiler: JavaCompiler) do
469 var v = compiler.new_visitor("RTVal.java")
470 v.add("import java.util.HashMap;")
471 v.add("public class RTVal \{")
472 v.add(" public RTClass rtclass;")
473 v.add(" public HashMap<String, RTVal> attrs = new HashMap<>();")
474 v.add(" Object value;")
475 v.add(" public RTVal(RTClass rtclass) \{")
476 v.add(" this.rtclass = rtclass;")
477 v.add(" \}")
478 v.add(" public RTVal(RTClass rtclass, Object value) \{")
479 v.add(" this.rtclass = rtclass;")
480 v.add(" this.value = value;")
481 v.add(" \}")
482 v.add(" public boolean is_null() \{ return rtclass == null && value == null; \}")
483 v.add("\}")
484 end
485 end
486
487 # A runtime variable hold a runtime value in Java.
488 # Runtime variables are associated to Nit local variables and intermediate results in Nit expressions.
489 class RuntimeVariable
490
491 # The name of the variable in the Java code
492 var name: String
493
494 # The static type of the variable (as declard in Java)
495 var mtype: MType
496
497 # The current casted type of the variable (as known in Nit)
498 var mcasttype: MType is writable
499
500 # If the variable exaclty a mcasttype?
501 # false (usual value) means that the variable is a mcasttype or a subtype.
502 var is_exact: Bool = false is writable
503
504 # Is this variable declared as a RTVal or a Java primitive one?
505 var is_boxed = false
506
507 redef fun to_s do return name
508
509 redef fun inspect
510 do
511 var exact_str
512 if self.is_exact then
513 exact_str = " exact"
514 else
515 exact_str = ""
516 end
517 var type_str
518 if self.mtype == self.mcasttype then
519 type_str = "{mtype}{exact_str}"
520 else
521 type_str = "{mtype}({mcasttype}{exact_str})"
522 end
523 return "<{name}:{type_str}>"
524 end
525 end
526
527 # The static context of a visited property in a `JavaCompilerVisitor`
528 class JavaStaticFrame
529 # The associated visitor
530 var visitor: JavaCompilerVisitor
531
532 # The executed property.
533 # A Method in case of a call, an attribute in case of a default initialization.
534 var mpropdef: MPropDef
535
536 # The static type of the receiver
537 var receiver: MClassType
538
539 # Arguments of the method (the first is the receiver)
540 var arguments: Array[RuntimeVariable]
541
542 # The runtime_variable associated to the return (in a function)
543 var returnvar: nullable RuntimeVariable = null is writable
544
545 # The label at the end of the property
546 var returnlabel: nullable String = null is writable
547 end
548
549 redef class Location
550 # Return a shortened version of the location with `"{file}:{line_start}"`
551 fun short_location: String do
552 var file = self.file
553 if file == null then return "<no file>:{line_start}"
554 return "{file.filename.escape_to_c}:{line_start}"
555 end
556 end
557
558 redef class MType
559 # Return the Java type associated to a given Nit static type
560 fun java_type: String do return "RTVal"
561
562 # Is the associated Java type a primitive one?
563 #
564 # ENSURE `result == (java_type != "Object")`
565 var is_java_primitive: Bool is lazy do return java_type != "RTVal"
566 end
567
568 redef class MClassType
569
570 redef var java_type is lazy do
571 if mclass.name == "Int" then
572 return "int"
573 else if mclass.name == "Bool" then
574 return "boolean"
575 else if mclass.name == "Char" then
576 return "char"
577 else if mclass.name == "Float" then
578 return "double"
579 else if mclass.name == "Byte" then
580 return "byte"
581 else if mclass.name == "NativeString" then
582 return "String"
583 else if mclass.name == "NativeArray" then
584 return "Array"
585 end
586 return "RTVal"
587 end
588 end
589
590 redef class MClass
591
592 # Runtime name
593 private fun rt_name: String do return "RTClass_{intro.mmodule.jname}_{jname}"
594
595 # Generate a Java RTClass for a Nit MClass
596 fun compile_to_java(v: JavaCompilerVisitor) do
597 v.add("public class {rt_name} extends RTClass \{")
598 v.add(" protected static RTClass instance;")
599 v.add(" private {rt_name}() \{")
600 v.add(" this.class_name = \"{name}\";")
601 compile_vft(v)
602 compile_type_table(v)
603 v.add(" \}")
604 v.add(" public static RTClass get{rt_name}() \{")
605 v.add(" if(instance == null) \{")
606 v.add(" instance = new {rt_name}();")
607 v.add(" \}")
608 v.add(" return instance;")
609 v.add(" \}")
610 v.add("\}")
611 end
612
613 # Compile the virtual function table for the mclass
614 private fun compile_vft(v: JavaCompilerVisitor) do
615 # TODO handle generics
616 if mclass_type.need_anchor then return
617 var mclassdefs = mclass_type.collect_mclassdefs(v.compiler.mainmodule).to_a
618 v.compiler.mainmodule.linearize_mclassdefs(mclassdefs)
619
620 var mainmodule = v.compiler.mainmodule
621 for mclassdef in mclassdefs.reversed do
622 for mprop in mclassdef.intro_mproperties do
623 var mpropdef = mprop.lookup_first_definition(mainmodule, intro.bound_mtype)
624 if not mpropdef isa MMethodDef then continue
625 var rt_name = mpropdef.rt_name
626 v.add("this.vft.put(\"{mprop.full_name}\", {rt_name}.get{rt_name}());")
627
628 # fill super next definitions
629 while mpropdef.has_supercall do
630 var prefix = mpropdef.full_name
631 mpropdef = mpropdef.lookup_next_definition(mainmodule, intro.bound_mtype)
632 rt_name = mpropdef.rt_name
633 v.add("this.vft.put(\"{prefix}\", {rt_name}.get{rt_name}());")
634 end
635 end
636 end
637 end
638
639 # Compile the type table for the MClass
640 fun compile_type_table(v: JavaCompilerVisitor) do
641 for pclass in in_hierarchy(v.compiler.mainmodule).greaters do
642 if pclass == self then
643 v.add("supers.put(\"{pclass.jname}\", this);")
644 else
645 v.add("supers.put(\"{pclass.jname}\", {pclass.rt_name}.get{pclass.rt_name}());")
646 end
647 end
648 end
649 end
650
651 redef class MMethodDef
652
653 # Runtime name
654 private fun rt_name: String do
655 return "RTMethod_{mclassdef.mmodule.jname}_{mclassdef.mclass.jname}_{mproperty.jname}"
656 end
657
658 # Generate a Java RTMethod for `self`
659 fun compile_to_java(v: JavaCompilerVisitor) do
660 v.add("public class {rt_name} extends RTMethod \{")
661 v.add(" protected static RTMethod instance;")
662 v.add(" public static RTMethod get{rt_name}() \{")
663 v.add(" if(instance == null) \{")
664 v.add(" instance = new {rt_name}();")
665 v.add(" \}")
666 v.add(" return instance;")
667 v.add(" \}")
668 v.add(" @Override")
669 v.add(" public RTVal exec(RTVal[] args) \{")
670 compile_inside_to_java(v)
671 v.add(" \}")
672 v.add("\}")
673 end
674
675 # Compile the body of this function
676 fun compile_inside_to_java(v: JavaCompilerVisitor) do
677
678 var modelbuilder = v.compiler.modelbuilder
679 var node = modelbuilder.mpropdef2node(self)
680
681 if is_abstract then
682 # TODO compile abstract
683 v.info("NOT YET IMPLEMENTED call to abstract method")
684 v.add("return null;")
685 return
686 end
687
688 if node isa APropdef then
689 node.compile_to_java(v, self)
690 else if node isa AClassdef then
691 # TODO compile attributes
692 v.info("NOT YET IMPLEMENTED attribute handling")
693 v.add("return null;")
694 else
695 abort
696 end
697 end
698 end
699
700 redef class APropdef
701
702 # Compile that property definition to java code
703 fun compile_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef) do
704 v.info("NOT YET IMPLEMENTED {class_name}::compile_to_java")
705 end
706 end
707
708 redef class AMethPropdef
709 redef fun compile_to_java(v, mpropdef) do
710 # TODO Call the implicit super-init
711
712 # Compile intern methods
713 if mpropdef.is_intern then
714 v.info("NOT YET IMPLEMENTED {class_name}::compile_intern")
715 # TODO if compile_intern_to_java(v, mpropdef, arguments) then return
716 v.add("return null;")
717 return
718 end
719
720 # Compile block if any
721 var n_block = n_block
722 if n_block != null then
723 v.stmt(n_block)
724 return
725 end
726 end
727 end
728
729 redef class AExpr
730 # Try to compile self as an expression
731 # Do not call this method directly, use `v.expr` instead
732 private fun expr(v: JavaCompilerVisitor): nullable RuntimeVariable do
733 v.info("NOT YET IMPLEMENTED {class_name}::expr")
734 return null
735 end
736
737 # Try to compile self as a statement
738 # Do not call this method directly, use `v.stmt` instead
739 private fun stmt(v: JavaCompilerVisitor) do expr(v)
740 end
741
742 redef class ABlockExpr
743 redef fun stmt(v)
744 do
745 for e in self.n_expr do v.stmt(e)
746 end
747 redef fun expr(v)
748 do
749 var last = self.n_expr.last
750 for e in self.n_expr do
751 if e == last then break
752 v.stmt(e)
753 end
754 return v.expr(last, null)
755 end
756 end
757
758 redef class ASelfExpr
759 redef fun expr(v) do return v.frame.as(not null).arguments.first
760 end
761
762 redef class AImplicitSelfExpr
763 redef fun expr(v) do return v.frame.as(not null).arguments.first
764 end
765
766 redef class AAbortExpr
767 redef fun stmt(v) do v.add_abort("Aborted")
768 end
769
770 redef class ADebugTypeExpr
771 redef fun stmt(v) do end # do nothing
772 end