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