nitj: implement bool exprs
[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 var recv = mclassdef.bound_mtype
1327 var arguments = new Array[RuntimeVariable]
1328 var frame = new JavaStaticFrame(v, self, recv, arguments)
1329 v.frame = frame
1330
1331 var selfvar = v.decl_var("self", recv)
1332 arguments.add(selfvar)
1333 var boxed = v.new_expr("args[0]", v.compiler.mainmodule.object_type)
1334 v.add "{selfvar} = {v.autobox(boxed, recv)};"
1335
1336 var msignature = self.msignature
1337 var ret = null
1338 if msignature != null then
1339 ret = msignature.return_mtype
1340 if ret != null then
1341 var retvar = v.decl_var("ret", ret)
1342 if ret.name == "Int" then v.add "{retvar} = 0;"
1343 if ret.name == "Float" then v.add "{retvar} = 0.0;"
1344 if ret.name == "Bool" then v.add "{retvar} = false;"
1345 if ret.name == "Char" then v.add "{retvar} = 0;"
1346 if ret.name == "Byte" then v.add "{retvar} = 0;"
1347 frame.returnvar = retvar
1348 end
1349 end
1350 frame.returnlabel = v.get_name("RET_LABEL")
1351
1352 v.current_node = node
1353 if is_abstract then
1354 v.add_abort("Abstract method `{mproperty.name}` called on `\" + {selfvar}.rtclass.class_name +\"`")
1355 v.add("return null;")
1356 return
1357 end
1358 v.current_node = null
1359
1360 v.add("{frame.returnlabel.as(not null)}: \{")
1361
1362 if node isa APropdef then
1363 node.compile_to_java(v, self, arguments)
1364 else if node isa AClassdef then
1365 node.compile_to_java(v, self, arguments)
1366 else
1367 abort
1368 end
1369
1370 v.add("\}")
1371 if ret != null then
1372 v.add("return {v.autobox(frame.returnvar.as(not null), v.compiler.mainmodule.object_type)};")
1373 else
1374 v.add("return null;")
1375 end
1376 end
1377 end
1378
1379 redef class AClassdef
1380 private fun compile_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable]) do
1381 if mpropdef == self.mfree_init then
1382 assert mpropdef.mproperty.is_root_init
1383 if not mpropdef.is_intro then
1384 v.supercall(mpropdef, arguments.first.mtype.as(MClassType), arguments)
1385 end
1386 else
1387 abort
1388 end
1389 end
1390 end
1391
1392 redef class APropdef
1393
1394 # Compile that property definition to java code
1395 fun compile_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable]) do
1396 v.info("NOT YET IMPLEMENTED {class_name}::compile_to_java")
1397 end
1398 end
1399
1400 redef class AMethPropdef
1401 redef fun compile_to_java(v, mpropdef, arguments) do
1402 if mpropdef.msignature != null then
1403 var i = 0
1404 for mparam in mpropdef.msignature.as(not null).mparameters do
1405 var variable = n_signature.as(not null).n_params[i].variable
1406 if variable == null then continue
1407 var argvar = v.variable(variable)
1408 v.assign(argvar, v.new_expr("args[{i + 1}]", v.compiler.mainmodule.object_type))
1409 arguments.add(argvar)
1410 i += 1
1411 end
1412 end
1413
1414 # Call the implicit super-init
1415 var auto_super_inits = self.auto_super_inits
1416 if auto_super_inits != null then
1417 var args = [arguments.first]
1418 for auto_super_init in auto_super_inits do
1419 assert auto_super_init.mproperty != mpropdef.mproperty
1420 args.clear
1421 for i in [0..auto_super_init.msignature.arity+1[ do
1422 args.add(arguments[i])
1423 end
1424 assert auto_super_init.mproperty != mpropdef.mproperty
1425 v.compile_callsite(auto_super_init, args)
1426 end
1427 end
1428 if auto_super_call then
1429 v.supercall(mpropdef, arguments.first.mtype.as(MClassType), arguments)
1430 end
1431
1432 compile_inside_to_java(v, mpropdef, arguments)
1433 end
1434
1435 # Compile the inside of the method body
1436 private fun compile_inside_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable]) do
1437 # Compile intern methods
1438 if mpropdef.is_intern then
1439 if compile_intern_to_java(v, mpropdef, arguments) then return
1440 v.info("NOT YET IMPLEMENTED compile_intern for {mpropdef}")
1441 v.ret(v.null_instance)
1442 return
1443 end
1444
1445 # Compile block if any
1446 var n_block = n_block
1447 if n_block != null then
1448 v.stmt(n_block)
1449 return
1450 end
1451 end
1452
1453 # Compile an intern method using Java primitives
1454 fun compile_intern_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable]): Bool do
1455 var pname = mpropdef.mproperty.name
1456 var cname = mpropdef.mclassdef.mclass.name
1457 var ret = mpropdef.msignature.as(not null).return_mtype
1458 if cname == "Int" then
1459 if pname == "output" then
1460 v.add("System.out.println({arguments[0]});")
1461 v.ret(v.null_instance)
1462 return true
1463 else if pname == "object_id" then
1464 v.ret(arguments.first)
1465 return true
1466 else if pname == "+" then
1467 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1468 return true
1469 else if pname == "-" then
1470 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1471 return true
1472 else if pname == "unary -" then
1473 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1474 return true
1475 else if pname == "unary +" then
1476 v.ret(arguments[0])
1477 return true
1478 else if pname == "*" then
1479 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1480 return true
1481 else if pname == "/" then
1482 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
1483 return true
1484 else if pname == "%" then
1485 v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null)))
1486 return true
1487 else if pname == "lshift" then
1488 v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
1489 return true
1490 else if pname == "rshift" then
1491 v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null)))
1492 return true
1493 else if pname == "==" then
1494 v.ret(v.equal_test(arguments[0], arguments[1]))
1495 return true
1496 else if pname == "!=" then
1497 var res = v.equal_test(arguments[0], arguments[1])
1498 v.ret(v.new_expr("!{res}", ret.as(not null)))
1499 return true
1500 else if pname == "<" then
1501 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1502 return true
1503 else if pname == ">" then
1504 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1505 return true
1506 else if pname == "<=" then
1507 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1508 return true
1509 else if pname == ">=" then
1510 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1511 return true
1512 else if pname == "to_f" then
1513 v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
1514 return true
1515 else if pname == "to_b" then
1516 v.ret(v.new_expr("(byte){arguments[0]}", ret.as(not null)))
1517 return true
1518 else if pname == "ascii" then
1519 v.ret(v.new_expr("(char){arguments[0]}", ret.as(not null)))
1520 return true
1521 end
1522 else if cname == "Char" then
1523 if pname == "output" then
1524 v.add("System.out.print({arguments[0]});")
1525 v.ret(v.null_instance)
1526 return true
1527 else if pname == "object_id" then
1528 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1529 return true
1530 else if pname == "successor" then
1531 v.ret(v.new_expr("(char)({arguments[0]} + {arguments[1]})", ret.as(not null)))
1532 return true
1533 else if pname == "predecessor" then
1534 v.ret(v.new_expr("(char)({arguments[0]} - {arguments[1]})", ret.as(not null)))
1535 return true
1536 else if pname == "==" then
1537 v.ret(v.equal_test(arguments[0], arguments[1]))
1538 return true
1539 else if pname == "!=" then
1540 var res = v.equal_test(arguments[0], arguments[1])
1541 v.ret(v.new_expr("!{res}", ret.as(not null)))
1542 return true
1543 else if pname == "<" then
1544 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1545 return true
1546 else if pname == ">" then
1547 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1548 return true
1549 else if pname == "<=" then
1550 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1551 return true
1552 else if pname == ">=" then
1553 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1554 return true
1555 else if pname == "to_i" then
1556 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1557 return true
1558 else if pname == "ascii" then
1559 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1560 return true
1561 end
1562 else if cname == "Byte" then
1563 if pname == "output" then
1564 v.add("System.out.println({arguments[0]});")
1565 v.ret(v.null_instance)
1566 return true
1567 else if pname == "object_id" then
1568 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1569 return true
1570 else if pname == "+" then
1571 v.ret(v.new_expr("(byte)({arguments[0]} + {arguments[1]})", ret.as(not null)))
1572 return true
1573 else if pname == "-" then
1574 v.ret(v.new_expr("(byte)({arguments[0]} - {arguments[1]})", ret.as(not null)))
1575 return true
1576 else if pname == "unary -" then
1577 v.ret(v.new_expr("(byte)(-{arguments[0]})", ret.as(not null)))
1578 return true
1579 else if pname == "unary +" then
1580 v.ret(arguments[0])
1581 return true
1582 else if pname == "*" then
1583 v.ret(v.new_expr("(byte)({arguments[0]} * {arguments[1]})", ret.as(not null)))
1584 return true
1585 else if pname == "/" then
1586 v.ret(v.new_expr("(byte)({arguments[0]} / {arguments[1]})", ret.as(not null)))
1587 return true
1588 else if pname == "%" then
1589 v.ret(v.new_expr("(byte)({arguments[0]} % {arguments[1]})", ret.as(not null)))
1590 return true
1591 else if pname == "lshift" then
1592 v.ret(v.new_expr("(byte)({arguments[0]} << {arguments[1]})", ret.as(not null)))
1593 return true
1594 else if pname == "rshift" then
1595 v.ret(v.new_expr("(byte)({arguments[0]} >> {arguments[1]})", ret.as(not null)))
1596 return true
1597 else if pname == "==" then
1598 v.ret(v.equal_test(arguments[0], arguments[1]))
1599 return true
1600 else if pname == "!=" then
1601 var res = v.equal_test(arguments[0], arguments[1])
1602 v.ret(v.new_expr("!{res}", ret.as(not null)))
1603 return true
1604 else if pname == "<" then
1605 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1606 return true
1607 else if pname == ">" then
1608 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1609 return true
1610 else if pname == "<=" then
1611 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1612 return true
1613 else if pname == ">=" then
1614 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1615 return true
1616 else if pname == "to_i" then
1617 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1618 return true
1619 else if pname == "to_f" then
1620 v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
1621 return true
1622 else if pname == "ascii" then
1623 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
1624 return true
1625 end
1626 else if cname == "Bool" then
1627 if pname == "output" then
1628 v.add("System.out.println({arguments[0]});")
1629 v.ret(v.null_instance)
1630 return true
1631 else if pname == "object_id" then
1632 v.ret(v.new_expr("{arguments[0]}?1:0", ret.as(not null)))
1633 return true
1634 else if pname == "==" then
1635 v.ret(v.equal_test(arguments[0], arguments[1]))
1636 return true
1637 else if pname == "!=" then
1638 var res = v.equal_test(arguments[0], arguments[1])
1639 v.ret(v.new_expr("!{res}", ret.as(not null)))
1640 return true
1641 end
1642 else if cname == "Float" then
1643 if pname == "output" then
1644 v.add "if({arguments[0]} == Double.POSITIVE_INFINITY) \{"
1645 v.add "System.out.println(\"inf\");"
1646 v.add "\} else if({arguments[0]} == Double.POSITIVE_INFINITY) \{"
1647 v.add "System.out.println(\"-inf\");"
1648 v.add "\} else \{"
1649 var df = v.get_name("df")
1650 v.add "java.text.DecimalFormat {df} = new java.text.DecimalFormat(\"0.000000\");"
1651 v.add "System.out.println({df}.format({arguments[0]}));"
1652 v.add "\}"
1653 v.ret(v.null_instance)
1654 return true
1655 else if pname == "object_id" then
1656 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1657 return true
1658 else if pname == "+" then
1659 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1660 return true
1661 else if pname == "-" then
1662 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1663 return true
1664 else if pname == "unary -" then
1665 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1666 return true
1667 else if pname == "unary +" then
1668 v.ret(arguments[0])
1669 return true
1670 else if pname == "succ" then
1671 v.ret(v.new_expr("{arguments[0]} + 1", ret.as(not null)))
1672 return true
1673 else if pname == "prec" then
1674 v.ret(v.new_expr("{arguments[0]} - 1", ret.as(not null)))
1675 return true
1676 else if pname == "*" then
1677 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1678 return true
1679 else if pname == "/" then
1680 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
1681 return true
1682 else if pname == "==" then
1683 v.ret(v.equal_test(arguments[0], arguments[1]))
1684 return true
1685 else if pname == "!=" then
1686 var res = v.equal_test(arguments[0], arguments[1])
1687 v.ret(v.new_expr("!{res}", ret.as(not null)))
1688 return true
1689 else if pname == "<" then
1690 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1691 return true
1692 else if pname == ">" then
1693 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1694 return true
1695 else if pname == "<=" then
1696 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1697 return true
1698 else if pname == ">=" then
1699 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1700 return true
1701 else if pname == "to_i" then
1702 v.ret(v.new_expr("(int){arguments[0]}", ret.as(not null)))
1703 return true
1704 else if pname == "to_b" then
1705 v.ret(v.new_expr("(byte){arguments[0]}", ret.as(not null)))
1706 return true
1707 end
1708 end
1709 if pname == "exit" then
1710 v.add("System.exit({arguments[1]});")
1711 v.ret(v.null_instance)
1712 return true
1713 else if pname == "sys" then
1714 # TODO singleton
1715 var main_type = v.compiler.mainmodule.sys_type.as(not null)
1716 var sys = main_type.mclass
1717 v.ret(v.new_expr("new RTVal({sys.rt_name}.get{sys.rt_name}())", main_type))
1718 return true
1719 else if pname == "object_id" then
1720 v.ret(v.new_expr("{arguments[0]}.hashCode()", ret.as(not null)))
1721 return true
1722 else if pname == "is_same_type" then
1723 v.ret(v.is_same_type_test(arguments[0], arguments[1]))
1724 return true
1725 else if pname == "is_same_instance" then
1726 v.ret(v.equal_test(arguments[0], arguments[1]))
1727 return true
1728 else if pname == "output_class_name" then
1729 v.add("System.out.println({arguments[0]}.rtclass.class_name);")
1730 v.ret(v.null_instance)
1731 return true
1732 end
1733 return false
1734 end
1735 end
1736
1737 redef class AAttrPropdef
1738 redef fun compile_to_java(v, mpropdef, arguments) do
1739 v.current_node = self
1740 if mpropdef == mreadpropdef then
1741 compile_getter(v, mpropdef, arguments)
1742 else if mpropdef == mwritepropdef then
1743 compile_setter(v, mpropdef, arguments)
1744 else
1745 abort
1746 end
1747 v.current_node = null
1748 end
1749
1750 # Compile the setter method
1751 private fun compile_setter(v: JavaCompilerVisitor, mpropdef: MPropDef, arguments: Array[RuntimeVariable]) do
1752 var mtype = v.compiler.mainmodule.object_type
1753 var recv = arguments.first
1754 var val = v.new_expr("args[1]", mtype)
1755 v.write_attribute(self.mpropdef.as(not null).mproperty, recv, val)
1756 v.ret v.null_instance
1757 end
1758
1759 # Compile the getter method
1760 private fun compile_getter(v: JavaCompilerVisitor, mpropdef: MPropDef, arguments: Array[RuntimeVariable]) do
1761 var recv = arguments.first
1762 v.ret v.read_attribute(self.mpropdef.as(not null).mproperty, recv)
1763 end
1764
1765 private fun init_expr(v: JavaCompilerVisitor, recv: RuntimeVariable) do
1766 if has_value and not is_lazy and not n_expr isa ANullExpr then evaluate_expr(v, recv)
1767 end
1768
1769 # Evaluate, store and return the default value of the attribute
1770 private fun evaluate_expr(v: JavaCompilerVisitor, recv: RuntimeVariable): RuntimeVariable do
1771 var old = v.frame
1772 var frame = new JavaStaticFrame(v, self.mreadpropdef.as(not null), recv.mcasttype.undecorate.as(MClassType), [recv])
1773 v.frame = frame
1774
1775 var value
1776 var mtype = self.mtype
1777 assert mtype != null
1778
1779 var nexpr = self.n_expr
1780 var nblock = self.n_block
1781 if nexpr != null then
1782 value = v.expr(nexpr, mtype)
1783 else if nblock != null then
1784 value = v.new_var(mtype)
1785 frame.returnvar = value
1786 frame.returnlabel = v.get_name("RET_LABEL")
1787 v.add("{frame.returnlabel.as(not null)}: \{")
1788 v.stmt(nblock)
1789 v.add("\}")
1790 else
1791 abort
1792 end
1793
1794 v.write_attribute(self.mpropdef.as(not null).mproperty, recv, value)
1795 v.frame = old
1796 return value
1797 end
1798 end
1799
1800 redef class AExpr
1801 # Try to compile self as an expression
1802 # Do not call this method directly, use `v.expr` instead
1803 private fun expr(v: JavaCompilerVisitor): nullable RuntimeVariable do
1804 v.info("NOT YET IMPLEMENTED {class_name}::expr")
1805 return null
1806 end
1807
1808 # Try to compile self as a statement
1809 # Do not call this method directly, use `v.stmt` instead
1810 private fun stmt(v: JavaCompilerVisitor) do expr(v)
1811 end
1812
1813 redef class ABlockExpr
1814 redef fun stmt(v)
1815 do
1816 for e in self.n_expr do v.stmt(e)
1817 end
1818 redef fun expr(v)
1819 do
1820 var last = self.n_expr.last
1821 for e in self.n_expr do
1822 if e == last then break
1823 v.stmt(e)
1824 end
1825 return v.expr(last, null)
1826 end
1827 end
1828
1829 redef class ASendExpr
1830 redef fun expr(v) do
1831 var recv = v.expr(n_expr, null)
1832 var callsite = callsite.as(not null)
1833 var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, raw_arguments)
1834 return v.compile_callsite(callsite, args)
1835 end
1836 end
1837
1838 redef class ANewExpr
1839 redef fun expr(v)
1840 do
1841 var mtype = self.recvtype
1842 assert mtype != null
1843
1844 if mtype.mclass.name == "NativeArray" then
1845 # TODO handle native arrays
1846 v.info("NOT YET IMPLEMENTED new NativeArray")
1847 end
1848
1849 var recv = v.init_instance(mtype)
1850
1851 var callsite = self.callsite
1852 if callsite == null then return recv
1853
1854 var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs)
1855 var res2 = v.compile_callsite(callsite, args)
1856 if res2 != null then
1857 return res2
1858 end
1859 return recv
1860 end
1861 end
1862
1863 redef class ASuperExpr
1864 redef fun expr(v)
1865 do
1866 var frame = v.frame
1867 assert frame != null
1868 var recv = frame.arguments.first
1869
1870 var callsite = self.callsite
1871 if callsite != null then
1872 var args
1873
1874 if self.n_args.n_exprs.is_empty then
1875 # Add automatic arguments for the super init call
1876 args = [recv]
1877 for i in [0..callsite.msignature.arity[ do
1878 args.add(frame.arguments[i+1])
1879 end
1880 else
1881 args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs)
1882 end
1883
1884 # Super init call
1885 var res = v.compile_callsite(callsite, args)
1886 return res
1887 end
1888
1889 var mpropdef = self.mpropdef.as(not null)
1890
1891 var args
1892 if self.n_args.n_exprs.is_empty then
1893 args = frame.arguments
1894 else
1895 args = v.varargize(mpropdef, signaturemap, recv, self.n_args.n_exprs)
1896 end
1897
1898 # Standard call-next-method
1899 return v.supercall(mpropdef, recv.mtype.as(MClassType), args)
1900 end
1901 end
1902
1903 redef class ASelfExpr
1904 redef fun expr(v) do return v.frame.as(not null).arguments.first
1905 end
1906
1907 redef class AImplicitSelfExpr
1908 redef fun expr(v) do return v.frame.as(not null).arguments.first
1909 end
1910
1911 redef class AAttrExpr
1912 redef fun expr(v) do
1913 var recv = v.expr(self.n_expr, null)
1914 var mproperty = self.mproperty.as(not null)
1915 return v.read_attribute(mproperty, recv)
1916 end
1917 end
1918
1919 redef class AAttrAssignExpr
1920 redef fun expr(v) do
1921 var recv = v.expr(self.n_expr, null)
1922 var i = v.expr(self.n_value, null)
1923 var mproperty = self.mproperty.as(not null)
1924 v.write_attribute(mproperty, recv, i)
1925 return i
1926 end
1927 end
1928
1929 redef class AAttrReassignExpr
1930 redef fun stmt(v) do
1931 var recv = v.expr(self.n_expr, null)
1932 var value = v.expr(self.n_value, null)
1933 var mproperty = self.mproperty.as(not null)
1934 var attr = v.read_attribute(mproperty, recv)
1935 var res = v.compile_callsite(self.reassign_callsite.as(not null), [attr, value])
1936 assert res != null
1937 v.write_attribute(mproperty, recv, res)
1938 end
1939 end
1940
1941 redef class AIssetAttrExpr
1942 redef fun expr(v) do
1943 var recv = v.expr(self.n_expr, null)
1944 var mproperty = self.mproperty.as(not null)
1945 return v.isset_attribute(mproperty, recv)
1946 end
1947 end
1948
1949 redef class AReturnExpr
1950 redef fun stmt(v) do
1951 var nexpr = self.n_expr
1952 var frame = v.frame
1953 assert frame != null
1954 if nexpr != null then
1955 v.ret(v.expr(nexpr, frame.returnvar.as(not null).mtype))
1956 else
1957 v.ret(v.null_instance)
1958 end
1959 end
1960 end
1961
1962 redef class AIfExpr
1963 redef fun stmt(v) do
1964 var cond = v.expr_bool(self.n_expr)
1965 v.add("if ({cond})\{")
1966 v.stmt(self.n_then)
1967 v.add("\} else \{")
1968 v.stmt(self.n_else)
1969 v.add("\}")
1970 end
1971
1972 redef fun expr(v) do
1973 var res = v.new_var(self.mtype.as(not null))
1974 var cond = v.expr_bool(self.n_expr)
1975 v.add("if ({cond})\{")
1976 v.assign(res, v.expr(self.n_then.as(not null), null))
1977 v.add("\} else \{")
1978 v.assign(res, v.expr(self.n_else.as(not null), null))
1979 v.add("\}")
1980 return res
1981 end
1982 end
1983
1984 redef class ADoExpr
1985 redef fun stmt(v)
1986 do
1987 v.add_escape_label(break_mark)
1988 v.add "\{"
1989 v.stmt(self.n_block)
1990 v.add "\}"
1991 end
1992 end
1993
1994 redef class AWhileExpr
1995 redef fun stmt(v)
1996 do
1997 v.add_escape_label(break_mark)
1998 v.add_escape_label(continue_mark)
1999 v.add("for(;;) \{")
2000 var cond = v.expr_bool(self.n_expr)
2001 v.add("if (!{cond}) break;")
2002 v.stmt(self.n_block)
2003 v.add("\}")
2004 end
2005 end
2006
2007 redef class ALoopExpr
2008 redef fun stmt(v)
2009 do
2010 v.add_escape_label(break_mark)
2011 v.add_escape_label(continue_mark)
2012 v.add("for(;;) \{")
2013 v.stmt(self.n_block)
2014 v.add("\}")
2015 end
2016 end
2017
2018 redef class AEscapeExpr
2019 redef fun stmt(v) do v.add("break BREAK_{v.escapemark_name(escapemark)};")
2020 end
2021
2022 redef class AVardeclExpr
2023 redef fun stmt(v) do
2024 var variable = self.variable.as(not null)
2025 var ne = self.n_expr
2026 var decl = v.variable(variable)
2027 if ne != null then
2028 var i = v.expr(ne, variable.declared_type)
2029 v.assign(decl, i)
2030 end
2031 end
2032 end
2033
2034 redef class AVarExpr
2035 redef fun expr(v) do
2036 return v.variable(self.variable.as(not null))
2037 end
2038 end
2039
2040 redef class AVarAssignExpr
2041 redef fun expr(v) do
2042 var variable = self.variable.as(not null)
2043 var i = v.expr(self.n_value, variable.declared_type)
2044 v.assign(v.variable(variable), i)
2045 return i
2046 end
2047 end
2048
2049
2050 redef class AAssertExpr
2051 redef fun stmt(v) do
2052 var cond = v.expr_bool(self.n_expr)
2053 v.add("if (!{cond}) \{")
2054 v.stmt(self.n_else)
2055 var nid = self.n_id
2056 if nid != null then
2057 v.add_abort("Assert '{nid.text}' failed")
2058 else
2059 v.add_abort("Assert failed")
2060 end
2061 v.add("\}")
2062 end
2063 end
2064
2065 redef class AImpliesExpr
2066 redef fun expr(v) do
2067 var res = v.new_var(mtype.as(not null))
2068 var i1 = v.expr_bool(n_expr)
2069 v.add("if (!{i1}) \{")
2070 v.add("{res} = true;")
2071 v.add("\} else \{")
2072 var i2 = v.expr_bool(n_expr2)
2073 v.add("{res} = {i2};")
2074 v.add("\}")
2075 return res
2076 end
2077 end
2078
2079 redef class AOrElseExpr
2080 redef fun expr(v)
2081 do
2082 var res = v.new_var(self.mtype.as(not null))
2083 var i1 = v.expr(self.n_expr, null)
2084 v.add("if ({i1} != null && !{i1}.is_null()) \{")
2085 v.assign(res, i1)
2086 v.add("\} else \{")
2087 var i2 = v.expr(self.n_expr2, null)
2088 v.assign(res, i2)
2089 v.add("\}")
2090 return res
2091 end
2092 end
2093
2094 redef class AOrExpr
2095 redef fun expr(v) do
2096 var res = v.new_var(self.mtype.as(not null))
2097 var i1 = v.expr_bool(self.n_expr)
2098 v.add("if ({i1}) \{")
2099 v.add("{res} = true;")
2100 v.add("\} else \{")
2101 var i2 = v.expr_bool(self.n_expr2)
2102 v.add("{res} = {i2};")
2103 v.add("\}")
2104 return res
2105 end
2106 end
2107
2108 redef class AAndExpr
2109 redef fun expr(v) do
2110 var res = v.new_var(self.mtype.as(not null))
2111 var i1 = v.expr_bool(self.n_expr)
2112 v.add("if (!{i1}) \{")
2113 v.add("{res} = false;")
2114 v.add("\} else \{")
2115 var i2 = v.expr_bool(self.n_expr2)
2116 v.add("{res} = {i2};")
2117 v.add("\}")
2118 return res
2119 end
2120 end
2121
2122 redef class ANotExpr
2123 redef fun expr(v) do
2124 var cond = v.expr_bool(self.n_expr)
2125 return v.new_expr("!{cond}", self.mtype.as(not null))
2126 end
2127 end
2128
2129 redef class AIntExpr
2130 redef fun expr(v) do return v.int_instance(self.value.as(not null))
2131 end
2132
2133 redef class AByteExpr
2134 redef fun expr(v) do return v.byte_instance(self.value.as(not null))
2135 end
2136
2137 redef class AFloatExpr
2138 redef fun expr(v) do return v.float_instance("{self.n_float.text}") # FIXME use value, not n_float
2139 end
2140
2141 redef class ACharExpr
2142 redef fun expr(v) do return v.char_instance(self.value.as(not null))
2143 end
2144
2145 redef class ATrueExpr
2146 redef fun expr(v) do return v.bool_instance(true)
2147 end
2148
2149 redef class AFalseExpr
2150 redef fun expr(v) do return v.bool_instance(false)
2151 end
2152
2153 redef class ANullExpr
2154 redef fun expr(v) do return v.null_instance
2155 end
2156
2157 redef class AIsaExpr
2158 redef fun expr(v)
2159 do
2160 var i = v.expr(self.n_expr, null)
2161 var cast_type = self.cast_type
2162 if cast_type == null then return null # no-no on broken node
2163 return v.type_test(i, cast_type)
2164 end
2165 end
2166
2167 redef class AParExpr
2168 redef fun expr(v) do return v.expr(self.n_expr, null)
2169 end
2170
2171 redef class AAbortExpr
2172 redef fun stmt(v) do v.add_abort("Aborted")
2173 end
2174
2175 redef class ADebugTypeExpr
2176 redef fun stmt(v) do end # do nothing
2177 end