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