Merge remote-tracking branch 'upstream/master' into init_auto
[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.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 args[i].vararg_decl > 0 then
530 var vararg = exprs.sub(j, args[i].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 != "RTVal")`
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 == "CString" 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.mproperty.is_root_init then
1486 if not mpropdef.is_intro then
1487 v.supercall(mpropdef, arguments.first.mtype.as(MClassType), arguments)
1488 end
1489 else
1490 abort
1491 end
1492 end
1493 end
1494
1495 redef class APropdef
1496
1497 # Compile that property definition to java code
1498 fun compile_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable]) do
1499 v.info("NOT YET IMPLEMENTED {class_name}::compile_to_java")
1500 end
1501 end
1502
1503 redef class AMethPropdef
1504 redef fun compile_to_java(v, mpropdef, arguments) do
1505 if mpropdef.msignature != null then
1506 var i = 0
1507 for mparam in mpropdef.msignature.as(not null).mparameters do
1508 var variable = n_signature.as(not null).n_params[i].variable
1509 if variable == null then continue
1510 var argvar = v.variable(variable)
1511 v.assign(argvar, v.new_expr("args[{i + 1}]", v.compiler.mainmodule.object_type))
1512 arguments.add(argvar)
1513 i += 1
1514 end
1515 end
1516
1517 # Call the implicit super-init
1518 var auto_super_inits = self.auto_super_inits
1519 if auto_super_inits != null then
1520 var args = [arguments.first]
1521 for auto_super_init in auto_super_inits do
1522 assert auto_super_init.mproperty != mpropdef.mproperty
1523 args.clear
1524 for i in [0..auto_super_init.msignature.arity+1[ do
1525 args.add(arguments[i])
1526 end
1527 assert auto_super_init.mproperty != mpropdef.mproperty
1528 v.compile_callsite(auto_super_init, args)
1529 end
1530 end
1531 if auto_super_call then
1532 v.supercall(mpropdef, arguments.first.mtype.as(MClassType), arguments)
1533 end
1534
1535 compile_inside_to_java(v, mpropdef, arguments)
1536 end
1537
1538 # Compile the inside of the method body
1539 private fun compile_inside_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable]) do
1540 # Compile intern methods
1541 if mpropdef.is_intern then
1542 if compile_intern_to_java(v, mpropdef, arguments) then return
1543 v.info("NOT YET IMPLEMENTED compile_intern for {mpropdef}")
1544 v.ret(v.null_instance)
1545 return
1546 end
1547
1548 # Compile block if any
1549 var n_block = n_block
1550 if n_block != null then
1551 v.stmt(n_block)
1552 return
1553 end
1554 end
1555
1556 # Compile an intern method using Java primitives
1557 fun compile_intern_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable]): Bool do
1558 var pname = mpropdef.mproperty.name
1559 var cname = mpropdef.mclassdef.mclass.name
1560 var ret = mpropdef.msignature.as(not null).return_mtype
1561 if cname == "Int" then
1562 if pname == "output" then
1563 v.add("System.out.println({arguments[0]});")
1564 v.ret(v.null_instance)
1565 return true
1566 else if pname == "object_id" then
1567 v.ret(arguments.first)
1568 return true
1569 else if pname == "+" then
1570 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1571 return true
1572 else if pname == "-" then
1573 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1574 return true
1575 else if pname == "unary -" then
1576 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1577 return true
1578 else if pname == "unary +" then
1579 v.ret(arguments[0])
1580 return true
1581 else if pname == "*" then
1582 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1583 return true
1584 else if pname == "/" then
1585 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
1586 return true
1587 else if pname == "%" then
1588 v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null)))
1589 return true
1590 else if pname == "<<" then
1591 v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
1592 return true
1593 else if pname == ">>" then
1594 v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null)))
1595 return true
1596 else if pname == "==" then
1597 v.ret(v.equal_test(arguments[0], arguments[1]))
1598 return true
1599 else if pname == "!=" then
1600 var res = v.equal_test(arguments[0], arguments[1])
1601 v.ret(v.new_expr("!{res}", ret.as(not null)))
1602 return true
1603 else if pname == "<" then
1604 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1605 return true
1606 else if pname == ">" then
1607 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1608 return true
1609 else if pname == "<=" then
1610 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1611 return true
1612 else if pname == ">=" then
1613 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1614 return true
1615 else if pname == "to_f" then
1616 v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
1617 return true
1618 else if pname == "to_b" then
1619 v.ret(v.new_expr("(byte){arguments[0]}", ret.as(not null)))
1620 return true
1621 else if pname == "ascii" then
1622 v.ret(v.new_expr("(char){arguments[0]}", ret.as(not null)))
1623 return true
1624 end
1625 else if cname == "Char" then
1626 if pname == "output" then
1627 v.add("System.out.print({arguments[0]});")
1628 v.ret(v.null_instance)
1629 return true
1630 else if pname == "object_id" then
1631 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1632 return true
1633 else if pname == "successor" then
1634 v.ret(v.new_expr("(char)({arguments[0]} + {arguments[1]})", ret.as(not null)))
1635 return true
1636 else if pname == "predecessor" then
1637 v.ret(v.new_expr("(char)({arguments[0]} - {arguments[1]})", ret.as(not null)))
1638 return true
1639 else if pname == "==" then
1640 v.ret(v.equal_test(arguments[0], arguments[1]))
1641 return true
1642 else if pname == "!=" then
1643 var res = v.equal_test(arguments[0], arguments[1])
1644 v.ret(v.new_expr("!{res}", ret.as(not null)))
1645 return true
1646 else if pname == "<" then
1647 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1648 return true
1649 else if pname == ">" then
1650 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1651 return true
1652 else if pname == "<=" then
1653 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1654 return true
1655 else if pname == ">=" then
1656 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1657 return true
1658 else if pname == "to_i" then
1659 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1660 return true
1661 else if pname == "ascii" then
1662 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1663 return true
1664 end
1665 else if cname == "Byte" then
1666 if pname == "output" then
1667 v.add("System.out.println({arguments[0]});")
1668 v.ret(v.null_instance)
1669 return true
1670 else if pname == "object_id" then
1671 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1672 return true
1673 else if pname == "+" then
1674 v.ret(v.new_expr("(byte)({arguments[0]} + {arguments[1]})", ret.as(not null)))
1675 return true
1676 else if pname == "-" then
1677 v.ret(v.new_expr("(byte)({arguments[0]} - {arguments[1]})", ret.as(not null)))
1678 return true
1679 else if pname == "unary -" then
1680 v.ret(v.new_expr("(byte)(-{arguments[0]})", ret.as(not null)))
1681 return true
1682 else if pname == "unary +" then
1683 v.ret(arguments[0])
1684 return true
1685 else if pname == "*" then
1686 v.ret(v.new_expr("(byte)({arguments[0]} * {arguments[1]})", ret.as(not null)))
1687 return true
1688 else if pname == "/" then
1689 v.ret(v.new_expr("(byte)({arguments[0]} / {arguments[1]})", ret.as(not null)))
1690 return true
1691 else if pname == "%" then
1692 v.ret(v.new_expr("(byte)({arguments[0]} % {arguments[1]})", ret.as(not null)))
1693 return true
1694 else if pname == "<<" then
1695 v.ret(v.new_expr("(byte)({arguments[0]} << {arguments[1]})", ret.as(not null)))
1696 return true
1697 else if pname == ">>" then
1698 v.ret(v.new_expr("(byte)({arguments[0]} >> {arguments[1]})", ret.as(not null)))
1699 return true
1700 else if pname == "==" then
1701 v.ret(v.equal_test(arguments[0], arguments[1]))
1702 return true
1703 else if pname == "!=" then
1704 var res = v.equal_test(arguments[0], arguments[1])
1705 v.ret(v.new_expr("!{res}", ret.as(not null)))
1706 return true
1707 else if pname == "<" then
1708 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1709 return true
1710 else if pname == ">" then
1711 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1712 return true
1713 else if pname == "<=" then
1714 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1715 return true
1716 else if pname == ">=" then
1717 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1718 return true
1719 else if pname == "to_i" then
1720 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1721 return true
1722 else if pname == "to_f" then
1723 v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
1724 return true
1725 else if pname == "ascii" then
1726 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
1727 return true
1728 end
1729 else if cname == "Bool" then
1730 if pname == "output" then
1731 v.add("System.out.println({arguments[0]});")
1732 v.ret(v.null_instance)
1733 return true
1734 else if pname == "object_id" then
1735 v.ret(v.new_expr("{arguments[0]}?1:0", ret.as(not null)))
1736 return true
1737 else if pname == "==" then
1738 v.ret(v.equal_test(arguments[0], arguments[1]))
1739 return true
1740 else if pname == "!=" then
1741 var res = v.equal_test(arguments[0], arguments[1])
1742 v.ret(v.new_expr("!{res}", ret.as(not null)))
1743 return true
1744 end
1745 else if cname == "Float" then
1746 if pname == "output" then
1747 v.add "if({arguments[0]} == Double.POSITIVE_INFINITY) \{"
1748 v.add "System.out.println(\"inf\");"
1749 v.add "\} else if({arguments[0]} == Double.POSITIVE_INFINITY) \{"
1750 v.add "System.out.println(\"-inf\");"
1751 v.add "\} else \{"
1752 var df = v.get_name("df")
1753 v.add "java.text.DecimalFormat {df} = new java.text.DecimalFormat(\"0.000000\");"
1754 v.add "System.out.println({df}.format({arguments[0]}));"
1755 v.add "\}"
1756 v.ret(v.null_instance)
1757 return true
1758 else if pname == "object_id" then
1759 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1760 return true
1761 else if pname == "+" then
1762 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1763 return true
1764 else if pname == "-" then
1765 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1766 return true
1767 else if pname == "unary -" then
1768 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1769 return true
1770 else if pname == "unary +" then
1771 v.ret(arguments[0])
1772 return true
1773 else if pname == "succ" then
1774 v.ret(v.new_expr("{arguments[0]} + 1", ret.as(not null)))
1775 return true
1776 else if pname == "prec" then
1777 v.ret(v.new_expr("{arguments[0]} - 1", ret.as(not null)))
1778 return true
1779 else if pname == "*" then
1780 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1781 return true
1782 else if pname == "/" then
1783 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
1784 return true
1785 else if pname == "==" then
1786 v.ret(v.equal_test(arguments[0], arguments[1]))
1787 return true
1788 else if pname == "!=" then
1789 var res = v.equal_test(arguments[0], arguments[1])
1790 v.ret(v.new_expr("!{res}", ret.as(not null)))
1791 return true
1792 else if pname == "<" then
1793 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1794 return true
1795 else if pname == ">" then
1796 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1797 return true
1798 else if pname == "<=" then
1799 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1800 return true
1801 else if pname == ">=" then
1802 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1803 return true
1804 else if pname == "to_i" then
1805 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1806 return true
1807 else if pname == "to_b" then
1808 v.ret(v.new_expr("(byte){arguments[0]}", ret.as(not null)))
1809 return true
1810 end
1811 end
1812 if pname == "exit" then
1813 v.add("System.exit({arguments[1]});")
1814 v.ret(v.null_instance)
1815 return true
1816 else if pname == "sys" then
1817 # TODO singleton
1818 var main_type = v.compiler.mainmodule.sys_type.as(not null)
1819 var sys = main_type.mclass
1820 v.ret(v.new_expr("new RTVal({sys.rt_name}.get{sys.rt_name}())", main_type))
1821 return true
1822 else if pname == "object_id" then
1823 v.ret(v.new_expr("{arguments[0]}.hashCode()", ret.as(not null)))
1824 return true
1825 else if pname == "is_same_type" then
1826 v.ret(v.is_same_type_test(arguments[0], arguments[1]))
1827 return true
1828 else if pname == "is_same_instance" then
1829 v.ret(v.equal_test(arguments[0], arguments[1]))
1830 return true
1831 else if pname == "output_class_name" then
1832 v.add("System.out.println({arguments[0]}.rtclass.class_name);")
1833 v.ret(v.null_instance)
1834 return true
1835 end
1836 return false
1837 end
1838 end
1839
1840 redef class AAttrPropdef
1841 redef fun compile_to_java(v, mpropdef, arguments) do
1842 v.current_node = self
1843 if mpropdef == mreadpropdef then
1844 compile_getter(v, mpropdef, arguments)
1845 else if mpropdef == mwritepropdef then
1846 compile_setter(v, mpropdef, arguments)
1847 else
1848 abort
1849 end
1850 v.current_node = null
1851 end
1852
1853 # Compile the setter method
1854 private fun compile_setter(v: JavaCompilerVisitor, mpropdef: MPropDef, arguments: Array[RuntimeVariable]) do
1855 var mtype = v.compiler.mainmodule.object_type
1856 var recv = arguments.first
1857 var val = v.new_expr("args[1]", mtype)
1858 v.write_attribute(self.mpropdef.as(not null).mproperty, recv, val)
1859 v.ret v.null_instance
1860 end
1861
1862 # Compile the getter method
1863 private fun compile_getter(v: JavaCompilerVisitor, mpropdef: MPropDef, arguments: Array[RuntimeVariable]) do
1864 var recv = arguments.first
1865 v.ret v.read_attribute(self.mpropdef.as(not null).mproperty, recv)
1866 end
1867
1868 private fun init_expr(v: JavaCompilerVisitor, recv: RuntimeVariable) do
1869 if has_value and not is_lazy and not n_expr isa ANullExpr then evaluate_expr(v, recv)
1870 end
1871
1872 # Evaluate, store and return the default value of the attribute
1873 private fun evaluate_expr(v: JavaCompilerVisitor, recv: RuntimeVariable): RuntimeVariable do
1874 var old = v.frame
1875 var frame = new JavaStaticFrame(v, self.mreadpropdef.as(not null), recv.mcasttype.undecorate.as(MClassType), [recv])
1876 v.frame = frame
1877
1878 var value
1879 var mtype = self.mtype
1880 assert mtype != null
1881
1882 var nexpr = self.n_expr
1883 var nblock = self.n_block
1884 if nexpr != null then
1885 value = v.expr(nexpr, mtype)
1886 else if nblock != null then
1887 value = v.new_var(mtype)
1888 frame.returnvar = value
1889 frame.returnlabel = v.get_name("RET_LABEL")
1890 v.add("{frame.returnlabel.as(not null)}: \{")
1891 v.stmt(nblock)
1892 v.add("\}")
1893 else
1894 abort
1895 end
1896
1897 v.write_attribute(self.mpropdef.as(not null).mproperty, recv, value)
1898 v.frame = old
1899 return value
1900 end
1901 end
1902
1903 redef class AExpr
1904 # Try to compile self as an expression
1905 # Do not call this method directly, use `v.expr` instead
1906 private fun expr(v: JavaCompilerVisitor): nullable RuntimeVariable do
1907 v.info("NOT YET IMPLEMENTED {class_name}::expr")
1908 return null
1909 end
1910
1911 # Try to compile self as a statement
1912 # Do not call this method directly, use `v.stmt` instead
1913 private fun stmt(v: JavaCompilerVisitor) do expr(v)
1914 end
1915
1916 redef class ABlockExpr
1917 redef fun stmt(v)
1918 do
1919 for e in self.n_expr do v.stmt(e)
1920 end
1921 redef fun expr(v)
1922 do
1923 var last = self.n_expr.last
1924 for e in self.n_expr do
1925 if e == last then break
1926 v.stmt(e)
1927 end
1928 return v.expr(last, null)
1929 end
1930 end
1931
1932 redef class ASendExpr
1933 redef fun expr(v) do
1934 var recv = v.expr(n_expr, null)
1935 var callsite = callsite.as(not null)
1936 var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, raw_arguments)
1937 return v.compile_callsite(callsite, args)
1938 end
1939 end
1940
1941 redef class ANewExpr
1942 redef fun expr(v)
1943 do
1944 var mtype = self.recvtype
1945 assert mtype != null
1946
1947 if mtype.mclass.name == "NativeArray" then
1948 # TODO handle native arrays
1949 v.info("NOT YET IMPLEMENTED new NativeArray")
1950 end
1951
1952 var recv = v.init_instance(mtype)
1953
1954 var callsite = self.callsite
1955 if callsite == null then return recv
1956
1957 var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs)
1958 var res2 = v.compile_callsite(callsite, args)
1959 if res2 != null then
1960 return res2
1961 end
1962 return recv
1963 end
1964 end
1965
1966 redef class ASuperExpr
1967 redef fun expr(v)
1968 do
1969 var frame = v.frame
1970 assert frame != null
1971 var recv = frame.arguments.first
1972
1973 var callsite = self.callsite
1974 if callsite != null then
1975 var args
1976
1977 if self.n_args.n_exprs.is_empty then
1978 # Add automatic arguments for the super init call
1979 args = [recv]
1980 for i in [0..callsite.msignature.arity[ do
1981 args.add(frame.arguments[i+1])
1982 end
1983 else
1984 args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs)
1985 end
1986
1987 # Super init call
1988 var res = v.compile_callsite(callsite, args)
1989 return res
1990 end
1991
1992 var mpropdef = self.mpropdef.as(not null)
1993
1994 var args
1995 if self.n_args.n_exprs.is_empty then
1996 args = frame.arguments
1997 else
1998 args = v.varargize(mpropdef, signaturemap, recv, self.n_args.n_exprs)
1999 end
2000
2001 # Standard call-next-method
2002 return v.supercall(mpropdef, recv.mtype.as(MClassType), args)
2003 end
2004 end
2005
2006 redef class ASelfExpr
2007 redef fun expr(v) do return v.frame.as(not null).arguments.first
2008 end
2009
2010 redef class AImplicitSelfExpr
2011 redef fun expr(v) do return v.frame.as(not null).arguments.first
2012 end
2013
2014 redef class AAttrExpr
2015 redef fun expr(v) do
2016 var recv = v.expr(self.n_expr, null)
2017 var mproperty = self.mproperty.as(not null)
2018 return v.read_attribute(mproperty, recv)
2019 end
2020 end
2021
2022 redef class AAttrAssignExpr
2023 redef fun expr(v) do
2024 var recv = v.expr(self.n_expr, null)
2025 var i = v.expr(self.n_value, null)
2026 var mproperty = self.mproperty.as(not null)
2027 v.write_attribute(mproperty, recv, i)
2028 return i
2029 end
2030 end
2031
2032 redef class AAttrReassignExpr
2033 redef fun stmt(v) do
2034 var recv = v.expr(self.n_expr, null)
2035 var value = v.expr(self.n_value, null)
2036 var mproperty = self.mproperty.as(not null)
2037 var attr = v.read_attribute(mproperty, recv)
2038 var res = v.compile_callsite(self.reassign_callsite.as(not null), [attr, value])
2039 assert res != null
2040 v.write_attribute(mproperty, recv, res)
2041 end
2042 end
2043
2044 redef class AIssetAttrExpr
2045 redef fun expr(v) do
2046 var recv = v.expr(self.n_expr, null)
2047 var mproperty = self.mproperty.as(not null)
2048 return v.isset_attribute(mproperty, recv)
2049 end
2050 end
2051
2052 redef class AReturnExpr
2053 redef fun stmt(v) do
2054 var nexpr = self.n_expr
2055 var frame = v.frame
2056 assert frame != null
2057 if nexpr != null then
2058 v.ret(v.expr(nexpr, frame.returnvar.as(not null).mtype))
2059 else
2060 v.ret(v.null_instance)
2061 end
2062 end
2063 end
2064
2065 redef class AIfExpr
2066 redef fun stmt(v) do
2067 var cond = v.expr_bool(self.n_expr)
2068 v.add("if ({cond})\{")
2069 v.stmt(self.n_then)
2070 v.add("\} else \{")
2071 v.stmt(self.n_else)
2072 v.add("\}")
2073 end
2074
2075 redef fun expr(v) do
2076 var res = v.new_var(self.mtype.as(not null))
2077 var cond = v.expr_bool(self.n_expr)
2078 v.add("if ({cond})\{")
2079 v.assign(res, v.expr(self.n_then.as(not null), null))
2080 v.add("\} else \{")
2081 v.assign(res, v.expr(self.n_else.as(not null), null))
2082 v.add("\}")
2083 return res
2084 end
2085 end
2086
2087 redef class ADoExpr
2088 redef fun stmt(v)
2089 do
2090 v.add_escape_label(break_mark)
2091 v.add "\{"
2092 v.stmt(self.n_block)
2093 v.add "\}"
2094 end
2095 end
2096
2097 redef class AWhileExpr
2098 redef fun stmt(v)
2099 do
2100 v.add_escape_label(break_mark)
2101 v.add_escape_label(continue_mark)
2102 v.add("for(;;) \{")
2103 var cond = v.expr_bool(self.n_expr)
2104 v.add("if (!{cond}) break;")
2105 v.stmt(self.n_block)
2106 v.add("\}")
2107 end
2108 end
2109
2110 redef class ALoopExpr
2111 redef fun stmt(v)
2112 do
2113 v.add_escape_label(break_mark)
2114 v.add_escape_label(continue_mark)
2115 v.add("for(;;) \{")
2116 v.stmt(self.n_block)
2117 v.add("\}")
2118 end
2119 end
2120
2121 redef class AEscapeExpr
2122 redef fun stmt(v) do v.add("break BREAK_{v.escapemark_name(escapemark)};")
2123 end
2124
2125 redef class AVardeclExpr
2126 redef fun stmt(v) do
2127 var variable = self.variable.as(not null)
2128 var ne = self.n_expr
2129 var decl = v.variable(variable)
2130 if ne != null then
2131 var i = v.expr(ne, variable.declared_type)
2132 v.assign(decl, i)
2133 end
2134 end
2135 end
2136
2137 redef class AVarExpr
2138 redef fun expr(v) do
2139 return v.variable(self.variable.as(not null))
2140 end
2141 end
2142
2143 redef class AVarAssignExpr
2144 redef fun expr(v) do
2145 var variable = self.variable.as(not null)
2146 var i = v.expr(self.n_value, variable.declared_type)
2147 v.assign(v.variable(variable), i)
2148 return i
2149 end
2150 end
2151
2152
2153 redef class AAssertExpr
2154 redef fun stmt(v) do
2155 var cond = v.expr_bool(self.n_expr)
2156 v.add("if (!{cond}) \{")
2157 v.stmt(self.n_else)
2158 var nid = self.n_id
2159 if nid != null then
2160 v.add_abort("Assert '{nid.text}' failed")
2161 else
2162 v.add_abort("Assert failed")
2163 end
2164 v.add("\}")
2165 end
2166 end
2167
2168 redef class AImpliesExpr
2169 redef fun expr(v) do
2170 var res = v.new_var(mtype.as(not null))
2171 var i1 = v.expr_bool(n_expr)
2172 v.add("if (!{i1}) \{")
2173 v.add("{res} = true;")
2174 v.add("\} else \{")
2175 var i2 = v.expr_bool(n_expr2)
2176 v.add("{res} = {i2};")
2177 v.add("\}")
2178 return res
2179 end
2180 end
2181
2182 redef class AOrElseExpr
2183 redef fun expr(v)
2184 do
2185 var res = v.new_var(self.mtype.as(not null))
2186 var i1 = v.expr(self.n_expr, null)
2187 v.add("if ({i1} != null && !{i1}.is_null()) \{")
2188 v.assign(res, i1)
2189 v.add("\} else \{")
2190 var i2 = v.expr(self.n_expr2, null)
2191 v.assign(res, i2)
2192 v.add("\}")
2193 return res
2194 end
2195 end
2196
2197 redef class AOrExpr
2198 redef fun expr(v) do
2199 var res = v.new_var(self.mtype.as(not null))
2200 var i1 = v.expr_bool(self.n_expr)
2201 v.add("if ({i1}) \{")
2202 v.add("{res} = true;")
2203 v.add("\} else \{")
2204 var i2 = v.expr_bool(self.n_expr2)
2205 v.add("{res} = {i2};")
2206 v.add("\}")
2207 return res
2208 end
2209 end
2210
2211 redef class AAndExpr
2212 redef fun expr(v) do
2213 var res = v.new_var(self.mtype.as(not null))
2214 var i1 = v.expr_bool(self.n_expr)
2215 v.add("if (!{i1}) \{")
2216 v.add("{res} = false;")
2217 v.add("\} else \{")
2218 var i2 = v.expr_bool(self.n_expr2)
2219 v.add("{res} = {i2};")
2220 v.add("\}")
2221 return res
2222 end
2223 end
2224
2225 redef class ANotExpr
2226 redef fun expr(v) do
2227 var cond = v.expr_bool(self.n_expr)
2228 return v.new_expr("!{cond}", self.mtype.as(not null))
2229 end
2230 end
2231
2232 redef class AIntegerExpr
2233 redef fun expr(v) do
2234 if value isa Int then
2235 return v.int_instance(self.value.as(Int))
2236 else if value isa Byte then
2237 return v.byte_instance(self.value.as(Byte))
2238 else
2239 # Should not happen
2240 abort
2241 end
2242 end
2243 end
2244
2245 redef class AFloatExpr
2246 redef fun expr(v) do return v.float_instance("{self.n_float.text}") # FIXME use value, not n_float
2247 end
2248
2249 redef class ACharExpr
2250 redef fun expr(v) do return v.char_instance(self.value.as(not null))
2251 end
2252
2253 redef class ATrueExpr
2254 redef fun expr(v) do return v.bool_instance(true)
2255 end
2256
2257 redef class AFalseExpr
2258 redef fun expr(v) do return v.bool_instance(false)
2259 end
2260
2261 redef class ANullExpr
2262 redef fun expr(v) do return v.null_instance
2263 end
2264
2265 redef class AAsCastExpr
2266 redef fun expr(v)
2267 do
2268 var i = v.expr(n_expr, null)
2269 v.add_cast(i, mtype.as(not null))
2270 return i
2271 end
2272 end
2273
2274 redef class AAsNotnullExpr
2275 redef fun expr(v) do
2276 var i = v.expr(n_expr, null)
2277 if i.mtype.is_java_primitive then return i
2278
2279 v.add("if ({i} == null || {i}.is_null()) \{")
2280 v.add_abort("Cast failed")
2281 v.add("\}")
2282 return i
2283 end
2284 end
2285
2286 redef class AIsaExpr
2287 redef fun expr(v)
2288 do
2289 var i = v.expr(self.n_expr, null)
2290 var cast_type = self.cast_type
2291 if cast_type == null then return null # no-no on broken node
2292 return v.type_test(i, cast_type)
2293 end
2294 end
2295
2296 redef class AParExpr
2297 redef fun expr(v) do return v.expr(self.n_expr, null)
2298 end
2299
2300 redef class AAbortExpr
2301 redef fun stmt(v) do v.add_abort("Aborted")
2302 end
2303
2304 redef class ADebugTypeExpr
2305 redef fun stmt(v) do end # do nothing
2306 end