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