nitj: compile native instances of Int, Byte, Float, Char and Bool
[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 frontend
29
30 redef class ToolContext
31
32 # Where to output the generated binary
33 var opt_output = new OptionString("Output file", "-o", "--output")
34
35 # Where to output tmp files
36 var opt_compile_dir = new OptionString("Directory used to generate temporary files", "--compile-dir")
37
38 redef init do
39 super
40 option_context.add_option(opt_output, opt_compile_dir)
41 end
42 end
43
44 redef class ModelBuilder
45
46 # Start the Java compiler
47 fun run_java_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis) do
48 var time0 = get_time
49 toolcontext.info("*** GENERATING JAVA ***", 1)
50
51 var compiler = new JavaCompiler(mainmodule, self, runtime_type_analysis)
52 compiler.do_compilation
53
54 var time1 = get_time
55 toolcontext.info("*** END GENERATING JAVA: {time1-time0} ***", 2)
56 write_and_make(compiler)
57 end
58
59 # Write Java code and compile it into an executable jar
60 fun write_and_make(compiler: JavaCompiler) do
61 var time0 = get_time
62 toolcontext.info("*** WRITING JAVA ***", 1)
63
64 compiler.compile_dir.mkdir
65
66 var jfiles = write_java_files(compiler)
67
68 var time1 = get_time
69 toolcontext.info("*** END WRITING JAVA: {time1-time0} ***", 2)
70
71 time0 = time1
72 toolcontext.info("*** COMPILING JAVA ***", 1)
73
74 build_with_make(compiler, jfiles)
75 write_shell_script(compiler)
76
77 time1 = get_time
78 toolcontext.info("*** END COMPILING JAVA: {time1-time0} ***", 2)
79 end
80
81 # Write files managed by `compiler` into concrete files
82 fun write_java_files(compiler: JavaCompiler): Array[String] do
83 var jfiles = new Array[String]
84 for f in compiler.files do
85 var file = new FileWriter.open("{compiler.compile_dir}/{f.filename}")
86 for line in f.lines do file.write(line)
87 file.close
88 jfiles.add(f.filename)
89 end
90 return jfiles
91 end
92
93 # Compile Java generated files using `make`
94 fun build_with_make(compiler: JavaCompiler, jfiles: Array[String]) do
95 write_manifest(compiler)
96 write_makefile(compiler, jfiles)
97 var compile_dir = compiler.compile_dir
98 var outname = compiler.outname.to_path.filename
99 toolcontext.info("make -N -C {compile_dir} -f {outname}.mk", 2)
100 var res
101 if toolcontext.verbose_level >= 3 then
102 res = sys.system("make -B -C {compile_dir} -f {outname}.mk 2>&1")
103 else
104 res = sys.system("make -B -C {compile_dir} -f {outname}.mk 2>&1 > /dev/null")
105 end
106 if res != 0 then toolcontext.error(null, "make failed! Error code: {res}.")
107 end
108
109 # Write the Makefile used to compile Java generated files into an executable jar
110 fun write_makefile(compiler: JavaCompiler, jfiles: Array[String]) do
111 # list class files from jfiles
112 var ofiles = new List[String]
113 for f in jfiles do ofiles.add(f.strip_extension(".java") + ".class")
114
115 var compile_dir = compiler.compile_dir
116 var outname = compiler.outname.to_path.filename
117 var outpath = (sys.getcwd / compiler.outname).simplify_path
118 var makename = "{compile_dir}/{outname}.mk"
119 var makefile = new FileWriter.open(makename)
120
121 makefile.write("JC = javac\n")
122 makefile.write("JAR = jar\n\n")
123
124 makefile.write("all: {outpath}.jar\n\n")
125
126 makefile.write("{outpath}.jar: {compiler.mainmodule.jname}_Main.class\n")
127 makefile.write("\t$(JAR) cfm {outpath}.jar {outname}.mf {ofiles.join(" ")}\n\n")
128
129 makefile.write("{compiler.mainmodule.jname}_Main.class:\n")
130 makefile.write("\t$(JC) {jfiles.join(" ")}\n\n")
131
132 makefile.write("clean:\n")
133 makefile.write("\trm {ofiles.join(" ")} 2>/dev/null\n\n")
134
135 makefile.close
136 toolcontext.info("Generated makefile: {makename}", 2)
137 end
138
139 # Write the Java manifest file
140 private fun write_manifest(compiler: JavaCompiler) do
141 var compile_dir = compiler.compile_dir
142 var outname = compiler.outname.to_path.filename
143 var maniffile = new FileWriter.open("{compile_dir}/{outname}.mf")
144 maniffile.write("Manifest-Version: 1.0\n")
145 maniffile.write("Main-Class: {compiler.mainmodule.jname}_Main\n")
146 maniffile.close
147 end
148
149 # Write a simple bash script that runs the jar like it was a binary generated by nitc
150 private fun write_shell_script(compiler: JavaCompiler) do
151 var outname = compiler.outname
152 var shfile = new FileWriter.open(outname)
153 shfile.write("#!/bin/bash\n")
154 shfile.write("java -jar {outname}.jar \"$@\"\n")
155 shfile.close
156 sys.system("chmod +x {outname}")
157 end
158 end
159
160 # Compiler that translates Nit code to Java code
161 class JavaCompiler
162 # The main module of the program currently compiled
163 var mainmodule: MModule
164
165 # Modelbuilder used to know the model and the AST
166 var modelbuilder: ModelBuilder
167
168 # The result of the RTA (used to know live types and methods)
169 var runtime_type_analysis: RapidTypeAnalysis
170
171 # Where to generate tmp files
172 var compile_dir: String is lazy do
173 var dir = modelbuilder.toolcontext.opt_compile_dir.value
174 if dir == null then dir = "nitj_compile"
175 return dir
176 end
177
178 # Name of the generated executable
179 var outname: String is lazy do
180 var name = modelbuilder.toolcontext.opt_output.value
181 if name == null then name = mainmodule.jname
182 return name
183 end
184
185 # The list of all associated files
186 # Used to generate .java files
187 var files: Array[JavaCodeFile] = new Array[JavaCodeFile]
188
189 # Force the creation of a new file
190 # The point is to avoid contamination between must-be-compiled-separately files
191 fun new_file(name: String): JavaCodeFile do
192 var file = new JavaCodeFile(name)
193 files.add(file)
194 return file
195 end
196
197 # Kind of visitor to use
198 type VISITOR: JavaCompilerVisitor
199
200 # Initialize a visitor specific for the compiler engine
201 fun new_visitor(filename: String): VISITOR do
202 return new JavaCompilerVisitor(self, new_file(filename))
203 end
204
205 # RuntimeModel representation
206 private var rt_model: JavaRuntimeModel is lazy do return new JavaRuntimeModel
207
208 # Compile Nit code to Java
209 fun do_compilation do
210 # compile java classes used to represents the runtime model of the program
211 rt_model.compile_rtmodel(self)
212
213 # compile class structures
214 compile_mclasses_to_java
215
216 # compile method structures
217 compile_mmethods_to_java
218
219 # TODO compile main
220 modelbuilder.toolcontext.info("NOT YET IMPLEMENTED", 0)
221 end
222
223 # Generate a `RTClass` for each `MClass` found in model
224 #
225 # This is a global phase because we need to know all the program to build
226 # attributes, fill vft and type table.
227 fun compile_mclasses_to_java do
228 for mclass in mainmodule.model.mclasses do
229 mclass.compile_to_java(new_visitor("{mclass.rt_name}.java"))
230 end
231 end
232
233 # Generate a `RTMethod` for each `MMethodDef` found in model
234 #
235 # This is a separate phase.
236 fun compile_mmethods_to_java do
237 for mmodule in mainmodule.in_importation.greaters do
238 for mclassdef in mmodule.mclassdefs do
239 for mdef in mclassdef.mpropdefs do
240 if mdef isa MMethodDef then
241 mdef.compile_to_java(new_visitor("{mdef.rt_name}.java"))
242 end
243 end
244 end
245 end
246 end
247 end
248
249 # The class visiting the AST
250 #
251 # A visitor is attached to one JavaCodeFile it writes into.
252 class JavaCompilerVisitor
253 super Visitor
254
255 # JavaCompiler used with this visitor
256 type COMPILER: JavaCompiler
257
258 # The associated compiler
259 var compiler: JavaCompiler
260
261 # The file to write generated code into
262 var file: JavaCodeFile
263
264 # Names handling
265
266 private var names = new HashSet[String]
267 private var last: Int = 0
268
269 # Return a new name based on `s` and unique in the visitor
270 fun get_name(s: String): String do
271 if not self.names.has(s) then
272 self.names.add(s)
273 return s
274 end
275 var i = self.last + 1
276 loop
277 var s2 = s + i.to_s
278 if not self.names.has(s2) then
279 self.last = i
280 self.names.add(s2)
281 return s2
282 end
283 i = i + 1
284 end
285 end
286
287 # Variables handling
288
289 # Registered variables
290 protected var variables = new HashMap[Variable, RuntimeVariable]
291
292 # Return the local RuntimeVariable associated to a Nit local variable
293 fun variable(variable: Variable): RuntimeVariable do
294 if variables.has_key(variable) then
295 return variables[variable]
296 else
297 var name = get_name("var_{variable.name}")
298 var mtype = variable.declared_type.as(not null)
299 # TODO mtype = self.anchor(mtype)
300 var res = decl_var(name, mtype)
301 variables[variable] = res
302 return res
303 end
304 end
305
306 # Return a new uninitialized local RuntimeVariable with `name`
307 fun decl_var(name: String, mtype: MType): RuntimeVariable do
308 var res = new RuntimeVariable(name, mtype, mtype)
309 add("{mtype.java_type} {name} /* : {mtype} */;")
310 return res
311 end
312
313 # Return a new uninitialized local RuntimeVariable
314 fun new_var(mtype: MType): RuntimeVariable do
315 # TODO mtype = self.anchor(mtype)
316 var name = self.get_name("var")
317 return decl_var(name, mtype)
318 end
319
320 # Calls handling
321
322 # The current `JavaStaticFrame`
323 var frame: nullable JavaStaticFrame = null is writable
324
325 # Return a new local RuntimeVariable initialized from `args[0]`
326 fun new_recv(mtype: MType): RuntimeVariable do
327 var res = new_var(mtype)
328 add("{res} = args[0];")
329 return res
330 end
331
332 # Code generation
333
334 # Add a line (will be suffixed by `\n`)
335 fun add(line: String) do file.lines.add("{line}\n")
336
337 # Add a new partial line (no `\n` suffix)
338 fun addn(line: String) do file.lines.add(line)
339
340 # Compile a statement (if any)
341 fun stmt(nexpr: nullable AExpr) do
342 if nexpr == null then return
343 var old = self.current_node
344 current_node = nexpr
345 nexpr.stmt(self)
346 current_node = old
347 end
348
349 # Compile an expression an return its result
350 # `mtype` is the expected return type, pass null if no specific type is expected.
351 fun expr(nexpr: AExpr, mtype: nullable MType): RuntimeVariable do
352 var old = current_node
353 current_node = nexpr
354
355 var res = null
356 if nexpr.mtype != null then
357 res = nexpr.expr(self)
358 end
359 assert res != null
360 current_node = old
361 return res
362 end
363
364 # Correctly assign a left and a right value
365 # Boxing and unboxing is performed if required
366 fun assign(left, right: RuntimeVariable) do
367 # TODO right = autobox(right, left.mtype)
368 add("{left} = {right};")
369 end
370
371 # Return a new local RuntimeVariable initialized with the Java expression `jexpr`.
372 #
373 # `mtype` is used for the Java return variable initialization.
374 fun new_expr(jexpr: String, mtype: MType): RuntimeVariable do
375 var res = new_var(mtype)
376 add("{res} = {jexpr};")
377 return res
378 end
379
380 # Generate generic abort
381 #
382 # Used by aborts, asserts, casts, etc.
383 fun add_abort(message: String) do
384 add("System.err.print(\"Runtime error: {message}\");")
385 var node = current_node
386 if node != null then
387 add("System.err.print(\" ({node.location.short_location})\");")
388 end
389 add("System.err.println(\"\");")
390 add("System.exit(1);")
391 end
392
393 # Native instances
394
395 # Generate an integer value
396 fun int_instance(value: Int): RuntimeVariable do
397 var t = compiler.mainmodule.int_type
398 return new RuntimeVariable(value.to_s, t, t)
399 end
400
401 # Generate a byte value
402 fun byte_instance(value: Byte): RuntimeVariable do
403 var t = compiler.mainmodule.byte_type
404 return new RuntimeVariable(value.to_s, t, t)
405 end
406
407 # Generate a char value
408 fun char_instance(value: Char): RuntimeVariable do
409 var t = compiler.mainmodule.char_type
410 return new RuntimeVariable("'{value.to_s.escape_to_c}'", t, t)
411 end
412
413 # Generate a float value
414 #
415 # FIXME pass a Float, not a string
416 fun float_instance(value: String): RuntimeVariable do
417 var t = compiler.mainmodule.float_type
418 return new RuntimeVariable(value.to_s, t, t)
419 end
420
421 # Generate an integer value
422 fun bool_instance(value: Bool): RuntimeVariable do
423 var t = compiler.mainmodule.bool_type
424 return new RuntimeVariable(value.to_s, t, t)
425 end
426
427 # Generate the `null` value
428 fun null_instance: RuntimeVariable do
429 var t = compiler.mainmodule.model.null_type
430 return new RuntimeVariable("null", t, t)
431 end
432
433 # Utils
434
435 # Display a info message
436 fun info(str: String) do compiler.modelbuilder.toolcontext.info(str, 0)
437 end
438
439 # A file containing Java code.
440 class JavaCodeFile
441
442 # File name
443 var filename: String
444
445 # Lines to write
446 var lines: List[String] = new List[String]
447 end
448
449 redef class MEntity
450 # A Java compatible name for `self`
451 private fun jname: String do return name.to_cmangle
452 end
453
454 # Handler for runtime classes generation
455 #
456 # We need 3 kinds of runtime structures:
457 # * `RTClass` to represent a global class
458 # * `RTMethod` to represent a method definition
459 # * `RTVal` to represent runtime variables
460 class JavaRuntimeModel
461
462 # Compile JavaRuntimeModel structures
463 fun compile_rtmodel(compiler: JavaCompiler) do
464 compile_rtclass(compiler)
465 compile_rtmethod(compiler)
466 compile_rtval(compiler)
467 end
468
469 # Compile the abstract runtime class structure
470 #
471 # Runtime classes have 3 attributes:
472 # * `class_name`: the class name as a String
473 # * `vft`: the virtual function table for the class (flattened)
474 # * `supers`: the super type table (used for type tests)
475 fun compile_rtclass(compiler: JavaCompiler) do
476 var v = compiler.new_visitor("RTClass.java")
477 v.add("import java.util.HashMap;")
478 v.add("public abstract class RTClass \{")
479 v.add(" public String class_name;")
480 v.add(" public HashMap<String, RTMethod> vft = new HashMap<>();")
481 v.add(" public HashMap<String, RTClass> supers = new HashMap<>();")
482 v.add(" protected RTClass() \{\}")
483 v.add("\}")
484 end
485
486 # Compile the abstract runtime method structure
487 #
488 # Method body is executed through the `exec` method:
489 # * `exec` always take an array of RTVal as arg, the first one must be the receiver
490 # * `exec` always returns a RTVal (or null if the Nit return type is void)
491 fun compile_rtmethod(compiler: JavaCompiler) do
492 var v = compiler.new_visitor("RTMethod.java")
493 v.add("public abstract class RTMethod \{")
494 v.add(" protected RTMethod() \{\}")
495 v.add(" public abstract RTVal exec(RTVal[] args);")
496 v.add("\}")
497 end
498
499 # Compile the runtime value structure
500 #
501 # RTVal both represents object instances and primitives values:
502 # * object instances:
503 # * `rtclass` the class of the RTVal is instance of
504 # * `attrs` contains the attributes of the instance
505 # * primitive values:
506 # * `rtclass` represents the class of the primitive value Nit type
507 # * `value` contains the primitive value of the instance
508 # * null values:
509 # * they must have both `rtclass` and `value` as null
510 fun compile_rtval(compiler: JavaCompiler) do
511 var v = compiler.new_visitor("RTVal.java")
512 v.add("import java.util.HashMap;")
513 v.add("public class RTVal \{")
514 v.add(" public RTClass rtclass;")
515 v.add(" public HashMap<String, RTVal> attrs = new HashMap<>();")
516 v.add(" Object value;")
517 v.add(" public RTVal(RTClass rtclass) \{")
518 v.add(" this.rtclass = rtclass;")
519 v.add(" \}")
520 v.add(" public RTVal(RTClass rtclass, Object value) \{")
521 v.add(" this.rtclass = rtclass;")
522 v.add(" this.value = value;")
523 v.add(" \}")
524 v.add(" public boolean is_null() \{ return rtclass == null && value == null; \}")
525 v.add("\}")
526 end
527 end
528
529 # A runtime variable hold a runtime value in Java.
530 # Runtime variables are associated to Nit local variables and intermediate results in Nit expressions.
531 class RuntimeVariable
532
533 # The name of the variable in the Java code
534 var name: String
535
536 # The static type of the variable (as declard in Java)
537 var mtype: MType
538
539 # The current casted type of the variable (as known in Nit)
540 var mcasttype: MType is writable
541
542 # If the variable exaclty a mcasttype?
543 # false (usual value) means that the variable is a mcasttype or a subtype.
544 var is_exact: Bool = false is writable
545
546 # Is this variable declared as a RTVal or a Java primitive one?
547 var is_boxed = false
548
549 redef fun to_s do return name
550
551 redef fun inspect
552 do
553 var exact_str
554 if self.is_exact then
555 exact_str = " exact"
556 else
557 exact_str = ""
558 end
559 var type_str
560 if self.mtype == self.mcasttype then
561 type_str = "{mtype}{exact_str}"
562 else
563 type_str = "{mtype}({mcasttype}{exact_str})"
564 end
565 return "<{name}:{type_str}>"
566 end
567 end
568
569 # The static context of a visited property in a `JavaCompilerVisitor`
570 class JavaStaticFrame
571 # The associated visitor
572 var visitor: JavaCompilerVisitor
573
574 # The executed property.
575 # A Method in case of a call, an attribute in case of a default initialization.
576 var mpropdef: MPropDef
577
578 # The static type of the receiver
579 var receiver: MClassType
580
581 # Arguments of the method (the first is the receiver)
582 var arguments: Array[RuntimeVariable]
583
584 # The runtime_variable associated to the return (in a function)
585 var returnvar: nullable RuntimeVariable = null is writable
586
587 # The label at the end of the property
588 var returnlabel: nullable String = null is writable
589 end
590
591 redef class Location
592 # Return a shortened version of the location with `"{file}:{line_start}"`
593 fun short_location: String do
594 var file = self.file
595 if file == null then return "<no file>:{line_start}"
596 return "{file.filename.escape_to_c}:{line_start}"
597 end
598 end
599
600 redef class MType
601 # Return the Java type associated to a given Nit static type
602 fun java_type: String do return "RTVal"
603
604 # Is the associated Java type a primitive one?
605 #
606 # ENSURE `result == (java_type != "Object")`
607 var is_java_primitive: Bool is lazy do return java_type != "RTVal"
608 end
609
610 redef class MClassType
611
612 redef var java_type is lazy do
613 if mclass.name == "Int" then
614 return "int"
615 else if mclass.name == "Bool" then
616 return "boolean"
617 else if mclass.name == "Char" then
618 return "char"
619 else if mclass.name == "Float" then
620 return "double"
621 else if mclass.name == "Byte" then
622 return "byte"
623 else if mclass.name == "NativeString" then
624 return "String"
625 else if mclass.name == "NativeArray" then
626 return "Array"
627 end
628 return "RTVal"
629 end
630 end
631
632 redef class MClass
633
634 # Runtime name
635 private fun rt_name: String do return "RTClass_{intro.mmodule.jname}_{jname}"
636
637 # Generate a Java RTClass for a Nit MClass
638 fun compile_to_java(v: JavaCompilerVisitor) do
639 v.add("public class {rt_name} extends RTClass \{")
640 v.add(" protected static RTClass instance;")
641 v.add(" private {rt_name}() \{")
642 v.add(" this.class_name = \"{name}\";")
643 compile_vft(v)
644 compile_type_table(v)
645 v.add(" \}")
646 v.add(" public static RTClass get{rt_name}() \{")
647 v.add(" if(instance == null) \{")
648 v.add(" instance = new {rt_name}();")
649 v.add(" \}")
650 v.add(" return instance;")
651 v.add(" \}")
652 v.add("\}")
653 end
654
655 # Compile the virtual function table for the mclass
656 private fun compile_vft(v: JavaCompilerVisitor) do
657 # TODO handle generics
658 if mclass_type.need_anchor then return
659 var mclassdefs = mclass_type.collect_mclassdefs(v.compiler.mainmodule).to_a
660 v.compiler.mainmodule.linearize_mclassdefs(mclassdefs)
661
662 var mainmodule = v.compiler.mainmodule
663 for mclassdef in mclassdefs.reversed do
664 for mprop in mclassdef.intro_mproperties do
665 var mpropdef = mprop.lookup_first_definition(mainmodule, intro.bound_mtype)
666 if not mpropdef isa MMethodDef then continue
667 var rt_name = mpropdef.rt_name
668 v.add("this.vft.put(\"{mprop.full_name}\", {rt_name}.get{rt_name}());")
669
670 # fill super next definitions
671 while mpropdef.has_supercall do
672 var prefix = mpropdef.full_name
673 mpropdef = mpropdef.lookup_next_definition(mainmodule, intro.bound_mtype)
674 rt_name = mpropdef.rt_name
675 v.add("this.vft.put(\"{prefix}\", {rt_name}.get{rt_name}());")
676 end
677 end
678 end
679 end
680
681 # Compile the type table for the MClass
682 fun compile_type_table(v: JavaCompilerVisitor) do
683 for pclass in in_hierarchy(v.compiler.mainmodule).greaters do
684 if pclass == self then
685 v.add("supers.put(\"{pclass.jname}\", this);")
686 else
687 v.add("supers.put(\"{pclass.jname}\", {pclass.rt_name}.get{pclass.rt_name}());")
688 end
689 end
690 end
691 end
692
693 redef class MMethodDef
694
695 # Runtime name
696 private fun rt_name: String do
697 return "RTMethod_{mclassdef.mmodule.jname}_{mclassdef.mclass.jname}_{mproperty.jname}"
698 end
699
700 # Generate a Java RTMethod for `self`
701 fun compile_to_java(v: JavaCompilerVisitor) do
702 v.add("public class {rt_name} extends RTMethod \{")
703 v.add(" protected static RTMethod instance;")
704 v.add(" public static RTMethod get{rt_name}() \{")
705 v.add(" if(instance == null) \{")
706 v.add(" instance = new {rt_name}();")
707 v.add(" \}")
708 v.add(" return instance;")
709 v.add(" \}")
710 v.add(" @Override")
711 v.add(" public RTVal exec(RTVal[] args) \{")
712 compile_inside_to_java(v)
713 v.add(" \}")
714 v.add("\}")
715 end
716
717 # Compile the body of this function
718 fun compile_inside_to_java(v: JavaCompilerVisitor) do
719
720 var modelbuilder = v.compiler.modelbuilder
721 var node = modelbuilder.mpropdef2node(self)
722
723 if is_abstract then
724 # TODO compile abstract
725 v.info("NOT YET IMPLEMENTED call to abstract method")
726 v.add("return null;")
727 return
728 end
729
730 if node isa APropdef then
731 node.compile_to_java(v, self)
732 else if node isa AClassdef then
733 # TODO compile attributes
734 v.info("NOT YET IMPLEMENTED attribute handling")
735 v.add("return null;")
736 else
737 abort
738 end
739 end
740 end
741
742 redef class APropdef
743
744 # Compile that property definition to java code
745 fun compile_to_java(v: JavaCompilerVisitor, mpropdef: MMethodDef) do
746 v.info("NOT YET IMPLEMENTED {class_name}::compile_to_java")
747 end
748 end
749
750 redef class AMethPropdef
751 redef fun compile_to_java(v, mpropdef) do
752 # TODO Call the implicit super-init
753
754 # Compile intern methods
755 if mpropdef.is_intern then
756 v.info("NOT YET IMPLEMENTED {class_name}::compile_intern")
757 # TODO if compile_intern_to_java(v, mpropdef, arguments) then return
758 v.add("return null;")
759 return
760 end
761
762 # Compile block if any
763 var n_block = n_block
764 if n_block != null then
765 v.stmt(n_block)
766 return
767 end
768 end
769 end
770
771 redef class AExpr
772 # Try to compile self as an expression
773 # Do not call this method directly, use `v.expr` instead
774 private fun expr(v: JavaCompilerVisitor): nullable RuntimeVariable do
775 v.info("NOT YET IMPLEMENTED {class_name}::expr")
776 return null
777 end
778
779 # Try to compile self as a statement
780 # Do not call this method directly, use `v.stmt` instead
781 private fun stmt(v: JavaCompilerVisitor) do expr(v)
782 end
783
784 redef class ABlockExpr
785 redef fun stmt(v)
786 do
787 for e in self.n_expr do v.stmt(e)
788 end
789 redef fun expr(v)
790 do
791 var last = self.n_expr.last
792 for e in self.n_expr do
793 if e == last then break
794 v.stmt(e)
795 end
796 return v.expr(last, null)
797 end
798 end
799
800 redef class ASelfExpr
801 redef fun expr(v) do return v.frame.as(not null).arguments.first
802 end
803
804 redef class AImplicitSelfExpr
805 redef fun expr(v) do return v.frame.as(not null).arguments.first
806 end
807
808 redef class AIntExpr
809 redef fun expr(v) do return v.int_instance(self.value.as(not null))
810 end
811
812 redef class AByteExpr
813 redef fun expr(v) do return v.byte_instance(self.value.as(not null))
814 end
815
816 redef class AFloatExpr
817 redef fun expr(v) do return v.float_instance("{self.n_float.text}") # FIXME use value, not n_float
818 end
819
820 redef class ACharExpr
821 redef fun expr(v) do return v.char_instance(self.value.as(not null))
822 end
823
824 redef class ATrueExpr
825 redef fun expr(v) do return v.bool_instance(true)
826 end
827
828 redef class AFalseExpr
829 redef fun expr(v) do return v.bool_instance(false)
830 end
831
832 redef class ANullExpr
833 redef fun expr(v) do return v.null_instance
834 end
835
836 redef class AAbortExpr
837 redef fun stmt(v) do v.add_abort("Aborted")
838 end
839
840 redef class ADebugTypeExpr
841 redef fun stmt(v) do end # do nothing
842 end