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