nitj: avoid dead code execution
[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 # Return an unique and stable identifier associated with an escapemark
329 fun escapemark_name(e: nullable EscapeMark): String do
330 assert e != null
331 var frame = self.frame
332 assert frame != null
333 if frame.escapemark_names.has_key(e) then return frame.escapemark_names[e]
334 var name = e.name
335 if name == null then name = "label"
336 name = get_name(name)
337 frame.escapemark_names[e] = name
338 return name
339 end
340
341 # Insert a C label for associated with an escapemark
342 fun add_escape_label(e: nullable EscapeMark) do
343 if e == null then return
344 if e.escapes.is_empty then return
345 add("BREAK_{escapemark_name(e)}: ")
346 end
347
348 # Variables handling
349
350 # Registered variables
351 protected var variables = new HashMap[Variable, RuntimeVariable]
352
353 # Return the local RuntimeVariable associated to a Nit local variable
354 fun variable(variable: Variable): RuntimeVariable do
355 if variables.has_key(variable) then
356 return variables[variable]
357 else
358 var name = get_name("var_{variable.name}")
359 var mtype = variable.declared_type.as(not null)
360 mtype = anchor(mtype)
361 var res = decl_var(name, mtype)
362 variables[variable] = res
363 return res
364 end
365 end
366
367 # Return a new uninitialized local RuntimeVariable with `name`
368 fun decl_var(name: String, mtype: MType): RuntimeVariable do
369 var res = new RuntimeVariable(name, mtype, mtype)
370 res.is_boxed = not mtype.is_java_primitive
371 add("{mtype.java_type} {name} /* : {mtype} */;")
372 return res
373 end
374
375 # Return a new uninitialized local RuntimeVariable
376 fun new_var(mtype: MType): RuntimeVariable do
377 mtype = anchor(mtype)
378 var name = self.get_name("var")
379 return decl_var(name, mtype)
380 end
381
382 # Calls handling
383
384 # The current `JavaStaticFrame`
385 var frame: nullable JavaStaticFrame = null is writable
386
387 # Return a new local RuntimeVariable initialized from `args[0]`
388 fun new_recv(mtype: MType): RuntimeVariable do
389 var res = new_var(mtype)
390 add("{res} = args[0];")
391 return res
392 end
393
394 # Calls handling
395
396 # Compile a call within a callsite
397 fun compile_callsite(callsite: CallSite, arguments: Array[RuntimeVariable]): nullable RuntimeVariable do
398 var initializers = callsite.mpropdef.initializers
399 if not initializers.is_empty then
400 var recv = arguments.first
401
402 var i = 1
403 for p in initializers do
404 if p isa MMethod then
405 var args = [recv]
406 var msignature = p.intro.msignature
407 if msignature != null then
408 for x in msignature.mparameters do
409 args.add arguments[i]
410 i += 1
411 end
412 end
413 send(p, args)
414 else if p isa MAttribute then
415 info("NOT YET IMPLEMENTED {class_name}::compile_callsite for MAttribute `{p}`")
416 #self.write_attribute(p, recv, arguments[i])
417 i += 1
418 else abort
419 end
420 assert i == arguments.length
421
422 return send(callsite.mproperty, [recv])
423 end
424
425 return send(callsite.mproperty, arguments)
426 end
427
428 # Evaluate `args` as expressions in the call of `mpropdef` on `recv`.
429 #
430 # This method is used to manage varargs in signatures and returns the real array
431 # of runtime variables to use in the call.
432 fun varargize(mpropdef: MMethodDef, map: nullable SignatureMap, recv: RuntimeVariable, args: SequenceRead[AExpr]): Array[RuntimeVariable] do
433 var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null)
434 var res = new Array[RuntimeVariable]
435 res.add(recv)
436
437 if msignature.arity == 0 then return res
438
439 if map == null then
440 assert args.length == msignature.arity
441 for ne in args do
442 res.add expr(ne, null)
443 end
444 return res
445 end
446
447 # Eval in order of arguments, not parameters
448 var exprs = new Array[RuntimeVariable].with_capacity(args.length)
449 for ne in args do
450 exprs.add expr(ne, null)
451 end
452
453 # Fill `res` with the result of the evaluation according to the mapping
454 for i in [0..msignature.arity[ do
455 var param = msignature.mparameters[i]
456 var j = map.map.get_or_null(i)
457 if j == null then
458 # default value
459 res.add(null_instance)
460 continue
461 end
462 if param.is_vararg and map.vararg_decl > 0 then
463 var vararg = exprs.sub(j, map.vararg_decl)
464 var elttype = param.mtype
465 var arg = self.vararg_instance(mpropdef, recv, vararg, elttype)
466 res.add(arg)
467 continue
468 end
469 res.add exprs[j]
470 end
471 return res
472 end
473
474 # Generate a static call on a method definition (no receiver needed).
475 fun static_call(mmethoddef: MMethodDef, arguments: Array[RuntimeVariable]): nullable RuntimeVariable do
476 var res: nullable RuntimeVariable
477 var ret = mmethoddef.msignature.as(not null).return_mtype
478 if ret == null then
479 res = null
480 else
481 ret = ret.resolve_for(mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.mmodule, true)
482 res = self.new_var(ret)
483 end
484
485 # Autobox arguments
486 adapt_signature(mmethoddef, arguments)
487
488 var rt_name = mmethoddef.rt_name
489 if res == null then
490 add("{rt_name}.get{rt_name}().exec(new RTVal[]\{{arguments.join(",")}\});")
491 return null
492 end
493 var ress = new_expr("{rt_name}.get{rt_name}().exec(new RTVal[]\{{arguments.join(",")}\});", compiler.mainmodule.object_type)
494 assign(res, ress)
495 return res
496 end
497
498 # Generate a polymorphic send for `method` with `arguments`
499 fun send(mmethod: MMethod, arguments: Array[RuntimeVariable]): nullable RuntimeVariable do
500 # Shortcut calls on primitives
501 if arguments.first.mcasttype.is_java_primitive then
502 return monomorphic_send(mmethod, arguments.first.mcasttype, arguments)
503 end
504 # Polymorphic send
505 return table_send(mmethod, arguments)
506 end
507
508
509 # Handle common special cases before doing the effective method invocation
510 # This methods handle the `==` and `!=` methods and the case of the null receiver.
511 # Note: a { is open in the generated C, that enclose and protect the effective method invocation.
512 # Client must not forget to close the } after them.
513 #
514 # The value returned is the result of the common special cases.
515 # If not null, client must compile it with the result of their own effective method invocation.
516 #
517 # If `before_send` can shortcut the whole message sending, a dummy `if(0){`
518 # is generated to cancel the effective method invocation that will follow
519 # TODO: find a better approach
520 private fun before_send(res: nullable RuntimeVariable, mmethod: MMethodDef, arguments: Array[RuntimeVariable]) do
521 var bool_type = compiler.mainmodule.bool_type
522 var recv = arguments.first
523 var consider_null = mmethod.name == "==" or mmethod.name == "!=" or mmethod.name == "is_same_instance"
524 if recv.mcasttype isa MNullableType or recv.mcasttype isa MNullType then
525 add("if ({recv} == null || {recv}.is_null()) \{")
526 if mmethod.name == "==" or mmethod.name == "is_same_instance" then
527 if res == null then res = new_var(bool_type)
528 var arg = arguments[1]
529 if arg.mcasttype isa MNullableType then
530 add("{res} = ({arg} == null || {arg}.is_null());")
531 else if arg.mcasttype isa MNullType then
532 add("{res} = true; /* is null */")
533 else
534 add("{res} = false; /* {arg.inspect} cannot be null */")
535 end
536 else if mmethod.name == "!=" then
537 if res == null then res = new_var(bool_type)
538 # res = self.new_var(bool_type)
539 var arg = arguments[1]
540 if arg.mcasttype isa MNullableType then
541 add("{res} = ({arg} != null && !{arg}.is_null());")
542 else if arg.mcasttype isa MNullType then
543 add("{res} = false; /* is null */")
544 else
545 add("{res} = true; /* {arg.inspect} cannot be null */")
546 end
547 else
548 add_abort("Receiver is null")
549 ret(null_instance)
550 end
551 add("\} else \{")
552 else
553 add "\{"
554 add "/* recv ({recv}) cannot be null since it's a {recv.mcasttype}"
555 end
556 if consider_null then
557 var arg = arguments[1]
558 if arg.mcasttype isa MNullType then
559 if res == null then res = new_var(bool_type)
560 if mmethod.name == "!=" then
561 add("{res} = true; /* arg is null and recv is not */")
562 else # `==` and `is_same_instance`
563 add("{res} = false; /* arg is null but recv is not */")
564 end
565 add("\}") # closes the null case
566 add("if (false) \{") # what follow is useless, Javac will drop it
567 end
568 end
569 end
570
571 # Perform a method call through vft
572 private fun table_send(mmethod: TableCallable, arguments: Array[RuntimeVariable]): nullable RuntimeVariable do
573 var mdef: MMethodDef
574 var name: String
575 if mmethod isa MMethod then
576 mdef = mmethod.intro
577 name = mmethod.full_name
578 else if mmethod isa MMethodDef then
579 mdef = mmethod
580 name = mmethod.full_name
581 else
582 abort
583 end
584
585 var recv = arguments.first
586 var rect = mdef.mclassdef.bound_mtype
587 var msignature = mdef.msignature.as(not null)
588 msignature = msignature.resolve_for(rect, rect, compiler.mainmodule, true)
589 adapt_signature(mdef, arguments)
590
591 var res: nullable RuntimeVariable
592 var ret = msignature.return_mtype
593 if ret == null then
594 res = null
595 else
596 res = self.new_var(ret)
597 end
598
599 before_send(res, mdef, arguments)
600
601 add "/* concrete call to {mdef} */"
602 if res != null then
603 var ress = new_expr("{recv}.rtclass.vft.get(\"{name}\").exec(new RTVal[]\{{arguments.join(",")}\});", compiler.mainmodule.object_type)
604 assign(res, ress)
605 else
606 add("{recv}.rtclass.vft.get(\"{name}\").exec(new RTVal[]\{{arguments.join(",")}\});")
607 end
608
609 add("\}") # closes the null case
610
611 return res
612 end
613
614 # Generate a super call from a method definition
615 fun supercall(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable do
616 return table_send(m, args)
617 end
618
619 # Generate a monomorphic send for the method `m`, the type `t` and the arguments `args`
620 fun monomorphic_send(m: MMethod, t: MType, args: Array[RuntimeVariable]): nullable RuntimeVariable do
621 assert t isa MClassType
622 var propdef = m.lookup_first_definition(self.compiler.mainmodule, t)
623 return self.static_call(propdef, args)
624 end
625
626 # Code generation
627
628 # Add a line (will be suffixed by `\n`)
629 fun add(line: String) do file.lines.add("{line}\n")
630
631 # Add a new partial line (no `\n` suffix)
632 fun addn(line: String) do file.lines.add(line)
633
634 # Compile a statement (if any)
635 fun stmt(nexpr: nullable AExpr) do
636 if nexpr == null then return
637 if nexpr.mtype == null and not nexpr.is_typed then
638 # Untyped expression.
639 # Might mean dead code or invalid code
640 # so aborts
641 add_abort("FATAL: bad statement executed.")
642 return
643 end
644
645 var old = self.current_node
646 current_node = nexpr
647 nexpr.stmt(self)
648 current_node = old
649 end
650
651 # Compile an expression an return its result
652 # `mtype` is the expected return type, pass null if no specific type is expected.
653 fun expr(nexpr: AExpr, mtype: nullable MType): RuntimeVariable do
654 var old = current_node
655 current_node = nexpr
656
657 var res = null
658 if nexpr.mtype != null then
659 res = nexpr.expr(self)
660 end
661
662 if res == null then
663 # Untyped expression.
664 # Might mean dead code or invalid code.
665 # so aborts
666 add_abort("FATAL: bad expression executed.")
667 # and return a placebo result to please the C compiler
668 if mtype == null then mtype = compiler.mainmodule.object_type
669 res = null_instance
670
671 self.current_node = old
672 return res
673 end
674
675 if mtype != null then
676 mtype = anchor(mtype)
677 res = autobox(res, mtype)
678 end
679
680 current_node = old
681 return res
682 end
683
684 # Alias for `self.expr(nexpr, self.bool_type)`
685 fun expr_bool(nexpr: AExpr): RuntimeVariable do
686 return expr(nexpr, compiler.mainmodule.bool_type)
687 end
688
689 # Correctly assign a left and a right value
690 # Boxing and unboxing is performed if required
691 fun assign(left, right: RuntimeVariable) do
692 add("{left} = {autobox(right, left.mtype)};")
693 end
694
695 # Generate a return with `value`
696 fun ret(value: RuntimeVariable) do
697 var frame = self.frame
698 assert frame != null
699 var returnvar = frame.returnvar
700 if returnvar != null then
701 assign(returnvar, value)
702 end
703 self.add("break {frame.returnlabel.as(not null)};")
704 end
705
706 # Return a new local RuntimeVariable initialized with the Java expression `jexpr`.
707 #
708 # `mtype` is used for the Java return variable initialization.
709 fun new_expr(jexpr: String, mtype: MType): RuntimeVariable do
710 var res = new_var(mtype)
711 add("{res} = {jexpr};")
712 return res
713 end
714
715 # Generate generic abort
716 #
717 # Used by aborts, asserts, casts, etc.
718 fun add_abort(message: String) do
719 add("System.err.print(\"Runtime error: {message}\");")
720 var node = current_node
721 if node != null then
722 add("System.err.print(\" ({node.location.short_location})\");")
723 end
724 add("System.err.println(\"\");")
725 add("System.exit(1);")
726 end
727
728 # Types handling
729
730 # Anchor a type to the main module and the current receiver
731 fun anchor(mtype: MType): MType do
732 if not mtype.need_anchor then return mtype
733 return mtype.anchor_to(compiler.mainmodule, frame.as(not null).receiver)
734 end
735
736 # Adapt the arguments of a method according to targetted `MMethodDef`
737 fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable]) do
738 var msignature = m.msignature.as(not null).resolve_for(
739 m.mclassdef.bound_mtype,
740 m.mclassdef.bound_mtype,
741 m.mclassdef.mmodule, true)
742 args.first = autobox(args.first, compiler.mainmodule.object_type)
743 for i in [0..msignature.arity[ do
744 args[i+1] = autobox(args[i + 1], compiler.mainmodule.object_type)
745 end
746 end
747
748 # Box primitive `value` to `mtype`.
749 private fun box(value: RuntimeVariable, mtype: MType): RuntimeVariable do
750 if value.is_boxed then return value
751 var obj_type = compiler.mainmodule.object_type
752 if value.mtype isa MNullType then
753 return new_expr("new RTVal(null, null)", compiler.mainmodule.model.null_type)
754 end
755 var mbox = value.mtype.as(MClassType).mclass
756 return new_expr("new RTVal({mbox.rt_name}.get{mbox.rt_name}(), {value})", obj_type)
757 end
758
759 # Unbox primitive `value` to `mtype`.
760 private fun unbox(value: RuntimeVariable, mtype: MType): RuntimeVariable do
761 if not value.is_boxed then return value
762 if not mtype.is_java_primitive then return value
763 if compiler.box_kinds.has(mtype) then
764 return new_expr("({mtype.java_type}){value}.value", mtype)
765 else
766 info "NOT YET IMPLEMENTED unbox for {value} ({mtype})"
767 abort
768 end
769 end
770
771 # Box or unbox primitive `value` to `mtype` if needed.
772 private fun autobox(value: RuntimeVariable, mtype: MType): RuntimeVariable do
773 if mtype.is_java_primitive then return unbox(value, mtype)
774 return box(value, mtype)
775 end
776
777 # Can this `value` be a primitive Java value?
778 private fun can_be_primitive(value: RuntimeVariable): Bool do
779 var t = value.mcasttype.undecorate
780 if not t isa MClassType then return false
781 var k = t.mclass.kind
782 return k == interface_kind or t.is_java_primitive
783 end
784
785 # Generate a polymorphic subtype test
786 fun type_test(value: RuntimeVariable, mtype: MType): RuntimeVariable do
787 add("/* {value.inspect} isa {mtype} */")
788 var res = self.new_var(compiler.mainmodule.bool_type)
789
790 # check color is in table
791 var maybenull = (value.mcasttype isa MNullableType or value.mcasttype isa MNullType)
792 if maybenull then
793 add("if({value} == null || {value}.is_null()) \{")
794 add("{res} = true && {mtype isa MNullableType};")
795 add("\} else \{")
796 end
797 if mtype isa MNullableType then mtype = mtype.mtype
798 var mclass = mtype.as(MClassType).mclass
799 add("{res} = {value}.rtclass.supers.get(\"{mclass.jname}\") == {mclass.rt_name}.get{mclass.rt_name}();")
800 if maybenull then
801 add("\}")
802 end
803 return res
804 end
805
806 # Generate the code required to dynamically check if 2 objects share the same runtime type
807 fun is_same_type_test(value1, value2: RuntimeVariable): RuntimeVariable do
808 var res = self.new_var(compiler.mainmodule.bool_type)
809 add("{res} = {value1}.rtclass == {value2}.rtclass;")
810 return res
811 end
812
813 # Native instances
814
815 # Generate an integer value
816 fun int_instance(value: Int): RuntimeVariable do
817 var t = compiler.mainmodule.int_type
818 return new RuntimeVariable(value.to_s, t, t)
819 end
820
821 # Generate a byte value
822 fun byte_instance(value: Byte): RuntimeVariable do
823 var t = compiler.mainmodule.byte_type
824 return new RuntimeVariable(value.to_s, t, t)
825 end
826
827 # Generate a char value
828 fun char_instance(value: Char): RuntimeVariable do
829 var t = compiler.mainmodule.char_type
830 return new RuntimeVariable("'{value.to_s.escape_to_c}'", t, t)
831 end
832
833 # Generate a float value
834 #
835 # FIXME pass a Float, not a string
836 fun float_instance(value: String): RuntimeVariable do
837 var t = compiler.mainmodule.float_type
838 return new RuntimeVariable(value.to_s, t, t)
839 end
840
841 # Generate an integer value
842 fun bool_instance(value: Bool): RuntimeVariable do
843 var t = compiler.mainmodule.bool_type
844 return new RuntimeVariable(value.to_s, t, t)
845 end
846
847 # Generate the `null` value
848 fun null_instance: RuntimeVariable do
849 var t = compiler.mainmodule.model.null_type
850 return new RuntimeVariable("null", t, t)
851 end
852
853 # Get an instance of a array for a vararg
854 fun vararg_instance(mpropdef: MPropDef, recv: RuntimeVariable, varargs: Array[RuntimeVariable], elttype: MType): RuntimeVariable do
855 # TODO handle dynamic types
856 info("NOT YET IMPLEMENTED vararg_instance")
857 return null_instance
858 # TODO return array_instance(varargs, elttype)
859 end
860
861 # Nit instances
862
863 # Generate a alloc-instance + init-attributes
864 fun init_instance(mtype: MClassType): RuntimeVariable do
865 var rt_name = mtype.mclass.rt_name
866 var res = new_expr("new RTVal({rt_name}.get{rt_name}())", mtype)
867 generate_init_attr(self, res, mtype)
868 return res
869 end
870
871 # Generate code that initialize the attributes on a new instance
872 fun generate_init_attr(v: JavaCompilerVisitor, recv: RuntimeVariable, mtype: MClassType) do
873 var cds = mtype.collect_mclassdefs(v.compiler.mainmodule).to_a
874 v.compiler.mainmodule.linearize_mclassdefs(cds)
875 for cd in cds do
876 for npropdef in v.compiler.modelbuilder.collect_attr_propdef(cd) do
877 npropdef.init_expr(v, recv)
878 end
879 end
880 end
881
882 # Generate a Nit "is" for two runtime_variables
883 fun equal_test(value1, value2: RuntimeVariable): RuntimeVariable do
884 var res = new_var(compiler.mainmodule.bool_type)
885 if value2.mtype.is_java_primitive and not value1.mtype.is_java_primitive then
886 var tmp = value1
887 value1 = value2
888 value2 = tmp
889 end
890 if value1.mtype.is_java_primitive then
891 if value2.mtype == value1.mtype then
892 add("{res} = {value1} == {value2}; /* == with two primitives */")
893 else if value2.mtype.is_java_primitive then
894 add("{res} = true; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
895 # else if value1.mtype.is_tagged then
896 # add("{res} = ({value2} != NULL) && ({autobox(value2, value1.mtype)} == {value1});")
897 else
898 var rt_name = value1.mtype.as(MClassType).mclass.rt_name
899 add("{res} = ({value2} != null) && ({value2}.rtclass == {rt_name}.get{rt_name}());")
900 add("if ({res}) \{")
901 add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
902 add("\}")
903 end
904 return res
905 end
906 var maybe_null = true
907 var test = new Array[String]
908 var t1 = value1.mcasttype
909 if t1 isa MNullableType then
910 test.add("{value1} != null && !{value1}.is_null()")
911 t1 = t1.mtype
912 else
913 maybe_null = false
914 end
915 var t2 = value2.mcasttype
916 if t2 isa MNullableType then
917 test.add("{value2} != null && !{value2}.is_null()")
918 t2 = t2.mtype
919 else
920 maybe_null = false
921 end
922
923 var incompatible = false
924 var primitive
925 if t1.is_java_primitive then
926 primitive = t1
927 if t1 == t2 then
928 # No need to compare class
929 else if t2.is_java_primitive then
930 incompatible = true
931 else if can_be_primitive(value2) then
932 if t1.is_java_primitive then
933 self.add("{res} = {value1} == {value2}; /* t1 is primitive and t2 can be */")
934 return res
935 end
936 # if not compiler.modelbuilder.toolcontext.opt_no_tag_primitives.value then
937 # test.add("(!{extract_tag(value2)})")
938 # end
939 test.add("{value1}.rtclass == {value2}.rtclass")
940 else
941 incompatible = true
942 end
943 else if t2.is_java_primitive then
944 primitive = t2
945 if can_be_primitive(value1) then
946 if t2.is_java_primitive then
947 self.add("{res} = {value1} == {value2}; /* t2 is primitive and t1 can be */")
948 return res
949 end
950 test.add("{value1}.rtclass == {value2}.rtclass")
951 else
952 incompatible = true
953 end
954 else
955 primitive = null
956 end
957
958 if incompatible then
959 if maybe_null then
960 self.add("{res} = {value1} == {value2}; /* incompatible types {t1} vs. {t2}; but may be NULL*/")
961 return res
962 else
963 self.add("{res} = false; /* incompatible types {t1} vs. {t2}; cannot be NULL */")
964 return res
965 end
966 end
967 if primitive != null then
968 if primitive.is_java_primitive then
969 self.add("{res} = {value1} == {value2};")
970 return res
971 end
972 test.add("({value1}.value == {value2}.value")
973 else if can_be_primitive(value1) and can_be_primitive(value2) then
974 test.add("{value1}.rtclass == {value2}.rtclass")
975 var s = new Array[String]
976 for b in compiler.box_kinds do
977 var rt_name = b.mclass.rt_name
978 s.add "({value1}.rtclass == {rt_name}.get{rt_name}()) && ({value1}.value.equals({value2}.value))"
979 if b.mclass.name == "Float" then
980 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)"
981 end
982 end
983 if s.is_empty then
984 self.add("{res} = {value1} == {value2}; /* both can be primitive */")
985 return res
986 end
987 test.add("({s.join(" || ")})")
988 else
989 self.add("{res} = {value1} == {value2}; /* no primitives */")
990 return res
991 end
992 self.add("{res} = {value1} == {value2} || ({test.join(" && ")});")
993 return res
994 end
995
996 # Attributes
997
998 # Generate a polymorphic attribute is_set test
999 fun isset_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable do
1000 # TODO self.check_recv_notnull(recv)
1001 var res = new_var(compiler.mainmodule.bool_type)
1002
1003 # What is the declared type of the attribute?
1004 var mtype = a.intro.static_mtype.as(not null)
1005 var intromclassdef = a.intro.mclassdef
1006 mtype = mtype.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
1007
1008 if mtype isa MNullableType then
1009 add("{res} = true; /* easy isset: {a} on {recv.inspect} */")
1010 return res
1011 end
1012 add("{res} = {recv}.attrs.get(\"{a.jname}\") != null; /* {a} on {recv.inspect} */")
1013 return res
1014 end
1015
1016 # Generate a polymorphic attribute read
1017 fun read_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable do
1018 # TODO check_recv_notnull(recv)
1019 # TODO compile_check(v)
1020 # What is the declared type of the attribute?
1021 var ret = a.intro.static_mtype.as(not null)
1022 var intromclassdef = a.intro.mclassdef
1023 ret = ret.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
1024
1025 # Check for Uninitialized attribute
1026 if not ret isa MNullableType then check_attribute(a, recv)
1027
1028 return new_expr("{recv}.attrs.get(\"{a.jname}\")", ret)
1029 end
1030
1031 # Generate a polymorphic attribute write
1032 fun write_attribute(a: MAttribute, recv: RuntimeVariable, value: RuntimeVariable) do
1033 # TODO check_recv_notnull(recv)
1034 add "{recv}.attrs.put(\"{a.jname}\", {autobox(value, compiler.mainmodule.object_type)});"
1035 end
1036
1037 # Check uninitialized attribute
1038 fun check_attribute(a: MAttribute, recv: RuntimeVariable) do
1039 add "if({recv}.attrs.get(\"{a.jname}\") == null) \{"
1040 add_abort "Uninitialized attribute {a.name}"
1041 add "\}"
1042 end
1043
1044 # Utils
1045
1046 # Display a info message
1047 fun info(str: String) do compiler.modelbuilder.toolcontext.info(str, 0)
1048 end
1049
1050 # A file containing Java code.
1051 class JavaCodeFile
1052
1053 # File name
1054 var filename: String
1055
1056 # Lines to write
1057 var lines: List[String] = new List[String]
1058 end
1059
1060 redef class MEntity
1061 # A Java compatible name for `self`
1062 private fun jname: String do return name.to_cmangle
1063 end
1064
1065 # Handler for runtime classes generation
1066 #
1067 # We need 3 kinds of runtime structures:
1068 # * `RTClass` to represent a global class
1069 # * `RTMethod` to represent a method definition
1070 # * `RTVal` to represent runtime variables
1071 class JavaRuntimeModel
1072
1073 # Compile JavaRuntimeModel structures
1074 fun compile_rtmodel(compiler: JavaCompiler) do
1075 compile_rtclass(compiler)
1076 compile_rtmethod(compiler)
1077 compile_rtval(compiler)
1078 end
1079
1080 # Compile the abstract runtime class structure
1081 #
1082 # Runtime classes have 3 attributes:
1083 # * `class_name`: the class name as a String
1084 # * `vft`: the virtual function table for the class (flattened)
1085 # * `supers`: the super type table (used for type tests)
1086 fun compile_rtclass(compiler: JavaCompiler) do
1087 var v = compiler.new_visitor("RTClass.java")
1088 v.add("import java.util.HashMap;")
1089 v.add("public abstract class RTClass \{")
1090 v.add(" public String class_name;")
1091 v.add(" public HashMap<String, RTMethod> vft = new HashMap<>();")
1092 v.add(" public HashMap<String, RTClass> supers = new HashMap<>();")
1093 v.add(" protected RTClass() \{\}")
1094 v.add("\}")
1095 end
1096
1097 # Compile the abstract runtime method structure
1098 #
1099 # Method body is executed through the `exec` method:
1100 # * `exec` always take an array of RTVal as arg, the first one must be the receiver
1101 # * `exec` always returns a RTVal (or null if the Nit return type is void)
1102 fun compile_rtmethod(compiler: JavaCompiler) do
1103 var v = compiler.new_visitor("RTMethod.java")
1104 v.add("public abstract class RTMethod \{")
1105 v.add(" protected RTMethod() \{\}")
1106 v.add(" public abstract RTVal exec(RTVal[] args);")
1107 v.add("\}")
1108 end
1109
1110 # Compile the runtime value structure
1111 #
1112 # RTVal both represents object instances and primitives values:
1113 # * object instances:
1114 # * `rtclass` the class of the RTVal is instance of
1115 # * `attrs` contains the attributes of the instance
1116 # * primitive values:
1117 # * `rtclass` represents the class of the primitive value Nit type
1118 # * `value` contains the primitive value of the instance
1119 # * null values:
1120 # * they must have both `rtclass` and `value` as null
1121 fun compile_rtval(compiler: JavaCompiler) do
1122 var v = compiler.new_visitor("RTVal.java")
1123 v.add("import java.util.HashMap;")
1124 v.add("public class RTVal \{")
1125 v.add(" public RTClass rtclass;")
1126 v.add(" public HashMap<String, RTVal> attrs = new HashMap<>();")
1127 v.add(" Object value;")
1128 v.add(" public RTVal(RTClass rtclass) \{")
1129 v.add(" this.rtclass = rtclass;")
1130 v.add(" \}")
1131 v.add(" public RTVal(RTClass rtclass, Object value) \{")
1132 v.add(" this.rtclass = rtclass;")
1133 v.add(" this.value = value;")
1134 v.add(" \}")
1135 v.add(" public boolean is_null() \{ return rtclass == null && value == null; \}")
1136 v.add("\}")
1137 end
1138 end
1139
1140 # A runtime variable hold a runtime value in Java.
1141 # Runtime variables are associated to Nit local variables and intermediate results in Nit expressions.
1142 class RuntimeVariable
1143
1144 # The name of the variable in the Java code
1145 var name: String
1146
1147 # The static type of the variable (as declard in Java)
1148 var mtype: MType
1149
1150 # The current casted type of the variable (as known in Nit)
1151 var mcasttype: MType is writable
1152
1153 # If the variable exaclty a mcasttype?
1154 # false (usual value) means that the variable is a mcasttype or a subtype.
1155 var is_exact: Bool = false is writable
1156
1157 # Is this variable declared as a RTVal or a Java primitive one?
1158 var is_boxed = false
1159
1160 redef fun to_s do return name
1161
1162 redef fun inspect
1163 do
1164 var exact_str
1165 if self.is_exact then
1166 exact_str = " exact"
1167 else
1168 exact_str = ""
1169 end
1170 var type_str
1171 if self.mtype == self.mcasttype then
1172 type_str = "{mtype}{exact_str}"
1173 else
1174 type_str = "{mtype}({mcasttype}{exact_str})"
1175 end
1176 return "<{name}:{type_str}>"
1177 end
1178 end
1179
1180 # The static context of a visited property in a `JavaCompilerVisitor`
1181 class JavaStaticFrame
1182 # The associated visitor
1183 var visitor: JavaCompilerVisitor
1184
1185 # The executed property.
1186 # A Method in case of a call, an attribute in case of a default initialization.
1187 var mpropdef: MPropDef
1188
1189 # The static type of the receiver
1190 var receiver: MClassType
1191
1192 # Arguments of the method (the first is the receiver)
1193 var arguments: Array[RuntimeVariable]
1194
1195 # The runtime_variable associated to the return (in a function)
1196 var returnvar: nullable RuntimeVariable = null is writable
1197
1198 # The label at the end of the property
1199 var returnlabel: nullable String = null is writable
1200
1201 # Labels associated to a each escapemarks.
1202 # Because of inlinings, escape-marks must be associated to their context (the frame)
1203 private var escapemark_names = new HashMap[EscapeMark, String]
1204 end
1205
1206 redef class Location
1207 # Return a shortened version of the location with `"{file}:{line_start}"`
1208 fun short_location: String do
1209 var file = self.file
1210 if file == null then return "<no file>:{line_start}"
1211 return "{file.filename.escape_to_c}:{line_start}"
1212 end
1213 end
1214
1215 redef class MType
1216 # Return the Java type associated to a given Nit static type
1217 fun java_type: String do return "RTVal"
1218
1219 # Is the associated Java type a primitive one?
1220 #
1221 # ENSURE `result == (java_type != "Object")`
1222 var is_java_primitive: Bool is lazy do return java_type != "RTVal"
1223 end
1224
1225 redef class MClassType
1226
1227 redef var java_type is lazy do
1228 if mclass.name == "Int" then
1229 return "int"
1230 else if mclass.name == "Bool" then
1231 return "boolean"
1232 else if mclass.name == "Char" then
1233 return "char"
1234 else if mclass.name == "Float" then
1235 return "double"
1236 else if mclass.name == "Byte" then
1237 return "byte"
1238 else if mclass.name == "NativeString" then
1239 return "String"
1240 else if mclass.name == "NativeArray" then
1241 return "Array"
1242 end
1243 return "RTVal"
1244 end
1245 end
1246
1247 redef class MClass
1248
1249 # Runtime name
1250 private fun rt_name: String do return "RTClass_{intro.mmodule.jname}_{jname}"
1251
1252 # Generate a Java RTClass for a Nit MClass
1253 fun compile_to_java(v: JavaCompilerVisitor) do
1254 v.add("public class {rt_name} extends RTClass \{")
1255 v.add(" protected static RTClass instance;")
1256 v.add(" private {rt_name}() \{")
1257 v.add(" this.class_name = \"{name}\";")
1258 compile_vft(v)
1259 compile_type_table(v)
1260 v.add(" \}")
1261 v.add(" public static RTClass get{rt_name}() \{")
1262 v.add(" if(instance == null) \{")
1263 v.add(" instance = new {rt_name}();")
1264 v.add(" \}")
1265 v.add(" return instance;")
1266 v.add(" \}")
1267 v.add("\}")
1268 end
1269
1270 # Compile the virtual function table for the mclass
1271 private fun compile_vft(v: JavaCompilerVisitor) do
1272 # TODO handle generics
1273 if mclass_type.need_anchor then return
1274 var mclassdefs = mclass_type.collect_mclassdefs(v.compiler.mainmodule).to_a
1275 v.compiler.mainmodule.linearize_mclassdefs(mclassdefs)
1276
1277 var mainmodule = v.compiler.mainmodule
1278 for mclassdef in mclassdefs.reversed do
1279 for mprop in mclassdef.intro_mproperties do
1280 var mpropdef = mprop.lookup_first_definition(mainmodule, intro.bound_mtype)
1281 if not mpropdef isa MMethodDef then continue
1282 var rt_name = mpropdef.rt_name
1283 v.add("this.vft.put(\"{mprop.full_name}\", {rt_name}.get{rt_name}());")
1284
1285 # fill super next definitions
1286 while mpropdef.has_supercall do
1287 var prefix = mpropdef.full_name
1288 mpropdef = mpropdef.lookup_next_definition(mainmodule, intro.bound_mtype)
1289 rt_name = mpropdef.rt_name
1290 v.add("this.vft.put(\"{prefix}\", {rt_name}.get{rt_name}());")
1291 end
1292 end
1293 end
1294 end
1295
1296 # Compile the type table for the MClass
1297 fun compile_type_table(v: JavaCompilerVisitor) do
1298 for pclass in in_hierarchy(v.compiler.mainmodule).greaters do
1299 if pclass == self then
1300 v.add("supers.put(\"{pclass.jname}\", this);")
1301 else
1302 v.add("supers.put(\"{pclass.jname}\", {pclass.rt_name}.get{pclass.rt_name}());")
1303 end
1304 end
1305 end
1306 end
1307
1308 # Used as a common type between MMethod and MMethodDef for `table_send`
1309 private interface TableCallable
1310 end
1311
1312 redef class MMethod
1313 super TableCallable
1314 end
1315
1316 redef class MMethodDef
1317 super TableCallable
1318
1319 # Runtime name
1320 private fun rt_name: String do
1321 return "RTMethod_{mclassdef.mmodule.jname}_{mclassdef.mclass.jname}_{mproperty.jname}"
1322 end
1323
1324 # Generate a Java RTMethod for `self`
1325 fun compile_to_java(v: JavaCompilerVisitor) do
1326 v.add("public class {rt_name} extends RTMethod \{")
1327 v.add(" protected static RTMethod instance;")
1328 v.add(" public static RTMethod get{rt_name}() \{")
1329 v.add(" if(instance == null) \{")
1330 v.add(" instance = new {rt_name}();")
1331 v.add(" \}")
1332 v.add(" return instance;")
1333 v.add(" \}")
1334 v.add(" @Override")
1335 v.add(" public RTVal exec(RTVal[] args) \{")
1336 compile_inside_to_java(v)
1337 v.add(" \}")
1338 v.add("\}")
1339 end
1340
1341 # Compile the body of this function
1342 fun compile_inside_to_java(v: JavaCompilerVisitor) do
1343
1344 var modelbuilder = v.compiler.modelbuilder
1345 var node = modelbuilder.mpropdef2node(self)
1346
1347 var recv = mclassdef.bound_mtype
1348 var arguments = new Array[RuntimeVariable]
1349 var frame = new JavaStaticFrame(v, self, recv, arguments)
1350 v.frame = frame
1351
1352 var selfvar = v.decl_var("self", recv)
1353 arguments.add(selfvar)
1354 var boxed = v.new_expr("args[0]", v.compiler.mainmodule.object_type)
1355 v.add "{selfvar} = {v.autobox(boxed, recv)};"
1356
1357 var msignature = self.msignature
1358 var ret = null
1359 if msignature != null then
1360 ret = msignature.return_mtype
1361 if ret != null then
1362 var retvar = v.decl_var("ret", ret)
1363 if ret.name == "Int" then v.add "{retvar} = 0;"
1364 if ret.name == "Float" then v.add "{retvar} = 0.0;"
1365 if ret.name == "Bool" then v.add "{retvar} = false;"
1366 if ret.name == "Char" then v.add "{retvar} = 0;"
1367 if ret.name == "Byte" then v.add "{retvar} = 0;"
1368 frame.returnvar = retvar
1369 end
1370 end
1371 frame.returnlabel = v.get_name("RET_LABEL")
1372
1373 v.current_node = node
1374 if is_abstract then
1375 v.add_abort("Abstract method `{mproperty.name}` called on `\" + {selfvar}.rtclass.class_name +\"`")
1376 v.add("return null;")
1377 return
1378 end
1379 v.current_node = null
1380
1381 v.add("{frame.returnlabel.as(not null)}: \{")
1382
1383 if node isa APropdef then
1384 node.compile_to_java(v, self, arguments)
1385 else if node isa AClassdef then
1386 node.compile_to_java(v, self, arguments)
1387 else
1388 abort
1389 end
1390
1391 v.add("\}")
1392 if ret != null then
1393 v.add("return {v.autobox(frame.returnvar.as(not null), v.compiler.mainmodule.object_type)};")
1394 else
1395 v.add("return null;")
1396 end
1397 end
1398 end
1399
1400 redef class AClassdef
1401 private fun compile_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable]) do
1402 if mpropdef == self.mfree_init then
1403 assert mpropdef.mproperty.is_root_init
1404 if not mpropdef.is_intro then
1405 v.supercall(mpropdef, arguments.first.mtype.as(MClassType), arguments)
1406 end
1407 else
1408 abort
1409 end
1410 end
1411 end
1412
1413 redef class APropdef
1414
1415 # Compile that property definition to java code
1416 fun compile_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable]) do
1417 v.info("NOT YET IMPLEMENTED {class_name}::compile_to_java")
1418 end
1419 end
1420
1421 redef class AMethPropdef
1422 redef fun compile_to_java(v, mpropdef, arguments) do
1423 if mpropdef.msignature != null then
1424 var i = 0
1425 for mparam in mpropdef.msignature.as(not null).mparameters do
1426 var variable = n_signature.as(not null).n_params[i].variable
1427 if variable == null then continue
1428 var argvar = v.variable(variable)
1429 v.assign(argvar, v.new_expr("args[{i + 1}]", v.compiler.mainmodule.object_type))
1430 arguments.add(argvar)
1431 i += 1
1432 end
1433 end
1434
1435 # Call the implicit super-init
1436 var auto_super_inits = self.auto_super_inits
1437 if auto_super_inits != null then
1438 var args = [arguments.first]
1439 for auto_super_init in auto_super_inits do
1440 assert auto_super_init.mproperty != mpropdef.mproperty
1441 args.clear
1442 for i in [0..auto_super_init.msignature.arity+1[ do
1443 args.add(arguments[i])
1444 end
1445 assert auto_super_init.mproperty != mpropdef.mproperty
1446 v.compile_callsite(auto_super_init, args)
1447 end
1448 end
1449 if auto_super_call then
1450 v.supercall(mpropdef, arguments.first.mtype.as(MClassType), arguments)
1451 end
1452
1453 compile_inside_to_java(v, mpropdef, arguments)
1454 end
1455
1456 # Compile the inside of the method body
1457 private fun compile_inside_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable]) do
1458 # Compile intern methods
1459 if mpropdef.is_intern then
1460 if compile_intern_to_java(v, mpropdef, arguments) then return
1461 v.info("NOT YET IMPLEMENTED compile_intern for {mpropdef}")
1462 v.ret(v.null_instance)
1463 return
1464 end
1465
1466 # Compile block if any
1467 var n_block = n_block
1468 if n_block != null then
1469 v.stmt(n_block)
1470 return
1471 end
1472 end
1473
1474 # Compile an intern method using Java primitives
1475 fun compile_intern_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable]): Bool do
1476 var pname = mpropdef.mproperty.name
1477 var cname = mpropdef.mclassdef.mclass.name
1478 var ret = mpropdef.msignature.as(not null).return_mtype
1479 if cname == "Int" then
1480 if pname == "output" then
1481 v.add("System.out.println({arguments[0]});")
1482 v.ret(v.null_instance)
1483 return true
1484 else if pname == "object_id" then
1485 v.ret(arguments.first)
1486 return true
1487 else if pname == "+" then
1488 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1489 return true
1490 else if pname == "-" then
1491 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1492 return true
1493 else if pname == "unary -" then
1494 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1495 return true
1496 else if pname == "unary +" then
1497 v.ret(arguments[0])
1498 return true
1499 else if pname == "*" then
1500 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1501 return true
1502 else if pname == "/" then
1503 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
1504 return true
1505 else if pname == "%" then
1506 v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null)))
1507 return true
1508 else if pname == "lshift" then
1509 v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
1510 return true
1511 else if pname == "rshift" 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.equal_test(arguments[0], arguments[1]))
1516 return true
1517 else if pname == "!=" then
1518 var res = v.equal_test(arguments[0], arguments[1])
1519 v.ret(v.new_expr("!{res}", ret.as(not null)))
1520 return true
1521 else if pname == "<" then
1522 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1523 return true
1524 else if pname == ">" then
1525 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1526 return true
1527 else if pname == "<=" then
1528 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1529 return true
1530 else if pname == ">=" then
1531 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1532 return true
1533 else if pname == "to_f" then
1534 v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
1535 return true
1536 else if pname == "to_b" then
1537 v.ret(v.new_expr("(byte){arguments[0]}", ret.as(not null)))
1538 return true
1539 else if pname == "ascii" then
1540 v.ret(v.new_expr("(char){arguments[0]}", ret.as(not null)))
1541 return true
1542 end
1543 else if cname == "Char" then
1544 if pname == "output" then
1545 v.add("System.out.print({arguments[0]});")
1546 v.ret(v.null_instance)
1547 return true
1548 else if pname == "object_id" then
1549 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1550 return true
1551 else if pname == "successor" then
1552 v.ret(v.new_expr("(char)({arguments[0]} + {arguments[1]})", ret.as(not null)))
1553 return true
1554 else if pname == "predecessor" then
1555 v.ret(v.new_expr("(char)({arguments[0]} - {arguments[1]})", ret.as(not null)))
1556 return true
1557 else if pname == "==" then
1558 v.ret(v.equal_test(arguments[0], arguments[1]))
1559 return true
1560 else if pname == "!=" then
1561 var res = v.equal_test(arguments[0], arguments[1])
1562 v.ret(v.new_expr("!{res}", ret.as(not null)))
1563 return true
1564 else if pname == "<" then
1565 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1566 return true
1567 else if pname == ">" then
1568 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1569 return true
1570 else if pname == "<=" then
1571 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1572 return true
1573 else if pname == ">=" then
1574 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1575 return true
1576 else if pname == "to_i" then
1577 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1578 return true
1579 else if pname == "ascii" then
1580 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1581 return true
1582 end
1583 else if cname == "Byte" then
1584 if pname == "output" then
1585 v.add("System.out.println({arguments[0]});")
1586 v.ret(v.null_instance)
1587 return true
1588 else if pname == "object_id" then
1589 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1590 return true
1591 else if pname == "+" then
1592 v.ret(v.new_expr("(byte)({arguments[0]} + {arguments[1]})", ret.as(not null)))
1593 return true
1594 else if pname == "-" then
1595 v.ret(v.new_expr("(byte)({arguments[0]} - {arguments[1]})", ret.as(not null)))
1596 return true
1597 else if pname == "unary -" then
1598 v.ret(v.new_expr("(byte)(-{arguments[0]})", ret.as(not null)))
1599 return true
1600 else if pname == "unary +" then
1601 v.ret(arguments[0])
1602 return true
1603 else if pname == "*" then
1604 v.ret(v.new_expr("(byte)({arguments[0]} * {arguments[1]})", ret.as(not null)))
1605 return true
1606 else if pname == "/" then
1607 v.ret(v.new_expr("(byte)({arguments[0]} / {arguments[1]})", ret.as(not null)))
1608 return true
1609 else if pname == "%" then
1610 v.ret(v.new_expr("(byte)({arguments[0]} % {arguments[1]})", ret.as(not null)))
1611 return true
1612 else if pname == "lshift" then
1613 v.ret(v.new_expr("(byte)({arguments[0]} << {arguments[1]})", ret.as(not null)))
1614 return true
1615 else if pname == "rshift" then
1616 v.ret(v.new_expr("(byte)({arguments[0]} >> {arguments[1]})", ret.as(not null)))
1617 return true
1618 else if pname == "==" then
1619 v.ret(v.equal_test(arguments[0], arguments[1]))
1620 return true
1621 else if pname == "!=" then
1622 var res = v.equal_test(arguments[0], arguments[1])
1623 v.ret(v.new_expr("!{res}", ret.as(not null)))
1624 return true
1625 else if pname == "<" then
1626 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1627 return true
1628 else if pname == ">" then
1629 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1630 return true
1631 else if pname == "<=" then
1632 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1633 return true
1634 else if pname == ">=" then
1635 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1636 return true
1637 else if pname == "to_i" then
1638 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1639 return true
1640 else if pname == "to_f" then
1641 v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
1642 return true
1643 else if pname == "ascii" then
1644 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
1645 return true
1646 end
1647 else if cname == "Bool" then
1648 if pname == "output" then
1649 v.add("System.out.println({arguments[0]});")
1650 v.ret(v.null_instance)
1651 return true
1652 else if pname == "object_id" then
1653 v.ret(v.new_expr("{arguments[0]}?1:0", ret.as(not null)))
1654 return true
1655 else if pname == "==" then
1656 v.ret(v.equal_test(arguments[0], arguments[1]))
1657 return true
1658 else if pname == "!=" then
1659 var res = v.equal_test(arguments[0], arguments[1])
1660 v.ret(v.new_expr("!{res}", ret.as(not null)))
1661 return true
1662 end
1663 else if cname == "Float" then
1664 if pname == "output" then
1665 v.add "if({arguments[0]} == Double.POSITIVE_INFINITY) \{"
1666 v.add "System.out.println(\"inf\");"
1667 v.add "\} else if({arguments[0]} == Double.POSITIVE_INFINITY) \{"
1668 v.add "System.out.println(\"-inf\");"
1669 v.add "\} else \{"
1670 var df = v.get_name("df")
1671 v.add "java.text.DecimalFormat {df} = new java.text.DecimalFormat(\"0.000000\");"
1672 v.add "System.out.println({df}.format({arguments[0]}));"
1673 v.add "\}"
1674 v.ret(v.null_instance)
1675 return true
1676 else if pname == "object_id" then
1677 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1678 return true
1679 else if pname == "+" then
1680 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1681 return true
1682 else if pname == "-" then
1683 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1684 return true
1685 else if pname == "unary -" then
1686 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1687 return true
1688 else if pname == "unary +" then
1689 v.ret(arguments[0])
1690 return true
1691 else if pname == "succ" then
1692 v.ret(v.new_expr("{arguments[0]} + 1", ret.as(not null)))
1693 return true
1694 else if pname == "prec" then
1695 v.ret(v.new_expr("{arguments[0]} - 1", ret.as(not null)))
1696 return true
1697 else if pname == "*" then
1698 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1699 return true
1700 else if pname == "/" then
1701 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
1702 return true
1703 else if pname == "==" then
1704 v.ret(v.equal_test(arguments[0], arguments[1]))
1705 return true
1706 else if pname == "!=" then
1707 var res = v.equal_test(arguments[0], arguments[1])
1708 v.ret(v.new_expr("!{res}", ret.as(not null)))
1709 return true
1710 else if pname == "<" then
1711 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1712 return true
1713 else if pname == ">" then
1714 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1715 return true
1716 else if pname == "<=" then
1717 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1718 return true
1719 else if pname == ">=" then
1720 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1721 return true
1722 else if pname == "to_i" then
1723 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1724 return true
1725 else if pname == "to_b" then
1726 v.ret(v.new_expr("(byte){arguments[0]}", ret.as(not null)))
1727 return true
1728 end
1729 end
1730 if pname == "exit" then
1731 v.add("System.exit({arguments[1]});")
1732 v.ret(v.null_instance)
1733 return true
1734 else if pname == "sys" then
1735 # TODO singleton
1736 var main_type = v.compiler.mainmodule.sys_type.as(not null)
1737 var sys = main_type.mclass
1738 v.ret(v.new_expr("new RTVal({sys.rt_name}.get{sys.rt_name}())", main_type))
1739 return true
1740 else if pname == "object_id" then
1741 v.ret(v.new_expr("{arguments[0]}.hashCode()", ret.as(not null)))
1742 return true
1743 else if pname == "is_same_type" then
1744 v.ret(v.is_same_type_test(arguments[0], arguments[1]))
1745 return true
1746 else if pname == "is_same_instance" then
1747 v.ret(v.equal_test(arguments[0], arguments[1]))
1748 return true
1749 else if pname == "output_class_name" then
1750 v.add("System.out.println({arguments[0]}.rtclass.class_name);")
1751 v.ret(v.null_instance)
1752 return true
1753 end
1754 return false
1755 end
1756 end
1757
1758 redef class AAttrPropdef
1759 redef fun compile_to_java(v, mpropdef, arguments) do
1760 v.current_node = self
1761 if mpropdef == mreadpropdef then
1762 compile_getter(v, mpropdef, arguments)
1763 else if mpropdef == mwritepropdef then
1764 compile_setter(v, mpropdef, arguments)
1765 else
1766 abort
1767 end
1768 v.current_node = null
1769 end
1770
1771 # Compile the setter method
1772 private fun compile_setter(v: JavaCompilerVisitor, mpropdef: MPropDef, arguments: Array[RuntimeVariable]) do
1773 var mtype = v.compiler.mainmodule.object_type
1774 var recv = arguments.first
1775 var val = v.new_expr("args[1]", mtype)
1776 v.write_attribute(self.mpropdef.as(not null).mproperty, recv, val)
1777 v.ret v.null_instance
1778 end
1779
1780 # Compile the getter method
1781 private fun compile_getter(v: JavaCompilerVisitor, mpropdef: MPropDef, arguments: Array[RuntimeVariable]) do
1782 var recv = arguments.first
1783 v.ret v.read_attribute(self.mpropdef.as(not null).mproperty, recv)
1784 end
1785
1786 private fun init_expr(v: JavaCompilerVisitor, recv: RuntimeVariable) do
1787 if has_value and not is_lazy and not n_expr isa ANullExpr then evaluate_expr(v, recv)
1788 end
1789
1790 # Evaluate, store and return the default value of the attribute
1791 private fun evaluate_expr(v: JavaCompilerVisitor, recv: RuntimeVariable): RuntimeVariable do
1792 var old = v.frame
1793 var frame = new JavaStaticFrame(v, self.mreadpropdef.as(not null), recv.mcasttype.undecorate.as(MClassType), [recv])
1794 v.frame = frame
1795
1796 var value
1797 var mtype = self.mtype
1798 assert mtype != null
1799
1800 var nexpr = self.n_expr
1801 var nblock = self.n_block
1802 if nexpr != null then
1803 value = v.expr(nexpr, mtype)
1804 else if nblock != null then
1805 value = v.new_var(mtype)
1806 frame.returnvar = value
1807 frame.returnlabel = v.get_name("RET_LABEL")
1808 v.add("{frame.returnlabel.as(not null)}: \{")
1809 v.stmt(nblock)
1810 v.add("\}")
1811 else
1812 abort
1813 end
1814
1815 v.write_attribute(self.mpropdef.as(not null).mproperty, recv, value)
1816 v.frame = old
1817 return value
1818 end
1819 end
1820
1821 redef class AExpr
1822 # Try to compile self as an expression
1823 # Do not call this method directly, use `v.expr` instead
1824 private fun expr(v: JavaCompilerVisitor): nullable RuntimeVariable do
1825 v.info("NOT YET IMPLEMENTED {class_name}::expr")
1826 return null
1827 end
1828
1829 # Try to compile self as a statement
1830 # Do not call this method directly, use `v.stmt` instead
1831 private fun stmt(v: JavaCompilerVisitor) do expr(v)
1832 end
1833
1834 redef class ABlockExpr
1835 redef fun stmt(v)
1836 do
1837 for e in self.n_expr do v.stmt(e)
1838 end
1839 redef fun expr(v)
1840 do
1841 var last = self.n_expr.last
1842 for e in self.n_expr do
1843 if e == last then break
1844 v.stmt(e)
1845 end
1846 return v.expr(last, null)
1847 end
1848 end
1849
1850 redef class ASendExpr
1851 redef fun expr(v) do
1852 var recv = v.expr(n_expr, null)
1853 var callsite = callsite.as(not null)
1854 var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, raw_arguments)
1855 return v.compile_callsite(callsite, args)
1856 end
1857 end
1858
1859 redef class ANewExpr
1860 redef fun expr(v)
1861 do
1862 var mtype = self.recvtype
1863 assert mtype != null
1864
1865 if mtype.mclass.name == "NativeArray" then
1866 # TODO handle native arrays
1867 v.info("NOT YET IMPLEMENTED new NativeArray")
1868 end
1869
1870 var recv = v.init_instance(mtype)
1871
1872 var callsite = self.callsite
1873 if callsite == null then return recv
1874
1875 var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs)
1876 var res2 = v.compile_callsite(callsite, args)
1877 if res2 != null then
1878 return res2
1879 end
1880 return recv
1881 end
1882 end
1883
1884 redef class ASuperExpr
1885 redef fun expr(v)
1886 do
1887 var frame = v.frame
1888 assert frame != null
1889 var recv = frame.arguments.first
1890
1891 var callsite = self.callsite
1892 if callsite != null then
1893 var args
1894
1895 if self.n_args.n_exprs.is_empty then
1896 # Add automatic arguments for the super init call
1897 args = [recv]
1898 for i in [0..callsite.msignature.arity[ do
1899 args.add(frame.arguments[i+1])
1900 end
1901 else
1902 args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs)
1903 end
1904
1905 # Super init call
1906 var res = v.compile_callsite(callsite, args)
1907 return res
1908 end
1909
1910 var mpropdef = self.mpropdef.as(not null)
1911
1912 var args
1913 if self.n_args.n_exprs.is_empty then
1914 args = frame.arguments
1915 else
1916 args = v.varargize(mpropdef, signaturemap, recv, self.n_args.n_exprs)
1917 end
1918
1919 # Standard call-next-method
1920 return v.supercall(mpropdef, recv.mtype.as(MClassType), args)
1921 end
1922 end
1923
1924 redef class ASelfExpr
1925 redef fun expr(v) do return v.frame.as(not null).arguments.first
1926 end
1927
1928 redef class AImplicitSelfExpr
1929 redef fun expr(v) do return v.frame.as(not null).arguments.first
1930 end
1931
1932 redef class AAttrExpr
1933 redef fun expr(v) do
1934 var recv = v.expr(self.n_expr, null)
1935 var mproperty = self.mproperty.as(not null)
1936 return v.read_attribute(mproperty, recv)
1937 end
1938 end
1939
1940 redef class AAttrAssignExpr
1941 redef fun expr(v) do
1942 var recv = v.expr(self.n_expr, null)
1943 var i = v.expr(self.n_value, null)
1944 var mproperty = self.mproperty.as(not null)
1945 v.write_attribute(mproperty, recv, i)
1946 return i
1947 end
1948 end
1949
1950 redef class AAttrReassignExpr
1951 redef fun stmt(v) do
1952 var recv = v.expr(self.n_expr, null)
1953 var value = v.expr(self.n_value, null)
1954 var mproperty = self.mproperty.as(not null)
1955 var attr = v.read_attribute(mproperty, recv)
1956 var res = v.compile_callsite(self.reassign_callsite.as(not null), [attr, value])
1957 assert res != null
1958 v.write_attribute(mproperty, recv, res)
1959 end
1960 end
1961
1962 redef class AIssetAttrExpr
1963 redef fun expr(v) do
1964 var recv = v.expr(self.n_expr, null)
1965 var mproperty = self.mproperty.as(not null)
1966 return v.isset_attribute(mproperty, recv)
1967 end
1968 end
1969
1970 redef class AReturnExpr
1971 redef fun stmt(v) do
1972 var nexpr = self.n_expr
1973 var frame = v.frame
1974 assert frame != null
1975 if nexpr != null then
1976 v.ret(v.expr(nexpr, frame.returnvar.as(not null).mtype))
1977 else
1978 v.ret(v.null_instance)
1979 end
1980 end
1981 end
1982
1983 redef class AIfExpr
1984 redef fun stmt(v) do
1985 var cond = v.expr_bool(self.n_expr)
1986 v.add("if ({cond})\{")
1987 v.stmt(self.n_then)
1988 v.add("\} else \{")
1989 v.stmt(self.n_else)
1990 v.add("\}")
1991 end
1992
1993 redef fun expr(v) do
1994 var res = v.new_var(self.mtype.as(not null))
1995 var cond = v.expr_bool(self.n_expr)
1996 v.add("if ({cond})\{")
1997 v.assign(res, v.expr(self.n_then.as(not null), null))
1998 v.add("\} else \{")
1999 v.assign(res, v.expr(self.n_else.as(not null), null))
2000 v.add("\}")
2001 return res
2002 end
2003 end
2004
2005 redef class ADoExpr
2006 redef fun stmt(v)
2007 do
2008 v.add_escape_label(break_mark)
2009 v.add "\{"
2010 v.stmt(self.n_block)
2011 v.add "\}"
2012 end
2013 end
2014
2015 redef class AWhileExpr
2016 redef fun stmt(v)
2017 do
2018 v.add_escape_label(break_mark)
2019 v.add_escape_label(continue_mark)
2020 v.add("for(;;) \{")
2021 var cond = v.expr_bool(self.n_expr)
2022 v.add("if (!{cond}) break;")
2023 v.stmt(self.n_block)
2024 v.add("\}")
2025 end
2026 end
2027
2028 redef class ALoopExpr
2029 redef fun stmt(v)
2030 do
2031 v.add_escape_label(break_mark)
2032 v.add_escape_label(continue_mark)
2033 v.add("for(;;) \{")
2034 v.stmt(self.n_block)
2035 v.add("\}")
2036 end
2037 end
2038
2039 redef class AEscapeExpr
2040 redef fun stmt(v) do v.add("break BREAK_{v.escapemark_name(escapemark)};")
2041 end
2042
2043 redef class AVardeclExpr
2044 redef fun stmt(v) do
2045 var variable = self.variable.as(not null)
2046 var ne = self.n_expr
2047 var decl = v.variable(variable)
2048 if ne != null then
2049 var i = v.expr(ne, variable.declared_type)
2050 v.assign(decl, i)
2051 end
2052 end
2053 end
2054
2055 redef class AVarExpr
2056 redef fun expr(v) do
2057 return v.variable(self.variable.as(not null))
2058 end
2059 end
2060
2061 redef class AVarAssignExpr
2062 redef fun expr(v) do
2063 var variable = self.variable.as(not null)
2064 var i = v.expr(self.n_value, variable.declared_type)
2065 v.assign(v.variable(variable), i)
2066 return i
2067 end
2068 end
2069
2070
2071 redef class AAssertExpr
2072 redef fun stmt(v) do
2073 var cond = v.expr_bool(self.n_expr)
2074 v.add("if (!{cond}) \{")
2075 v.stmt(self.n_else)
2076 var nid = self.n_id
2077 if nid != null then
2078 v.add_abort("Assert '{nid.text}' failed")
2079 else
2080 v.add_abort("Assert failed")
2081 end
2082 v.add("\}")
2083 end
2084 end
2085
2086 redef class AImpliesExpr
2087 redef fun expr(v) do
2088 var res = v.new_var(mtype.as(not null))
2089 var i1 = v.expr_bool(n_expr)
2090 v.add("if (!{i1}) \{")
2091 v.add("{res} = true;")
2092 v.add("\} else \{")
2093 var i2 = v.expr_bool(n_expr2)
2094 v.add("{res} = {i2};")
2095 v.add("\}")
2096 return res
2097 end
2098 end
2099
2100 redef class AOrElseExpr
2101 redef fun expr(v)
2102 do
2103 var res = v.new_var(self.mtype.as(not null))
2104 var i1 = v.expr(self.n_expr, null)
2105 v.add("if ({i1} != null && !{i1}.is_null()) \{")
2106 v.assign(res, i1)
2107 v.add("\} else \{")
2108 var i2 = v.expr(self.n_expr2, null)
2109 v.assign(res, i2)
2110 v.add("\}")
2111 return res
2112 end
2113 end
2114
2115 redef class AOrExpr
2116 redef fun expr(v) do
2117 var res = v.new_var(self.mtype.as(not null))
2118 var i1 = v.expr_bool(self.n_expr)
2119 v.add("if ({i1}) \{")
2120 v.add("{res} = true;")
2121 v.add("\} else \{")
2122 var i2 = v.expr_bool(self.n_expr2)
2123 v.add("{res} = {i2};")
2124 v.add("\}")
2125 return res
2126 end
2127 end
2128
2129 redef class AAndExpr
2130 redef fun expr(v) do
2131 var res = v.new_var(self.mtype.as(not null))
2132 var i1 = v.expr_bool(self.n_expr)
2133 v.add("if (!{i1}) \{")
2134 v.add("{res} = false;")
2135 v.add("\} else \{")
2136 var i2 = v.expr_bool(self.n_expr2)
2137 v.add("{res} = {i2};")
2138 v.add("\}")
2139 return res
2140 end
2141 end
2142
2143 redef class ANotExpr
2144 redef fun expr(v) do
2145 var cond = v.expr_bool(self.n_expr)
2146 return v.new_expr("!{cond}", self.mtype.as(not null))
2147 end
2148 end
2149
2150 redef class AIntExpr
2151 redef fun expr(v) do return v.int_instance(self.value.as(not null))
2152 end
2153
2154 redef class AByteExpr
2155 redef fun expr(v) do return v.byte_instance(self.value.as(not null))
2156 end
2157
2158 redef class AFloatExpr
2159 redef fun expr(v) do return v.float_instance("{self.n_float.text}") # FIXME use value, not n_float
2160 end
2161
2162 redef class ACharExpr
2163 redef fun expr(v) do return v.char_instance(self.value.as(not null))
2164 end
2165
2166 redef class ATrueExpr
2167 redef fun expr(v) do return v.bool_instance(true)
2168 end
2169
2170 redef class AFalseExpr
2171 redef fun expr(v) do return v.bool_instance(false)
2172 end
2173
2174 redef class ANullExpr
2175 redef fun expr(v) do return v.null_instance
2176 end
2177
2178 redef class AIsaExpr
2179 redef fun expr(v)
2180 do
2181 var i = v.expr(self.n_expr, null)
2182 var cast_type = self.cast_type
2183 if cast_type == null then return null # no-no on broken node
2184 return v.type_test(i, cast_type)
2185 end
2186 end
2187
2188 redef class AParExpr
2189 redef fun expr(v) do return v.expr(self.n_expr, null)
2190 end
2191
2192 redef class AAbortExpr
2193 redef fun stmt(v) do v.add_abort("Aborted")
2194 end
2195
2196 redef class ADebugTypeExpr
2197 redef fun stmt(v) do end # do nothing
2198 end