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