nitj: implement AIFExpr
[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 transform
29 import frontend
30
31 redef class ToolContext
32
33 # Where to output the generated binary
34 var opt_output = new OptionString("Output file", "-o", "--output")
35
36 # Where to output tmp files
37 var opt_compile_dir = new OptionString("Directory used to generate temporary files", "--compile-dir")
38
39 redef init do
40 super
41 option_context.add_option(opt_output, opt_compile_dir)
42 end
43 end
44
45 redef class ModelBuilder
46
47 # Start the Java compiler
48 fun run_java_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis) do
49 var time0 = get_time
50 toolcontext.info("*** GENERATING JAVA ***", 1)
51
52 var compiler = new JavaCompiler(mainmodule, self, runtime_type_analysis)
53 compiler.do_compilation
54
55 var time1 = get_time
56 toolcontext.info("*** END GENERATING JAVA: {time1-time0} ***", 2)
57 write_and_make(compiler)
58 end
59
60 # Write Java code and compile it into an executable jar
61 fun write_and_make(compiler: JavaCompiler) do
62 var time0 = get_time
63 toolcontext.info("*** WRITING JAVA ***", 1)
64
65 compiler.compile_dir.mkdir
66
67 var jfiles = write_java_files(compiler)
68
69 var time1 = get_time
70 toolcontext.info("*** END WRITING JAVA: {time1-time0} ***", 2)
71
72 time0 = time1
73 toolcontext.info("*** COMPILING JAVA ***", 1)
74
75 build_with_make(compiler, jfiles)
76 write_shell_script(compiler)
77
78 time1 = get_time
79 toolcontext.info("*** END COMPILING JAVA: {time1-time0} ***", 2)
80 end
81
82 # Write files managed by `compiler` into concrete files
83 fun write_java_files(compiler: JavaCompiler): Array[String] do
84 var jfiles = new Array[String]
85 for f in compiler.files do
86 var file = new FileWriter.open("{compiler.compile_dir}/{f.filename}")
87 for line in f.lines do file.write(line)
88 file.close
89 jfiles.add(f.filename)
90 end
91 return jfiles
92 end
93
94 # Compile Java generated files using `make`
95 fun build_with_make(compiler: JavaCompiler, jfiles: Array[String]) do
96 write_manifest(compiler)
97 write_makefile(compiler, jfiles)
98 var compile_dir = compiler.compile_dir
99 var outname = compiler.outname.to_path.filename
100 toolcontext.info("make -N -C {compile_dir} -f {outname}.mk", 2)
101 var res
102 if toolcontext.verbose_level >= 3 then
103 res = sys.system("make -B -C {compile_dir} -f {outname}.mk 2>&1")
104 else
105 res = sys.system("make -B -C {compile_dir} -f {outname}.mk 2>&1 > /dev/null")
106 end
107 if res != 0 then toolcontext.error(null, "make failed! Error code: {res}.")
108 end
109
110 # Write the Makefile used to compile Java generated files into an executable jar
111 fun write_makefile(compiler: JavaCompiler, jfiles: Array[String]) do
112 # list class files from jfiles
113 var ofiles = new List[String]
114 for f in jfiles do ofiles.add(f.strip_extension(".java") + ".class")
115
116 var compile_dir = compiler.compile_dir
117 var outname = compiler.outname.to_path.filename
118 var outpath = (sys.getcwd / compiler.outname).simplify_path
119 var makename = "{compile_dir}/{outname}.mk"
120 var makefile = new FileWriter.open(makename)
121
122 makefile.write("JC = javac\n")
123 makefile.write("JAR = jar\n\n")
124
125 makefile.write("all: {outpath}.jar\n\n")
126
127 makefile.write("{outpath}.jar: {compiler.mainmodule.jname}_Main.class\n")
128 makefile.write("\t$(JAR) cfm {outpath}.jar {outname}.mf {ofiles.join(" ")}\n\n")
129
130 makefile.write("{compiler.mainmodule.jname}_Main.class:\n")
131 makefile.write("\t$(JC) {jfiles.join(" ")}\n\n")
132
133 makefile.write("clean:\n")
134 makefile.write("\trm {ofiles.join(" ")} 2>/dev/null\n\n")
135
136 makefile.close
137 toolcontext.info("Generated makefile: {makename}", 2)
138 end
139
140 # Write the Java manifest file
141 private fun write_manifest(compiler: JavaCompiler) do
142 var compile_dir = compiler.compile_dir
143 var outname = compiler.outname.to_path.filename
144 var maniffile = new FileWriter.open("{compile_dir}/{outname}.mf")
145 maniffile.write("Manifest-Version: 1.0\n")
146 maniffile.write("Main-Class: {compiler.mainmodule.jname}_Main\n")
147 maniffile.close
148 end
149
150 # Write a simple bash script that runs the jar like it was a binary generated by nitc
151 private fun write_shell_script(compiler: JavaCompiler) do
152 var outname = compiler.outname
153 var shfile = new FileWriter.open(outname)
154 shfile.write("#!/bin/bash\n")
155 shfile.write("java -jar {outname}.jar \"$@\"\n")
156 shfile.close
157 sys.system("chmod +x {outname}")
158 end
159 end
160
161 # Compiler that translates Nit code to Java code
162 class JavaCompiler
163 # The main module of the program currently compiled
164 var mainmodule: MModule
165
166 # Modelbuilder used to know the model and the AST
167 var modelbuilder: ModelBuilder
168
169 # The result of the RTA (used to know live types and methods)
170 var runtime_type_analysis: RapidTypeAnalysis
171
172 # Where to generate tmp files
173 var compile_dir: String is lazy do
174 var dir = modelbuilder.toolcontext.opt_compile_dir.value
175 if dir == null then dir = "nitj_compile"
176 return dir
177 end
178
179 # Name of the generated executable
180 var outname: String is lazy do
181 var name = modelbuilder.toolcontext.opt_output.value
182 if name == null then name = mainmodule.jname
183 return name
184 end
185
186 # The list of all associated files
187 # Used to generate .java files
188 var files: Array[JavaCodeFile] = new Array[JavaCodeFile]
189
190 # Force the creation of a new file
191 # The point is to avoid contamination between must-be-compiled-separately files
192 fun new_file(name: String): JavaCodeFile do
193 var file = new JavaCodeFile(name)
194 files.add(file)
195 return file
196 end
197
198 # Kind of visitor to use
199 type VISITOR: JavaCompilerVisitor
200
201 # Initialize a visitor specific for the compiler engine
202 fun new_visitor(filename: String): VISITOR do
203 return new JavaCompilerVisitor(self, new_file(filename))
204 end
205
206 # RuntimeModel representation
207 private var rt_model: JavaRuntimeModel is lazy do return new JavaRuntimeModel
208
209 # Compile Nit code to Java
210 fun do_compilation do
211 # compile java classes used to represents the runtime model of the program
212 rt_model.compile_rtmodel(self)
213 compile_box_kinds
214
215 # compile class structures
216 compile_mclasses_to_java
217
218 # compile method structures
219 compile_mmethods_to_java
220
221 # compile main
222 compile_main_function
223 end
224
225 # Prepare the boxes used to represent Java primitive types
226 fun compile_box_kinds do
227 # Collect all bas box class
228 # FIXME: this is not completely fine with a separate compilation scheme
229 for classname in ["Int", "Bool", "Byte", "Char", "Float"] do
230 var classes = mainmodule.model.get_mclasses_by_name(classname)
231 if classes == null then continue
232 assert classes.length == 1 else print classes.join(", ")
233 box_kinds.add(classes.first.mclass_type)
234 end
235 end
236
237 # Types of boxes used to represent Java primitive types
238 var box_kinds = new Array[MClassType]
239
240 # Generate a `RTClass` for each `MClass` found in model
241 #
242 # This is a global phase because we need to know all the program to build
243 # attributes, fill vft and type table.
244 fun compile_mclasses_to_java do
245 for mclass in mainmodule.model.mclasses do
246 mclass.compile_to_java(new_visitor("{mclass.rt_name}.java"))
247 end
248 end
249
250 # Generate a `RTMethod` for each `MMethodDef` found in model
251 #
252 # This is a separate phase.
253 fun compile_mmethods_to_java do
254 for mmodule in mainmodule.in_importation.greaters do
255 for mclassdef in mmodule.mclassdefs do
256 for mdef in mclassdef.mpropdefs do
257 if mdef isa MMethodDef then
258 mdef.compile_to_java(new_visitor("{mdef.rt_name}.java"))
259 end
260 end
261 end
262 end
263 end
264
265 # Generate Java main that call Sys.main
266 fun compile_main_function do
267 var v = new_visitor("{mainmodule.jname}_Main.java")
268 v.add("public class {mainmodule.jname}_Main \{")
269 v.add(" public static void main(String[] args) \{")
270
271 var main_type = mainmodule.sys_type
272 if main_type != null then
273 var mainmodule = v.compiler.mainmodule
274 var glob_sys = v.init_instance(main_type)
275 var main_init = mainmodule.try_get_primitive_method("init", main_type.mclass)
276 if main_init != null then
277 v.send(main_init, [glob_sys])
278 end
279 var main_method = mainmodule.try_get_primitive_method("run", main_type.mclass) or else
280 mainmodule.try_get_primitive_method("main", main_type.mclass)
281 if main_method != null then
282 v.send(main_method, [glob_sys])
283 end
284 end
285 v.add(" \}")
286 v.add("\}")
287 end
288 end
289
290 # The class visiting the AST
291 #
292 # A visitor is attached to one JavaCodeFile it writes into.
293 class JavaCompilerVisitor
294 super Visitor
295
296 # JavaCompiler used with this visitor
297 type COMPILER: JavaCompiler
298
299 # The associated compiler
300 var compiler: JavaCompiler
301
302 # The file to write generated code into
303 var file: JavaCodeFile
304
305 # Names handling
306
307 private var names = new HashSet[String]
308 private var last: Int = 0
309
310 # Return a new name based on `s` and unique in the visitor
311 fun get_name(s: String): String do
312 if not self.names.has(s) then
313 self.names.add(s)
314 return s
315 end
316 var i = self.last + 1
317 loop
318 var s2 = s + i.to_s
319 if not self.names.has(s2) then
320 self.last = i
321 self.names.add(s2)
322 return s2
323 end
324 i = i + 1
325 end
326 end
327
328 # Variables handling
329
330 # Registered variables
331 protected var variables = new HashMap[Variable, RuntimeVariable]
332
333 # Return the local RuntimeVariable associated to a Nit local variable
334 fun variable(variable: Variable): RuntimeVariable do
335 if variables.has_key(variable) then
336 return variables[variable]
337 else
338 var name = get_name("var_{variable.name}")
339 var mtype = variable.declared_type.as(not null)
340 mtype = anchor(mtype)
341 var res = decl_var(name, mtype)
342 variables[variable] = res
343 return res
344 end
345 end
346
347 # Return a new uninitialized local RuntimeVariable with `name`
348 fun decl_var(name: String, mtype: MType): RuntimeVariable do
349 var res = new RuntimeVariable(name, mtype, mtype)
350 res.is_boxed = not mtype.is_java_primitive
351 add("{mtype.java_type} {name} /* : {mtype} */;")
352 return res
353 end
354
355 # Return a new uninitialized local RuntimeVariable
356 fun new_var(mtype: MType): RuntimeVariable do
357 mtype = anchor(mtype)
358 var name = self.get_name("var")
359 return decl_var(name, mtype)
360 end
361
362 # Calls handling
363
364 # The current `JavaStaticFrame`
365 var frame: nullable JavaStaticFrame = null is writable
366
367 # Return a new local RuntimeVariable initialized from `args[0]`
368 fun new_recv(mtype: MType): RuntimeVariable do
369 var res = new_var(mtype)
370 add("{res} = args[0];")
371 return res
372 end
373
374 # Calls handling
375
376 # Compile a call within a callsite
377 fun compile_callsite(callsite: CallSite, arguments: Array[RuntimeVariable]): nullable RuntimeVariable do
378 var initializers = callsite.mpropdef.initializers
379 if not initializers.is_empty then
380 var recv = arguments.first
381
382 var i = 1
383 for p in initializers do
384 if p isa MMethod then
385 var args = [recv]
386 var msignature = p.intro.msignature
387 if msignature != null then
388 for x in msignature.mparameters do
389 args.add arguments[i]
390 i += 1
391 end
392 end
393 send(p, args)
394 else if p isa MAttribute then
395 info("NOT YET IMPLEMENTED {class_name}::compile_callsite for MAttribute `{p}`")
396 #self.write_attribute(p, recv, arguments[i])
397 i += 1
398 else abort
399 end
400 assert i == arguments.length
401
402 return send(callsite.mproperty, [recv])
403 end
404
405 return send(callsite.mproperty, arguments)
406 end
407
408 # Evaluate `args` as expressions in the call of `mpropdef` on `recv`.
409 #
410 # This method is used to manage varargs in signatures and returns the real array
411 # of runtime variables to use in the call.
412 fun varargize(mpropdef: MMethodDef, map: nullable SignatureMap, recv: RuntimeVariable, args: SequenceRead[AExpr]): Array[RuntimeVariable] do
413 var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null)
414 var res = new Array[RuntimeVariable]
415 res.add(recv)
416
417 if msignature.arity == 0 then return res
418
419 if map == null then
420 assert args.length == msignature.arity
421 for ne in args do
422 res.add expr(ne, null)
423 end
424 return res
425 end
426
427 # Eval in order of arguments, not parameters
428 var exprs = new Array[RuntimeVariable].with_capacity(args.length)
429 for ne in args do
430 exprs.add expr(ne, null)
431 end
432
433 # Fill `res` with the result of the evaluation according to the mapping
434 for i in [0..msignature.arity[ do
435 var param = msignature.mparameters[i]
436 var j = map.map.get_or_null(i)
437 if j == null then
438 # default value
439 res.add(null_instance)
440 continue
441 end
442 if param.is_vararg and map.vararg_decl > 0 then
443 var vararg = exprs.sub(j, map.vararg_decl)
444 var elttype = param.mtype
445 var arg = self.vararg_instance(mpropdef, recv, vararg, elttype)
446 res.add(arg)
447 continue
448 end
449 res.add exprs[j]
450 end
451 return res
452 end
453
454 # Generate a static call on a method definition (no receiver needed).
455 fun static_call(mmethoddef: MMethodDef, arguments: Array[RuntimeVariable]): nullable RuntimeVariable do
456 var res: nullable RuntimeVariable
457 var ret = mmethoddef.msignature.as(not null).return_mtype
458 if ret == null then
459 res = null
460 else
461 ret = ret.resolve_for(mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.mmodule, true)
462 res = self.new_var(ret)
463 end
464
465 # Autobox arguments
466 adapt_signature(mmethoddef, arguments)
467
468 var rt_name = mmethoddef.rt_name
469 if res == null then
470 add("{rt_name}.get{rt_name}().exec(new RTVal[]\{{arguments.join(",")}\});")
471 return null
472 end
473 var ress = new_expr("{rt_name}.get{rt_name}().exec(new RTVal[]\{{arguments.join(",")}\});", compiler.mainmodule.object_type)
474 assign(res, ress)
475 return res
476 end
477
478 # Generate a polymorphic send for `method` with `arguments`
479 fun send(mmethod: MMethod, arguments: Array[RuntimeVariable]): nullable RuntimeVariable do
480 # Shortcut calls on primitives
481 if arguments.first.mcasttype.is_java_primitive then
482 return monomorphic_send(mmethod, arguments.first.mcasttype, arguments)
483 end
484 # Polymorphic send
485 return table_send(mmethod, arguments)
486 end
487
488
489 # Handle common special cases before doing the effective method invocation
490 # This methods handle the `==` and `!=` methods and the case of the null receiver.
491 # Note: a { is open in the generated C, that enclose and protect the effective method invocation.
492 # Client must not forget to close the } after them.
493 #
494 # The value returned is the result of the common special cases.
495 # If not null, client must compile it with the result of their own effective method invocation.
496 #
497 # If `before_send` can shortcut the whole message sending, a dummy `if(0){`
498 # is generated to cancel the effective method invocation that will follow
499 # TODO: find a better approach
500 private fun before_send(res: nullable RuntimeVariable, mmethod: MMethodDef, arguments: Array[RuntimeVariable]) do
501 var bool_type = compiler.mainmodule.bool_type
502 var recv = arguments.first
503 var consider_null = mmethod.name == "==" or mmethod.name == "!=" or mmethod.name == "is_same_instance"
504 if recv.mcasttype isa MNullableType or recv.mcasttype isa MNullType then
505 add("if ({recv} == null || {recv}.is_null()) \{")
506 if mmethod.name == "==" or mmethod.name == "is_same_instance" then
507 if res == null then res = new_var(bool_type)
508 var arg = arguments[1]
509 if arg.mcasttype isa MNullableType then
510 add("{res} = ({arg} == null || {arg}.is_null());")
511 else if arg.mcasttype isa MNullType then
512 add("{res} = true; /* is null */")
513 else
514 add("{res} = false; /* {arg.inspect} cannot be null */")
515 end
516 else if mmethod.name == "!=" then
517 if res == null then res = new_var(bool_type)
518 # res = self.new_var(bool_type)
519 var arg = arguments[1]
520 if arg.mcasttype isa MNullableType then
521 add("{res} = ({arg} != null && !{arg}.is_null());")
522 else if arg.mcasttype isa MNullType then
523 add("{res} = false; /* is null */")
524 else
525 add("{res} = true; /* {arg.inspect} cannot be null */")
526 end
527 else
528 add_abort("Receiver is null")
529 ret(null_instance)
530 end
531 add("\} else \{")
532 else
533 add "\{"
534 add "/* recv ({recv}) cannot be null since it's a {recv.mcasttype}"
535 end
536 if consider_null then
537 var arg = arguments[1]
538 if arg.mcasttype isa MNullType then
539 if res == null then res = new_var(bool_type)
540 if mmethod.name == "!=" then
541 add("{res} = true; /* arg is null and recv is not */")
542 else # `==` and `is_same_instance`
543 add("{res} = false; /* arg is null but recv is not */")
544 end
545 add("\}") # closes the null case
546 add("if (false) \{") # what follow is useless, Javac will drop it
547 end
548 end
549 end
550
551 # Perform a method call through vft
552 private fun table_send(mmethod: TableCallable, arguments: Array[RuntimeVariable]): nullable RuntimeVariable do
553 var mdef: MMethodDef
554 var name: String
555 if mmethod isa MMethod then
556 mdef = mmethod.intro
557 name = mmethod.full_name
558 else if mmethod isa MMethodDef then
559 mdef = mmethod
560 name = mmethod.full_name
561 else
562 abort
563 end
564
565 var recv = arguments.first
566 var rect = mdef.mclassdef.bound_mtype
567 var msignature = mdef.msignature.as(not null)
568 msignature = msignature.resolve_for(rect, rect, compiler.mainmodule, true)
569 adapt_signature(mdef, arguments)
570
571 var res: nullable RuntimeVariable
572 var ret = msignature.return_mtype
573 if ret == null then
574 res = null
575 else
576 res = self.new_var(ret)
577 end
578
579 before_send(res, mdef, arguments)
580
581 add "/* concrete call to {mdef} */"
582 if res != null then
583 var ress = new_expr("{recv}.rtclass.vft.get(\"{name}\").exec(new RTVal[]\{{arguments.join(",")}\});", compiler.mainmodule.object_type)
584 assign(res, ress)
585 else
586 add("{recv}.rtclass.vft.get(\"{name}\").exec(new RTVal[]\{{arguments.join(",")}\});")
587 end
588
589 add("\}") # closes the null case
590
591 return res
592 end
593
594 # Generate a super call from a method definition
595 fun supercall(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable do
596 return table_send(m, args)
597 end
598
599 # Generate a monomorphic send for the method `m`, the type `t` and the arguments `args`
600 fun monomorphic_send(m: MMethod, t: MType, args: Array[RuntimeVariable]): nullable RuntimeVariable do
601 assert t isa MClassType
602 var propdef = m.lookup_first_definition(self.compiler.mainmodule, t)
603 return self.static_call(propdef, args)
604 end
605
606 # Code generation
607
608 # Add a line (will be suffixed by `\n`)
609 fun add(line: String) do file.lines.add("{line}\n")
610
611 # Add a new partial line (no `\n` suffix)
612 fun addn(line: String) do file.lines.add(line)
613
614 # Compile a statement (if any)
615 fun stmt(nexpr: nullable AExpr) do
616 if nexpr == null then return
617 var old = self.current_node
618 current_node = nexpr
619 nexpr.stmt(self)
620 current_node = old
621 end
622
623 # Compile an expression an return its result
624 # `mtype` is the expected return type, pass null if no specific type is expected.
625 fun expr(nexpr: AExpr, mtype: nullable MType): RuntimeVariable do
626 var old = current_node
627 current_node = nexpr
628
629 var res = null
630 if nexpr.mtype != null then
631 res = nexpr.expr(self)
632 end
633
634 if mtype != null then
635 mtype = anchor(mtype)
636 res = autobox(res, mtype)
637 end
638
639 current_node = old
640 return res
641 end
642
643 # Alias for `self.expr(nexpr, self.bool_type)`
644 fun expr_bool(nexpr: AExpr): RuntimeVariable do
645 return expr(nexpr, compiler.mainmodule.bool_type)
646 end
647
648 # Correctly assign a left and a right value
649 # Boxing and unboxing is performed if required
650 fun assign(left, right: RuntimeVariable) do
651 add("{left} = {autobox(right, left.mtype)};")
652 end
653
654 # Generate a return with `value`
655 fun ret(value: RuntimeVariable) do
656 var frame = self.frame
657 assert frame != null
658 var returnvar = frame.returnvar
659 if returnvar != null then
660 assign(returnvar, value)
661 end
662 self.add("break {frame.returnlabel.as(not null)};")
663 end
664
665 # Return a new local RuntimeVariable initialized with the Java expression `jexpr`.
666 #
667 # `mtype` is used for the Java return variable initialization.
668 fun new_expr(jexpr: String, mtype: MType): RuntimeVariable do
669 var res = new_var(mtype)
670 add("{res} = {jexpr};")
671 return res
672 end
673
674 # Generate generic abort
675 #
676 # Used by aborts, asserts, casts, etc.
677 fun add_abort(message: String) do
678 add("System.err.print(\"Runtime error: {message}\");")
679 var node = current_node
680 if node != null then
681 add("System.err.print(\" ({node.location.short_location})\");")
682 end
683 add("System.err.println(\"\");")
684 add("System.exit(1);")
685 end
686
687 # Types handling
688
689 # Anchor a type to the main module and the current receiver
690 fun anchor(mtype: MType): MType do
691 if not mtype.need_anchor then return mtype
692 return mtype.anchor_to(compiler.mainmodule, frame.as(not null).receiver)
693 end
694
695 # Adapt the arguments of a method according to targetted `MMethodDef`
696 fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable]) do
697 var msignature = m.msignature.as(not null).resolve_for(
698 m.mclassdef.bound_mtype,
699 m.mclassdef.bound_mtype,
700 m.mclassdef.mmodule, true)
701 args.first = autobox(args.first, compiler.mainmodule.object_type)
702 for i in [0..msignature.arity[ do
703 args[i+1] = autobox(args[i + 1], compiler.mainmodule.object_type)
704 end
705 end
706
707 # Box primitive `value` to `mtype`.
708 private fun box(value: RuntimeVariable, mtype: MType): RuntimeVariable do
709 if value.is_boxed then return value
710 var obj_type = compiler.mainmodule.object_type
711 if value.mtype isa MNullType then
712 return new_expr("new RTVal(null, null)", compiler.mainmodule.model.null_type)
713 end
714 var mbox = value.mtype.as(MClassType).mclass
715 return new_expr("new RTVal({mbox.rt_name}.get{mbox.rt_name}(), {value})", obj_type)
716 end
717
718 # Unbox primitive `value` to `mtype`.
719 private fun unbox(value: RuntimeVariable, mtype: MType): RuntimeVariable do
720 if not value.is_boxed then return value
721 if not mtype.is_java_primitive then return value
722 if compiler.box_kinds.has(mtype) then
723 return new_expr("({mtype.java_type}){value}.value", mtype)
724 else
725 info "NOT YET IMPLEMENTED unbox for {value} ({mtype})"
726 abort
727 end
728 end
729
730 # Box or unbox primitive `value` to `mtype` if needed.
731 private fun autobox(value: RuntimeVariable, mtype: MType): RuntimeVariable do
732 if mtype.is_java_primitive then return unbox(value, mtype)
733 return box(value, mtype)
734 end
735
736 # Can this `value` be a primitive Java value?
737 private fun can_be_primitive(value: RuntimeVariable): Bool do
738 var t = value.mcasttype.undecorate
739 if not t isa MClassType then return false
740 var k = t.mclass.kind
741 return k == interface_kind or t.is_java_primitive
742 end
743
744 # Native instances
745
746 # Generate an integer value
747 fun int_instance(value: Int): RuntimeVariable do
748 var t = compiler.mainmodule.int_type
749 return new RuntimeVariable(value.to_s, t, t)
750 end
751
752 # Generate a byte value
753 fun byte_instance(value: Byte): RuntimeVariable do
754 var t = compiler.mainmodule.byte_type
755 return new RuntimeVariable(value.to_s, t, t)
756 end
757
758 # Generate a char value
759 fun char_instance(value: Char): RuntimeVariable do
760 var t = compiler.mainmodule.char_type
761 return new RuntimeVariable("'{value.to_s.escape_to_c}'", t, t)
762 end
763
764 # Generate a float value
765 #
766 # FIXME pass a Float, not a string
767 fun float_instance(value: String): RuntimeVariable do
768 var t = compiler.mainmodule.float_type
769 return new RuntimeVariable(value.to_s, t, t)
770 end
771
772 # Generate an integer value
773 fun bool_instance(value: Bool): RuntimeVariable do
774 var t = compiler.mainmodule.bool_type
775 return new RuntimeVariable(value.to_s, t, t)
776 end
777
778 # Generate the `null` value
779 fun null_instance: RuntimeVariable do
780 var t = compiler.mainmodule.model.null_type
781 return new RuntimeVariable("null", t, t)
782 end
783
784 # Get an instance of a array for a vararg
785 fun vararg_instance(mpropdef: MPropDef, recv: RuntimeVariable, varargs: Array[RuntimeVariable], elttype: MType): RuntimeVariable do
786 # TODO handle dynamic types
787 info("NOT YET IMPLEMENTED vararg_instance")
788 return null_instance
789 # TODO return array_instance(varargs, elttype)
790 end
791
792 # Nit instances
793
794 # Generate a alloc-instance + init-attributes
795 fun init_instance(mtype: MClassType): RuntimeVariable do
796 var rt_name = mtype.mclass.rt_name
797 var res = new_expr("new RTVal({rt_name}.get{rt_name}())", mtype)
798 generate_init_attr(self, res, mtype)
799 return res
800 end
801
802 # Generate code that initialize the attributes on a new instance
803 fun generate_init_attr(v: JavaCompilerVisitor, recv: RuntimeVariable, mtype: MClassType) do
804 var cds = mtype.collect_mclassdefs(v.compiler.mainmodule).to_a
805 v.compiler.mainmodule.linearize_mclassdefs(cds)
806 for cd in cds do
807 for npropdef in v.compiler.modelbuilder.collect_attr_propdef(cd) do
808 npropdef.init_expr(v, recv)
809 end
810 end
811 end
812
813 # Generate a Nit "is" for two runtime_variables
814 fun equal_test(value1, value2: RuntimeVariable): RuntimeVariable do
815 var res = new_var(compiler.mainmodule.bool_type)
816 if value2.mtype.is_java_primitive and not value1.mtype.is_java_primitive then
817 var tmp = value1
818 value1 = value2
819 value2 = tmp
820 end
821 if value1.mtype.is_java_primitive then
822 if value2.mtype == value1.mtype then
823 add("{res} = {value1} == {value2}; /* == with two primitives */")
824 else if value2.mtype.is_java_primitive then
825 add("{res} = true; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
826 # else if value1.mtype.is_tagged then
827 # add("{res} = ({value2} != NULL) && ({autobox(value2, value1.mtype)} == {value1});")
828 else
829 var rt_name = value1.mtype.as(MClassType).mclass.rt_name
830 add("{res} = ({value2} != null) && ({value2}.rtclass == {rt_name}.get{rt_name}());")
831 add("if ({res}) \{")
832 add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
833 add("\}")
834 end
835 return res
836 end
837 var maybe_null = true
838 var test = new Array[String]
839 var t1 = value1.mcasttype
840 if t1 isa MNullableType then
841 test.add("{value1} != null && !{value1}.is_null()")
842 t1 = t1.mtype
843 else
844 maybe_null = false
845 end
846 var t2 = value2.mcasttype
847 if t2 isa MNullableType then
848 test.add("{value2} != null && !{value2}.is_null()")
849 t2 = t2.mtype
850 else
851 maybe_null = false
852 end
853
854 var incompatible = false
855 var primitive
856 if t1.is_java_primitive then
857 primitive = t1
858 if t1 == t2 then
859 # No need to compare class
860 else if t2.is_java_primitive then
861 incompatible = true
862 else if can_be_primitive(value2) then
863 if t1.is_java_primitive then
864 self.add("{res} = {value1} == {value2}; /* t1 is primitive and t2 can be */")
865 return res
866 end
867 # if not compiler.modelbuilder.toolcontext.opt_no_tag_primitives.value then
868 # test.add("(!{extract_tag(value2)})")
869 # end
870 test.add("{value1}.rtclass == {value2}.rtclass")
871 else
872 incompatible = true
873 end
874 else if t2.is_java_primitive then
875 primitive = t2
876 if can_be_primitive(value1) then
877 if t2.is_java_primitive then
878 self.add("{res} = {value1} == {value2}; /* t2 is primitive and t1 can be */")
879 return res
880 end
881 test.add("{value1}.rtclass == {value2}.rtclass")
882 else
883 incompatible = true
884 end
885 else
886 primitive = null
887 end
888
889 if incompatible then
890 if maybe_null then
891 self.add("{res} = {value1} == {value2}; /* incompatible types {t1} vs. {t2}; but may be NULL*/")
892 return res
893 else
894 self.add("{res} = false; /* incompatible types {t1} vs. {t2}; cannot be NULL */")
895 return res
896 end
897 end
898 if primitive != null then
899 if primitive.is_java_primitive then
900 self.add("{res} = {value1} == {value2};")
901 return res
902 end
903 test.add("({value1}.value == {value2}.value")
904 else if can_be_primitive(value1) and can_be_primitive(value2) then
905 test.add("{value1}.rtclass == {value2}.rtclass")
906 var s = new Array[String]
907 for b in compiler.box_kinds do
908 var rt_name = b.mclass.rt_name
909 s.add "({value1}.rtclass == {rt_name}.get{rt_name}()) && ({value1}.value.equals({value2}.value))"
910 if b.mclass.name == "Float" then
911 s.add "({value1}.rtclass == RTClass_kernel_Float.getRTClass_kernel_Float() && {value1}.rtclass == {value2}.rtclass && Math.abs((double)({value1}.value)) == 0.0 && Math.abs((double)({value2}.value)) == 0.0)"
912 end
913 end
914 if s.is_empty then
915 self.add("{res} = {value1} == {value2}; /* both can be primitive */")
916 return res
917 end
918 test.add("({s.join(" || ")})")
919 else
920 self.add("{res} = {value1} == {value2}; /* no primitives */")
921 return res
922 end
923 self.add("{res} = {value1} == {value2} || ({test.join(" && ")});")
924 return res
925 end
926
927 # Attributes
928
929 # Generate a polymorphic attribute is_set test
930 fun isset_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable do
931 # TODO self.check_recv_notnull(recv)
932 var res = new_var(compiler.mainmodule.bool_type)
933
934 # What is the declared type of the attribute?
935 var mtype = a.intro.static_mtype.as(not null)
936 var intromclassdef = a.intro.mclassdef
937 mtype = mtype.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
938
939 if mtype isa MNullableType then
940 add("{res} = true; /* easy isset: {a} on {recv.inspect} */")
941 return res
942 end
943 add("{res} = {recv}.attrs.get(\"{a.jname}\") != null; /* {a} on {recv.inspect} */")
944 return res
945 end
946
947 # Generate a polymorphic attribute read
948 fun read_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable do
949 # TODO check_recv_notnull(recv)
950 # TODO compile_check(v)
951 # What is the declared type of the attribute?
952 var ret = a.intro.static_mtype.as(not null)
953 var intromclassdef = a.intro.mclassdef
954 ret = ret.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
955
956 # Check for Uninitialized attribute
957 if not ret isa MNullableType then check_attribute(a, recv)
958
959 return new_expr("{recv}.attrs.get(\"{a.jname}\")", ret)
960 end
961
962 # Generate a polymorphic attribute write
963 fun write_attribute(a: MAttribute, recv: RuntimeVariable, value: RuntimeVariable) do
964 # TODO check_recv_notnull(recv)
965 add "{recv}.attrs.put(\"{a.jname}\", {autobox(value, compiler.mainmodule.object_type)});"
966 end
967
968 # Check uninitialized attribute
969 fun check_attribute(a: MAttribute, recv: RuntimeVariable) do
970 add "if({recv}.attrs.get(\"{a.jname}\") == null) \{"
971 add_abort "Uninitialized attribute {a.name}"
972 add "\}"
973 end
974
975 # Utils
976
977 # Display a info message
978 fun info(str: String) do compiler.modelbuilder.toolcontext.info(str, 0)
979 end
980
981 # A file containing Java code.
982 class JavaCodeFile
983
984 # File name
985 var filename: String
986
987 # Lines to write
988 var lines: List[String] = new List[String]
989 end
990
991 redef class MEntity
992 # A Java compatible name for `self`
993 private fun jname: String do return name.to_cmangle
994 end
995
996 # Handler for runtime classes generation
997 #
998 # We need 3 kinds of runtime structures:
999 # * `RTClass` to represent a global class
1000 # * `RTMethod` to represent a method definition
1001 # * `RTVal` to represent runtime variables
1002 class JavaRuntimeModel
1003
1004 # Compile JavaRuntimeModel structures
1005 fun compile_rtmodel(compiler: JavaCompiler) do
1006 compile_rtclass(compiler)
1007 compile_rtmethod(compiler)
1008 compile_rtval(compiler)
1009 end
1010
1011 # Compile the abstract runtime class structure
1012 #
1013 # Runtime classes have 3 attributes:
1014 # * `class_name`: the class name as a String
1015 # * `vft`: the virtual function table for the class (flattened)
1016 # * `supers`: the super type table (used for type tests)
1017 fun compile_rtclass(compiler: JavaCompiler) do
1018 var v = compiler.new_visitor("RTClass.java")
1019 v.add("import java.util.HashMap;")
1020 v.add("public abstract class RTClass \{")
1021 v.add(" public String class_name;")
1022 v.add(" public HashMap<String, RTMethod> vft = new HashMap<>();")
1023 v.add(" public HashMap<String, RTClass> supers = new HashMap<>();")
1024 v.add(" protected RTClass() \{\}")
1025 v.add("\}")
1026 end
1027
1028 # Compile the abstract runtime method structure
1029 #
1030 # Method body is executed through the `exec` method:
1031 # * `exec` always take an array of RTVal as arg, the first one must be the receiver
1032 # * `exec` always returns a RTVal (or null if the Nit return type is void)
1033 fun compile_rtmethod(compiler: JavaCompiler) do
1034 var v = compiler.new_visitor("RTMethod.java")
1035 v.add("public abstract class RTMethod \{")
1036 v.add(" protected RTMethod() \{\}")
1037 v.add(" public abstract RTVal exec(RTVal[] args);")
1038 v.add("\}")
1039 end
1040
1041 # Compile the runtime value structure
1042 #
1043 # RTVal both represents object instances and primitives values:
1044 # * object instances:
1045 # * `rtclass` the class of the RTVal is instance of
1046 # * `attrs` contains the attributes of the instance
1047 # * primitive values:
1048 # * `rtclass` represents the class of the primitive value Nit type
1049 # * `value` contains the primitive value of the instance
1050 # * null values:
1051 # * they must have both `rtclass` and `value` as null
1052 fun compile_rtval(compiler: JavaCompiler) do
1053 var v = compiler.new_visitor("RTVal.java")
1054 v.add("import java.util.HashMap;")
1055 v.add("public class RTVal \{")
1056 v.add(" public RTClass rtclass;")
1057 v.add(" public HashMap<String, RTVal> attrs = new HashMap<>();")
1058 v.add(" Object value;")
1059 v.add(" public RTVal(RTClass rtclass) \{")
1060 v.add(" this.rtclass = rtclass;")
1061 v.add(" \}")
1062 v.add(" public RTVal(RTClass rtclass, Object value) \{")
1063 v.add(" this.rtclass = rtclass;")
1064 v.add(" this.value = value;")
1065 v.add(" \}")
1066 v.add(" public boolean is_null() \{ return rtclass == null && value == null; \}")
1067 v.add("\}")
1068 end
1069 end
1070
1071 # A runtime variable hold a runtime value in Java.
1072 # Runtime variables are associated to Nit local variables and intermediate results in Nit expressions.
1073 class RuntimeVariable
1074
1075 # The name of the variable in the Java code
1076 var name: String
1077
1078 # The static type of the variable (as declard in Java)
1079 var mtype: MType
1080
1081 # The current casted type of the variable (as known in Nit)
1082 var mcasttype: MType is writable
1083
1084 # If the variable exaclty a mcasttype?
1085 # false (usual value) means that the variable is a mcasttype or a subtype.
1086 var is_exact: Bool = false is writable
1087
1088 # Is this variable declared as a RTVal or a Java primitive one?
1089 var is_boxed = false
1090
1091 redef fun to_s do return name
1092
1093 redef fun inspect
1094 do
1095 var exact_str
1096 if self.is_exact then
1097 exact_str = " exact"
1098 else
1099 exact_str = ""
1100 end
1101 var type_str
1102 if self.mtype == self.mcasttype then
1103 type_str = "{mtype}{exact_str}"
1104 else
1105 type_str = "{mtype}({mcasttype}{exact_str})"
1106 end
1107 return "<{name}:{type_str}>"
1108 end
1109 end
1110
1111 # The static context of a visited property in a `JavaCompilerVisitor`
1112 class JavaStaticFrame
1113 # The associated visitor
1114 var visitor: JavaCompilerVisitor
1115
1116 # The executed property.
1117 # A Method in case of a call, an attribute in case of a default initialization.
1118 var mpropdef: MPropDef
1119
1120 # The static type of the receiver
1121 var receiver: MClassType
1122
1123 # Arguments of the method (the first is the receiver)
1124 var arguments: Array[RuntimeVariable]
1125
1126 # The runtime_variable associated to the return (in a function)
1127 var returnvar: nullable RuntimeVariable = null is writable
1128
1129 # The label at the end of the property
1130 var returnlabel: nullable String = null is writable
1131 end
1132
1133 redef class Location
1134 # Return a shortened version of the location with `"{file}:{line_start}"`
1135 fun short_location: String do
1136 var file = self.file
1137 if file == null then return "<no file>:{line_start}"
1138 return "{file.filename.escape_to_c}:{line_start}"
1139 end
1140 end
1141
1142 redef class MType
1143 # Return the Java type associated to a given Nit static type
1144 fun java_type: String do return "RTVal"
1145
1146 # Is the associated Java type a primitive one?
1147 #
1148 # ENSURE `result == (java_type != "Object")`
1149 var is_java_primitive: Bool is lazy do return java_type != "RTVal"
1150 end
1151
1152 redef class MClassType
1153
1154 redef var java_type is lazy do
1155 if mclass.name == "Int" then
1156 return "int"
1157 else if mclass.name == "Bool" then
1158 return "boolean"
1159 else if mclass.name == "Char" then
1160 return "char"
1161 else if mclass.name == "Float" then
1162 return "double"
1163 else if mclass.name == "Byte" then
1164 return "byte"
1165 else if mclass.name == "NativeString" then
1166 return "String"
1167 else if mclass.name == "NativeArray" then
1168 return "Array"
1169 end
1170 return "RTVal"
1171 end
1172 end
1173
1174 redef class MClass
1175
1176 # Runtime name
1177 private fun rt_name: String do return "RTClass_{intro.mmodule.jname}_{jname}"
1178
1179 # Generate a Java RTClass for a Nit MClass
1180 fun compile_to_java(v: JavaCompilerVisitor) do
1181 v.add("public class {rt_name} extends RTClass \{")
1182 v.add(" protected static RTClass instance;")
1183 v.add(" private {rt_name}() \{")
1184 v.add(" this.class_name = \"{name}\";")
1185 compile_vft(v)
1186 compile_type_table(v)
1187 v.add(" \}")
1188 v.add(" public static RTClass get{rt_name}() \{")
1189 v.add(" if(instance == null) \{")
1190 v.add(" instance = new {rt_name}();")
1191 v.add(" \}")
1192 v.add(" return instance;")
1193 v.add(" \}")
1194 v.add("\}")
1195 end
1196
1197 # Compile the virtual function table for the mclass
1198 private fun compile_vft(v: JavaCompilerVisitor) do
1199 # TODO handle generics
1200 if mclass_type.need_anchor then return
1201 var mclassdefs = mclass_type.collect_mclassdefs(v.compiler.mainmodule).to_a
1202 v.compiler.mainmodule.linearize_mclassdefs(mclassdefs)
1203
1204 var mainmodule = v.compiler.mainmodule
1205 for mclassdef in mclassdefs.reversed do
1206 for mprop in mclassdef.intro_mproperties do
1207 var mpropdef = mprop.lookup_first_definition(mainmodule, intro.bound_mtype)
1208 if not mpropdef isa MMethodDef then continue
1209 var rt_name = mpropdef.rt_name
1210 v.add("this.vft.put(\"{mprop.full_name}\", {rt_name}.get{rt_name}());")
1211
1212 # fill super next definitions
1213 while mpropdef.has_supercall do
1214 var prefix = mpropdef.full_name
1215 mpropdef = mpropdef.lookup_next_definition(mainmodule, intro.bound_mtype)
1216 rt_name = mpropdef.rt_name
1217 v.add("this.vft.put(\"{prefix}\", {rt_name}.get{rt_name}());")
1218 end
1219 end
1220 end
1221 end
1222
1223 # Compile the type table for the MClass
1224 fun compile_type_table(v: JavaCompilerVisitor) do
1225 for pclass in in_hierarchy(v.compiler.mainmodule).greaters do
1226 if pclass == self then
1227 v.add("supers.put(\"{pclass.jname}\", this);")
1228 else
1229 v.add("supers.put(\"{pclass.jname}\", {pclass.rt_name}.get{pclass.rt_name}());")
1230 end
1231 end
1232 end
1233 end
1234
1235 # Used as a common type between MMethod and MMethodDef for `table_send`
1236 private interface TableCallable
1237 end
1238
1239 redef class MMethod
1240 super TableCallable
1241 end
1242
1243 redef class MMethodDef
1244 super TableCallable
1245
1246 # Runtime name
1247 private fun rt_name: String do
1248 return "RTMethod_{mclassdef.mmodule.jname}_{mclassdef.mclass.jname}_{mproperty.jname}"
1249 end
1250
1251 # Generate a Java RTMethod for `self`
1252 fun compile_to_java(v: JavaCompilerVisitor) do
1253 v.add("public class {rt_name} extends RTMethod \{")
1254 v.add(" protected static RTMethod instance;")
1255 v.add(" public static RTMethod get{rt_name}() \{")
1256 v.add(" if(instance == null) \{")
1257 v.add(" instance = new {rt_name}();")
1258 v.add(" \}")
1259 v.add(" return instance;")
1260 v.add(" \}")
1261 v.add(" @Override")
1262 v.add(" public RTVal exec(RTVal[] args) \{")
1263 compile_inside_to_java(v)
1264 v.add(" \}")
1265 v.add("\}")
1266 end
1267
1268 # Compile the body of this function
1269 fun compile_inside_to_java(v: JavaCompilerVisitor) do
1270
1271 var modelbuilder = v.compiler.modelbuilder
1272 var node = modelbuilder.mpropdef2node(self)
1273
1274 if is_abstract then
1275 v.add_abort("Abstract method `{mproperty.name}` called on `\" + {selfvar}.rtclass.class_name +\"`")
1276 v.add("return null;")
1277 return
1278 end
1279
1280 if node isa APropdef then
1281 node.compile_to_java(v, self)
1282 else if node isa AClassdef then
1283 node.compile_to_java(v, self)
1284 else
1285 abort
1286 end
1287 end
1288 end
1289
1290 redef class AClassdef
1291 private fun compile_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef) do
1292 if mpropdef == self.mfree_init then
1293 var recv = mpropdef.mclassdef.bound_mtype
1294 var arguments = new Array[RuntimeVariable]
1295 var frame = new JavaStaticFrame(v, mpropdef, recv, arguments)
1296 v.frame = frame
1297
1298 var selfvar = v.decl_var("self", recv)
1299 arguments.add(selfvar)
1300 var boxed = v.new_expr("args[0];", v.compiler.mainmodule.object_type)
1301 v.add "{selfvar} = {v.unbox(boxed, recv)};"
1302
1303 var msignature = mpropdef.msignature
1304 var ret = null
1305 if msignature != null then
1306 ret = msignature.return_mtype
1307 if ret != null then frame.returnvar = v.new_var(ret)
1308 end
1309 frame.returnlabel = v.get_name("RET_LABEL")
1310
1311 assert mpropdef.mproperty.is_root_init
1312 if not mpropdef.is_intro then
1313 v.supercall(mpropdef, arguments.first.mtype.as(MClassType), arguments)
1314 end
1315 else
1316 abort
1317 end
1318 v.add("return null;")
1319 end
1320 end
1321
1322 redef class APropdef
1323
1324 # Compile that property definition to java code
1325 fun compile_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef) do
1326 v.info("NOT YET IMPLEMENTED {class_name}::compile_to_java")
1327 v.add("return null;")
1328 end
1329 end
1330
1331 redef class AMethPropdef
1332 redef fun compile_to_java(v, mpropdef) do
1333 var recv = mpropdef.mclassdef.bound_mtype
1334 var arguments = new Array[RuntimeVariable]
1335 var frame = new JavaStaticFrame(v, mpropdef, recv, arguments)
1336 v.frame = frame
1337
1338 var selfvar = v.decl_var("self", recv)
1339 arguments.add(selfvar)
1340 var boxed = v.new_expr("args[0];", v.compiler.mainmodule.object_type)
1341 v.add "{selfvar} = {v.unbox(boxed, recv)};"
1342
1343 var msignature = mpropdef.msignature
1344 var ret = null
1345 if msignature != null then
1346 ret = msignature.return_mtype
1347 if ret != null then frame.returnvar = v.new_var(ret)
1348 end
1349 frame.returnlabel = v.get_name("RET_LABEL")
1350
1351 if not mpropdef.is_intern and msignature != null then
1352 var i = 0
1353 for mparam in msignature.mparameters do
1354 var variable = n_signature.as(not null).n_params[i].variable
1355 if variable == null then continue
1356 var argvar = v.variable(variable)
1357 boxed = v.new_expr("args[{i + 1}];", v.compiler.mainmodule.object_type)
1358 v.add "{argvar} = {v.unbox(boxed, mparam.mtype)};"
1359 arguments.add(argvar)
1360 i += 1
1361 end
1362 end
1363
1364 v.add("{frame.returnlabel.as(not null)}: \{")
1365
1366 # Call the implicit super-init
1367 var auto_super_inits = self.auto_super_inits
1368 if auto_super_inits != null then
1369 var args = [arguments.first]
1370 for auto_super_init in auto_super_inits do
1371 assert auto_super_init.mproperty != mpropdef.mproperty
1372 args.clear
1373 for i in [0..auto_super_init.msignature.arity+1[ do
1374 args.add(arguments[i])
1375 end
1376 assert auto_super_init.mproperty != mpropdef.mproperty
1377 v.compile_callsite(auto_super_init, args)
1378 end
1379 end
1380 if auto_super_call then
1381 v.supercall(mpropdef, arguments.first.mtype.as(MClassType), arguments)
1382 end
1383
1384 compile_inside_to_java(v, mpropdef)
1385 v.add("\}")
1386
1387 if ret != null then
1388 if ret.is_java_primitive then
1389 boxed = v.box(frame.returnvar.as(not null), v.compiler.mainmodule.object_type)
1390 v.add("return {boxed};")
1391 else
1392 v.add("return {frame.returnvar.as(not null)};")
1393 end
1394 else
1395 v.add("return null;")
1396 end
1397 v.frame = null
1398 end
1399
1400 # Compile the inside of the method body
1401 private fun compile_inside_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef) do
1402 # Compile intern methods
1403 if mpropdef.is_intern then
1404 if compile_intern_to_java(v, mpropdef, arguments) then return
1405 v.info("NOT YET IMPLEMENTED compile_intern for {mpropdef}")
1406 v.ret(v.null_instance)
1407 return
1408 end
1409
1410 # Compile block if any
1411 var n_block = n_block
1412 if n_block != null then
1413 v.stmt(n_block)
1414 return
1415 end
1416 end
1417
1418 # Compile an intern method using Java primitives
1419 fun compile_intern_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable]): Bool do
1420 var pname = mpropdef.mproperty.name
1421 var cname = mpropdef.mclassdef.mclass.name
1422 var ret = mpropdef.msignature.as(not null).return_mtype
1423 if cname == "Int" then
1424 if pname == "output" then
1425 v.add("System.out.println({arguments[0]});")
1426 v.ret(v.null_instance)
1427 return true
1428 else if pname == "object_id" then
1429 v.ret(arguments.first)
1430 return true
1431 else if pname == "+" then
1432 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1433 return true
1434 else if pname == "-" then
1435 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1436 return true
1437 else if pname == "unary -" then
1438 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1439 return true
1440 else if pname == "unary +" then
1441 v.ret(arguments[0])
1442 return true
1443 else if pname == "*" then
1444 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1445 return true
1446 else if pname == "/" then
1447 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
1448 return true
1449 else if pname == "%" then
1450 v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null)))
1451 return true
1452 else if pname == "lshift" then
1453 v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
1454 return true
1455 else if pname == "rshift" then
1456 v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null)))
1457 return true
1458 else if pname == "==" then
1459 v.ret(v.equal_test(arguments[0], arguments[1]))
1460 return true
1461 else if pname == "!=" then
1462 var res = v.equal_test(arguments[0], arguments[1])
1463 v.ret(v.new_expr("!{res}", ret.as(not null)))
1464 return true
1465 else if pname == "<" then
1466 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1467 return true
1468 else if pname == ">" then
1469 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1470 return true
1471 else if pname == "<=" then
1472 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1473 return true
1474 else if pname == ">=" then
1475 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1476 return true
1477 else if pname == "to_f" then
1478 v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
1479 return true
1480 else if pname == "to_b" then
1481 v.ret(v.new_expr("(byte){arguments[0]}", ret.as(not null)))
1482 return true
1483 else if pname == "ascii" then
1484 v.ret(v.new_expr("(char){arguments[0]}", ret.as(not null)))
1485 return true
1486 end
1487 else if cname == "Char" then
1488 if pname == "output" then
1489 v.add("System.out.print({arguments[0]});")
1490 v.ret(v.null_instance)
1491 return true
1492 else if pname == "object_id" then
1493 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1494 return true
1495 else if pname == "successor" then
1496 v.ret(v.new_expr("(char)({arguments[0]} + {arguments[1]})", ret.as(not null)))
1497 return true
1498 else if pname == "predecessor" then
1499 v.ret(v.new_expr("(char)({arguments[0]} - {arguments[1]})", ret.as(not null)))
1500 return true
1501 else if pname == "==" then
1502 v.ret(v.equal_test(arguments[0], arguments[1]))
1503 return true
1504 else if pname == "!=" then
1505 var res = v.equal_test(arguments[0], arguments[1])
1506 v.ret(v.new_expr("!{res}", ret.as(not null)))
1507 return true
1508 else if pname == "<" then
1509 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1510 return true
1511 else if pname == ">" then
1512 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1513 return true
1514 else if pname == "<=" then
1515 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1516 return true
1517 else if pname == ">=" then
1518 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1519 return true
1520 else if pname == "to_i" then
1521 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1522 return true
1523 else if pname == "ascii" then
1524 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1525 return true
1526 end
1527 else if cname == "Byte" then
1528 if pname == "output" then
1529 v.add("System.out.println({arguments[0]});")
1530 v.ret(v.null_instance)
1531 return true
1532 else if pname == "object_id" then
1533 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1534 return true
1535 else if pname == "+" then
1536 v.ret(v.new_expr("(byte)({arguments[0]} + {arguments[1]})", ret.as(not null)))
1537 return true
1538 else if pname == "-" then
1539 v.ret(v.new_expr("(byte)({arguments[0]} - {arguments[1]})", ret.as(not null)))
1540 return true
1541 else if pname == "unary -" then
1542 v.ret(v.new_expr("(byte)(-{arguments[0]})", ret.as(not null)))
1543 return true
1544 else if pname == "unary +" then
1545 v.ret(arguments[0])
1546 return true
1547 else if pname == "*" then
1548 v.ret(v.new_expr("(byte)({arguments[0]} * {arguments[1]})", ret.as(not null)))
1549 return true
1550 else if pname == "/" then
1551 v.ret(v.new_expr("(byte)({arguments[0]} / {arguments[1]})", ret.as(not null)))
1552 return true
1553 else if pname == "%" then
1554 v.ret(v.new_expr("(byte)({arguments[0]} % {arguments[1]})", ret.as(not null)))
1555 return true
1556 else if pname == "lshift" then
1557 v.ret(v.new_expr("(byte)({arguments[0]} << {arguments[1]})", ret.as(not null)))
1558 return true
1559 else if pname == "rshift" then
1560 v.ret(v.new_expr("(byte)({arguments[0]} >> {arguments[1]})", ret.as(not null)))
1561 return true
1562 else if pname == "==" then
1563 v.ret(v.equal_test(arguments[0], arguments[1]))
1564 return true
1565 else if pname == "!=" then
1566 var res = v.equal_test(arguments[0], arguments[1])
1567 v.ret(v.new_expr("!{res}", ret.as(not null)))
1568 return true
1569 else if pname == "<" then
1570 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1571 return true
1572 else if pname == ">" then
1573 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1574 return true
1575 else if pname == "<=" then
1576 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1577 return true
1578 else if pname == ">=" then
1579 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1580 return true
1581 else if pname == "to_i" then
1582 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1583 return true
1584 else if pname == "to_f" then
1585 v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
1586 return true
1587 else if pname == "ascii" then
1588 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
1589 return true
1590 end
1591 else if cname == "Bool" then
1592 if pname == "output" then
1593 v.add("System.out.println({arguments[0]});")
1594 v.ret(v.null_instance)
1595 return true
1596 else if pname == "object_id" then
1597 v.ret(v.new_expr("{arguments[0]}?1:0", ret.as(not null)))
1598 return true
1599 else if pname == "==" then
1600 v.ret(v.equal_test(arguments[0], arguments[1]))
1601 return true
1602 else if pname == "!=" then
1603 var res = v.equal_test(arguments[0], arguments[1])
1604 v.ret(v.new_expr("!{res}", ret.as(not null)))
1605 return true
1606 end
1607 else if cname == "Float" then
1608 if pname == "output" then
1609 v.add "if({arguments[0]} == Double.POSITIVE_INFINITY) \{"
1610 v.add "System.out.println(\"inf\");"
1611 v.add "\} else if({arguments[0]} == Double.POSITIVE_INFINITY) \{"
1612 v.add "System.out.println(\"-inf\");"
1613 v.add "\} else \{"
1614 var df = v.get_name("df")
1615 v.add "java.text.DecimalFormat {df} = new java.text.DecimalFormat(\"0.000000\");"
1616 v.add "System.out.println({df}.format({arguments[0]}));"
1617 v.add "\}"
1618 v.ret(v.null_instance)
1619 return true
1620 else if pname == "object_id" then
1621 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1622 return true
1623 else if pname == "+" then
1624 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1625 return true
1626 else if pname == "-" then
1627 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1628 return true
1629 else if pname == "unary -" then
1630 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1631 return true
1632 else if pname == "unary +" then
1633 v.ret(arguments[0])
1634 return true
1635 else if pname == "succ" then
1636 v.ret(v.new_expr("{arguments[0]} + 1", ret.as(not null)))
1637 return true
1638 else if pname == "prec" then
1639 v.ret(v.new_expr("{arguments[0]} - 1", ret.as(not null)))
1640 return true
1641 else if pname == "*" then
1642 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1643 return true
1644 else if pname == "/" then
1645 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
1646 return true
1647 else if pname == "==" then
1648 v.ret(v.equal_test(arguments[0], arguments[1]))
1649 return true
1650 else if pname == "!=" then
1651 var res = v.equal_test(arguments[0], arguments[1])
1652 v.ret(v.new_expr("!{res}", ret.as(not null)))
1653 return true
1654 else if pname == "<" then
1655 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1656 return true
1657 else if pname == ">" then
1658 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1659 return true
1660 else if pname == "<=" then
1661 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1662 return true
1663 else if pname == ">=" then
1664 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1665 return true
1666 else if pname == "to_i" then
1667 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1668 return true
1669 else if pname == "to_b" then
1670 v.ret(v.new_expr("(byte){arguments[0]}", ret.as(not null)))
1671 return true
1672 end
1673 end
1674 if pname == "exit" then
1675 v.add("System.exit({arguments[1]});")
1676 v.ret(v.null_instance)
1677 return true
1678 else if pname == "sys" then
1679 # TODO singleton
1680 var main_type = v.compiler.mainmodule.sys_type.as(not null)
1681 var sys = main_type.mclass
1682 v.ret(v.new_expr("new RTVal({sys.rt_name}.get{sys.rt_name}())", main_type))
1683 return true
1684 else if pname == "object_id" then
1685 v.ret(v.new_expr("{arguments[0]}.hashCode()", ret.as(not null)))
1686 return true
1687 else if pname == "is_same_type" then
1688 v.ret(v.is_same_type_test(arguments[0], arguments[1]))
1689 return true
1690 else if pname == "is_same_instance" then
1691 v.ret(v.equal_test(arguments[0], arguments[1]))
1692 return true
1693 else if pname == "output_class_name" then
1694 v.add("System.out.println({arguments[0]}.rtclass.class_name);")
1695 v.ret(v.null_instance)
1696 return true
1697 end
1698 return false
1699 end
1700 end
1701
1702 redef class AAttrPropdef
1703 redef fun compile_to_java(v, mpropdef, arguments) do
1704 v.current_node = self
1705 if mpropdef == mreadpropdef then
1706 compile_getter(v, mpropdef, arguments)
1707 else if mpropdef == mwritepropdef then
1708 compile_setter(v, mpropdef, arguments)
1709 else
1710 abort
1711 end
1712 v.current_node = null
1713 end
1714
1715 # Compile the setter method
1716 private fun compile_setter(v: JavaCompilerVisitor, mpropdef: MPropDef, arguments: Array[RuntimeVariable]) do
1717 var mtype = v.compiler.mainmodule.object_type
1718 var recv = arguments.first
1719 var val = v.new_expr("args[1]", mtype)
1720 v.write_attribute(self.mpropdef.as(not null).mproperty, recv, val)
1721 v.ret v.null_instance
1722 end
1723
1724 # Compile the getter method
1725 private fun compile_getter(v: JavaCompilerVisitor, mpropdef: MPropDef, arguments: Array[RuntimeVariable]) do
1726 var recv = arguments.first
1727 v.ret v.read_attribute(self.mpropdef.as(not null).mproperty, recv)
1728 end
1729
1730 private fun init_expr(v: JavaCompilerVisitor, recv: RuntimeVariable) do
1731 if has_value and not is_lazy and not n_expr isa ANullExpr then evaluate_expr(v, recv)
1732 end
1733
1734 # Evaluate, store and return the default value of the attribute
1735 private fun evaluate_expr(v: JavaCompilerVisitor, recv: RuntimeVariable): RuntimeVariable do
1736 var old = v.frame
1737 var frame = new JavaStaticFrame(v, self.mreadpropdef.as(not null), recv.mcasttype.undecorate.as(MClassType), [recv])
1738 v.frame = frame
1739
1740 var value
1741 var mtype = self.mtype
1742 assert mtype != null
1743
1744 var nexpr = self.n_expr
1745 var nblock = self.n_block
1746 if nexpr != null then
1747 value = v.expr(nexpr, mtype)
1748 else if nblock != null then
1749 value = v.new_var(mtype)
1750 frame.returnvar = value
1751 frame.returnlabel = v.get_name("RET_LABEL")
1752 v.add("{frame.returnlabel.as(not null)}: \{")
1753 v.stmt(nblock)
1754 v.add("\}")
1755 else
1756 abort
1757 end
1758
1759 v.write_attribute(self.mpropdef.as(not null).mproperty, recv, value)
1760 v.frame = old
1761 return value
1762 end
1763 end
1764
1765 redef class AExpr
1766 # Try to compile self as an expression
1767 # Do not call this method directly, use `v.expr` instead
1768 private fun expr(v: JavaCompilerVisitor): nullable RuntimeVariable do
1769 v.info("NOT YET IMPLEMENTED {class_name}::expr")
1770 return null
1771 end
1772
1773 # Try to compile self as a statement
1774 # Do not call this method directly, use `v.stmt` instead
1775 private fun stmt(v: JavaCompilerVisitor) do expr(v)
1776 end
1777
1778 redef class ABlockExpr
1779 redef fun stmt(v)
1780 do
1781 for e in self.n_expr do v.stmt(e)
1782 end
1783 redef fun expr(v)
1784 do
1785 var last = self.n_expr.last
1786 for e in self.n_expr do
1787 if e == last then break
1788 v.stmt(e)
1789 end
1790 return v.expr(last, null)
1791 end
1792 end
1793
1794 redef class ASendExpr
1795 redef fun expr(v) do
1796 var recv = v.expr(n_expr, null)
1797 var callsite = callsite.as(not null)
1798 var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, raw_arguments)
1799 return v.compile_callsite(callsite, args)
1800 end
1801 end
1802
1803 redef class ANewExpr
1804 redef fun expr(v)
1805 do
1806 var mtype = self.recvtype
1807 assert mtype != null
1808
1809 if mtype.mclass.name == "NativeArray" then
1810 # TODO handle native arrays
1811 v.info("NOT YET IMPLEMENTED new NativeArray")
1812 end
1813
1814 var recv = v.init_instance(mtype)
1815
1816 var callsite = self.callsite
1817 if callsite == null then return recv
1818
1819 var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs)
1820 var res2 = v.compile_callsite(callsite, args)
1821 if res2 != null then
1822 return res2
1823 end
1824 return recv
1825 end
1826 end
1827
1828 redef class ASuperExpr
1829 redef fun expr(v)
1830 do
1831 var frame = v.frame
1832 assert frame != null
1833 var recv = frame.arguments.first
1834
1835 var callsite = self.callsite
1836 if callsite != null then
1837 var args
1838
1839 if self.n_args.n_exprs.is_empty then
1840 # Add automatic arguments for the super init call
1841 args = [recv]
1842 for i in [0..callsite.msignature.arity[ do
1843 args.add(frame.arguments[i+1])
1844 end
1845 else
1846 args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs)
1847 end
1848
1849 # Super init call
1850 var res = v.compile_callsite(callsite, args)
1851 return res
1852 end
1853
1854 var mpropdef = self.mpropdef.as(not null)
1855
1856 var args
1857 if self.n_args.n_exprs.is_empty then
1858 args = frame.arguments
1859 else
1860 args = v.varargize(mpropdef, signaturemap, recv, self.n_args.n_exprs)
1861 end
1862
1863 # Standard call-next-method
1864 return v.supercall(mpropdef, recv.mtype.as(MClassType), args)
1865 end
1866 end
1867
1868 redef class ASelfExpr
1869 redef fun expr(v) do return v.frame.as(not null).arguments.first
1870 end
1871
1872 redef class AImplicitSelfExpr
1873 redef fun expr(v) do return v.frame.as(not null).arguments.first
1874 end
1875
1876 redef class AAttrExpr
1877 redef fun expr(v) do
1878 var recv = v.expr(self.n_expr, null)
1879 var mproperty = self.mproperty.as(not null)
1880 return v.read_attribute(mproperty, recv)
1881 end
1882 end
1883
1884 redef class AAttrAssignExpr
1885 redef fun expr(v) do
1886 var recv = v.expr(self.n_expr, null)
1887 var i = v.expr(self.n_value, null)
1888 var mproperty = self.mproperty.as(not null)
1889 v.write_attribute(mproperty, recv, i)
1890 return i
1891 end
1892 end
1893
1894 redef class AAttrReassignExpr
1895 redef fun stmt(v) do
1896 var recv = v.expr(self.n_expr, null)
1897 var value = v.expr(self.n_value, null)
1898 var mproperty = self.mproperty.as(not null)
1899 var attr = v.read_attribute(mproperty, recv)
1900 var res = v.compile_callsite(self.reassign_callsite.as(not null), [attr, value])
1901 assert res != null
1902 v.write_attribute(mproperty, recv, res)
1903 end
1904 end
1905
1906 redef class AIssetAttrExpr
1907 redef fun expr(v) do
1908 var recv = v.expr(self.n_expr, null)
1909 var mproperty = self.mproperty.as(not null)
1910 return v.isset_attribute(mproperty, recv)
1911 end
1912 end
1913
1914 redef class AReturnExpr
1915 redef fun stmt(v) do
1916 var nexpr = self.n_expr
1917 var frame = v.frame
1918 assert frame != null
1919 if nexpr != null then
1920 v.ret(v.expr(nexpr, frame.returnvar.as(not null).mtype))
1921 else
1922 v.ret(v.null_instance)
1923 end
1924 end
1925 end
1926
1927 redef class AIfExpr
1928 redef fun stmt(v) do
1929 var cond = v.expr_bool(self.n_expr)
1930 v.add("if ({cond})\{")
1931 v.stmt(self.n_then)
1932 v.add("\} else \{")
1933 v.stmt(self.n_else)
1934 v.add("\}")
1935 end
1936
1937 redef fun expr(v) do
1938 var res = v.new_var(self.mtype.as(not null))
1939 var cond = v.expr_bool(self.n_expr)
1940 v.add("if ({cond})\{")
1941 v.assign(res, v.expr(self.n_then.as(not null), null))
1942 v.add("\} else \{")
1943 v.assign(res, v.expr(self.n_else.as(not null), null))
1944 v.add("\}")
1945 return res
1946 end
1947 end
1948
1949 redef class AVardeclExpr
1950 redef fun stmt(v) do
1951 var variable = self.variable.as(not null)
1952 var ne = self.n_expr
1953 var decl = v.variable(variable)
1954 if ne != null then
1955 var i = v.expr(ne, variable.declared_type)
1956 v.assign(decl, i)
1957 end
1958 end
1959 end
1960
1961 redef class AVarExpr
1962 redef fun expr(v) do
1963 return v.variable(self.variable.as(not null))
1964 end
1965 end
1966
1967 redef class AVarAssignExpr
1968 redef fun expr(v) do
1969 var variable = self.variable.as(not null)
1970 var i = v.expr(self.n_value, variable.declared_type)
1971 v.assign(v.variable(variable), i)
1972 return i
1973 end
1974 end
1975
1976 redef class AIntExpr
1977 redef fun expr(v) do return v.int_instance(self.value.as(not null))
1978 end
1979
1980 redef class AByteExpr
1981 redef fun expr(v) do return v.byte_instance(self.value.as(not null))
1982 end
1983
1984 redef class AFloatExpr
1985 redef fun expr(v) do return v.float_instance("{self.n_float.text}") # FIXME use value, not n_float
1986 end
1987
1988 redef class ACharExpr
1989 redef fun expr(v) do return v.char_instance(self.value.as(not null))
1990 end
1991
1992 redef class ATrueExpr
1993 redef fun expr(v) do return v.bool_instance(true)
1994 end
1995
1996 redef class AFalseExpr
1997 redef fun expr(v) do return v.bool_instance(false)
1998 end
1999
2000 redef class ANullExpr
2001 redef fun expr(v) do return v.null_instance
2002 end
2003
2004 redef class AParExpr
2005 redef fun expr(v) do return v.expr(self.n_expr, null)
2006 end
2007
2008 redef class AAbortExpr
2009 redef fun stmt(v) do v.add_abort("Aborted")
2010 end
2011
2012 redef class ADebugTypeExpr
2013 redef fun stmt(v) do end # do nothing
2014 end