1 # This file is part of NIT ( http://www.nitlanguage.org ).
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
15 # Compile Nit code to Java code
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
22 # More details are given in the documentation of these 3 classes.
24 # TODO Factorize with `abstract_compiler`
27 import rapid_type_analysis
31 redef class ToolContext
33 # Where to output the generated binary
34 var opt_output
= new OptionString("Output file", "-o", "--output")
36 # Where to output tmp files
37 var opt_compile_dir
= new OptionString("Directory used to generate temporary files", "--compile-dir")
39 # Compile using ant instead of make (faster, but no error display)
40 var opt_ant
= new OptionBool("Batch with ant (faster, but no error display)", "--ant")
44 option_context
.add_option
(opt_output
, opt_compile_dir
, opt_ant
)
48 redef class ModelBuilder
50 # Start the Java compiler
51 fun run_java_compiler
(mainmodule
: MModule, runtime_type_analysis
: RapidTypeAnalysis) do
53 toolcontext
.info
("*** GENERATING JAVA ***", 1)
55 var compiler
= new JavaCompiler(mainmodule
, self, runtime_type_analysis
)
56 compiler
.do_compilation
59 toolcontext
.info
("*** END GENERATING JAVA: {time1-time0} ***", 2)
60 write_and_make
(compiler
)
63 # Write Java code and compile it into an executable jar
64 fun write_and_make
(compiler
: JavaCompiler) do
66 toolcontext
.info
("*** WRITING JAVA ***", 1)
68 compiler
.compile_dir
.mkdir
70 var jfiles
= write_java_files
(compiler
)
73 toolcontext
.info
("*** END WRITING JAVA: {time1-time0} ***", 2)
76 toolcontext
.info
("*** COMPILING JAVA ***", 1)
78 if toolcontext
.opt_ant
.value
then
79 build_with_ant
(compiler
, jfiles
)
81 build_with_make
(compiler
, jfiles
)
83 write_shell_script
(compiler
)
86 toolcontext
.info
("*** END COMPILING JAVA: {time1-time0} ***", 2)
89 # Write files managed by `compiler` into concrete files
90 fun write_java_files
(compiler
: JavaCompiler): Array[String] do
91 var jfiles
= new Array[String]
92 for f
in compiler
.files
do
93 var filepath
= "{compiler.compile_dir}/{f.filename}"
94 var file
= cache_file
(filepath
)
95 for line
in f
.lines
do file
.write
(line
)
96 close_cache
(filepath
, file
)
97 jfiles
.add
(f
.filename
)
102 # Cache a file as `{filepath}.tmp` and replace the original if different
103 private fun cache_file
(filepath
: String): FileWriter do
104 if toolcontext
.opt_ant
.value
and filepath
.file_exists
then
105 return new FileWriter.open
("{filepath}.tmp")
107 return new FileWriter.open
(filepath
)
111 # Close the writer and move tmp file to original if modified
112 private fun close_cache
(filepath
: String, file
: FileWriter) do
114 if "{filepath}.tmp".file_exists
then
115 sys
.system
("if ! diff {filepath}.tmp {filepath} > /dev/null; then mv {filepath}.tmp {filepath}; else rm {filepath}.tmp; fi")
119 # Compile Java generated files using `make`
120 fun build_with_make
(compiler
: JavaCompiler, jfiles
: Array[String]) do
121 write_manifest
(compiler
)
122 write_makefile
(compiler
, jfiles
)
123 var compile_dir
= compiler
.compile_dir
124 var outname
= compiler
.outname
.to_path
.filename
125 toolcontext
.info
("make -N -C {compile_dir} -f {outname}.mk", 2)
127 if toolcontext
.verbose_level
>= 3 then
128 res
= sys
.system
("make -B -C {compile_dir} -f {outname}.mk 2>&1")
130 res
= sys
.system
("make -B -C {compile_dir} -f {outname}.mk 2>&1 > /dev/null")
132 if res
!= 0 then toolcontext
.error
(null, "make failed! Error code: {res}.")
135 # Compile Java sources using `ant`
136 fun build_with_ant
(compiler
: JavaCompiler, jfiles
: Array[String]) do
137 compile_antfile
(compiler
, jfiles
)
138 var outname
= compiler
.outname
.to_path
.filename
139 var antpath
= "{compiler.compile_dir}/{outname}.xml"
140 self.toolcontext
.info
("ant jar -f {antpath}", 2)
142 if self.toolcontext
.verbose_level
>= 3 then
143 res
= sys
.system
("ant jar -f {antpath} 2>&1")
145 res
= sys
.system
("ant jar -f {antpath} 2>&1 > /dev/null")
148 toolcontext
.error
(null, "ant compile failed! Error code: {res}.")
152 # Write the Makefile used to compile Java generated files into an executable jar
153 fun write_makefile
(compiler
: JavaCompiler, jfiles
: Array[String]) do
154 # list class files from jfiles
155 var ofiles
= new List[String]
156 for f
in jfiles
do ofiles
.add
(f
.strip_extension
(".java") + ".class")
158 var compile_dir
= compiler
.compile_dir
159 var outname
= compiler
.outname
.to_path
.filename
160 var outpath
= (sys
.getcwd
/ compiler
.outname
).simplify_path
161 var makename
= "{compile_dir}/{outname}.mk"
162 var makefile
= new FileWriter.open
(makename
)
164 makefile
.write
("JC = javac\n")
165 makefile
.write
("JAR = jar\n\n")
167 makefile
.write
("all: {outpath}.jar\n\n")
169 makefile
.write
("{outpath}.jar: {compiler.mainmodule.jname}_Main.class\n")
170 makefile
.write
("\t$(JAR) cfm {outpath}.jar {outname}.mf {ofiles.join(" ")}\n\n")
172 makefile
.write
("{compiler.mainmodule.jname}_Main.class:\n")
173 makefile
.write
("\t$(JC) {jfiles.join(" ")}\n\n")
175 makefile
.write
("clean:\n")
176 makefile
.write
("\trm {ofiles.join(" ")} 2>/dev/null\n\n")
179 toolcontext
.info
("Generated makefile: {makename}", 2)
182 # The Ant `build.xml` script used to compile build the final jar
183 fun compile_antfile
(compiler
: JavaCompiler, jfiles
: Array[String]) do
184 var compile_dir
= compiler
.compile_dir
185 var outname
= compiler
.outname
.to_path
.filename
186 var outpath
= (sys
.getcwd
/ compiler
.outname
).simplify_path
187 var antname
= "{compile_dir}/{outname}.xml"
188 var antfile
= new FileWriter.open
(antname
)
189 var jname
= compiler
.mainmodule
.jname
190 antfile
.write
("<project>")
191 antfile
.write
(" <target name=\"compile\
">")
192 antfile
.write
(" <mkdir dir=\"classes\
"/>")
193 antfile
.write
(" <javac includes=\"{compiler.mainmodule.jname}_Main
.java
{jfiles.join(" ")}\
" srcdir=\".\
" destdir=\"classes\
"/>")
194 antfile
.write
(" </target>")
195 antfile
.write
(" <target name=\"jar\
" depends=\"compile\
">")
196 antfile
.write
(" <jar destfile=\"{outpath}.jar\
" basedir=\"classes\
">")
197 antfile
.write
(" <manifest>")
198 antfile
.write
(" <attribute name=\"Main-Class\
" value=\"{jname}_Main\
"/>")
199 antfile
.write
(" </manifest>")
200 antfile
.write
(" </jar>")
201 antfile
.write
(" </target>")
202 antfile
.write
("</project>")
204 toolcontext
.info
("Generated antfile: {antname}", 2)
207 # Write the Java manifest file
208 private fun write_manifest
(compiler
: JavaCompiler) do
209 var compile_dir
= compiler
.compile_dir
210 var outname
= compiler
.outname
.to_path
.filename
211 var maniffile
= new FileWriter.open
("{compile_dir}/{outname}.mf")
212 maniffile
.write
("Manifest-Version: 1.0\n")
213 maniffile
.write
("Main-Class: {compiler.mainmodule.jname}_Main\n")
217 # Write a simple bash script that runs the jar like it was a binary generated by nitc
218 private fun write_shell_script
(compiler
: JavaCompiler) do
219 var outname
= compiler
.outname
220 var shfile
= new FileWriter.open
(outname
)
221 shfile
.write
("#!/bin/bash\n")
222 shfile
.write
("java -jar {outname}.jar \"$@\
"\n")
224 sys
.system
("chmod +x {outname}")
228 # Compiler that translates Nit code to Java code
230 # The main module of the program currently compiled
231 var mainmodule
: MModule
233 # Modelbuilder used to know the model and the AST
234 var modelbuilder
: ModelBuilder
236 # The result of the RTA (used to know live types and methods)
237 var runtime_type_analysis
: RapidTypeAnalysis
239 # Where to generate tmp files
240 var compile_dir
: String is lazy
do
241 var dir
= modelbuilder
.toolcontext
.opt_compile_dir
.value
242 if dir
== null then dir
= "nitj_compile"
246 # Name of the generated executable
247 var outname
: String is lazy
do
248 var name
= modelbuilder
.toolcontext
.opt_output
.value
249 if name
== null then name
= mainmodule
.jname
253 # The list of all associated files
254 # Used to generate .java files
255 var files
: Array[JavaCodeFile] = new Array[JavaCodeFile]
257 # Force the creation of a new file
258 # The point is to avoid contamination between must-be-compiled-separately files
259 fun new_file
(name
: String): JavaCodeFile do
260 var file
= new JavaCodeFile(name
)
265 # Kind of visitor to use
266 type VISITOR: JavaCompilerVisitor
268 # Initialize a visitor specific for the compiler engine
269 fun new_visitor
(filename
: String): VISITOR do
270 return new JavaCompilerVisitor(self, new_file
(filename
))
273 # RuntimeModel representation
274 private var rt_model
: JavaRuntimeModel is lazy
do return new JavaRuntimeModel
276 # Compile Nit code to Java
277 fun do_compilation
do
278 # compile java classes used to represents the runtime model of the program
279 rt_model
.compile_rtmodel
(self)
282 # compile class structures
283 compile_mclasses_to_java
285 # compile method structures
286 compile_mmethods_to_java
289 compile_main_function
292 # Prepare the boxes used to represent Java primitive types
293 fun compile_box_kinds
do
294 # Collect all bas box class
295 # FIXME: this is not completely fine with a separate compilation scheme
296 for classname
in ["Int", "Bool", "Byte", "Char", "Float"] do
297 var classes
= mainmodule
.model
.get_mclasses_by_name
(classname
)
298 if classes
== null then continue
299 assert classes
.length
== 1 else print classes
.join
(", ")
300 box_kinds
.add
(classes
.first
.mclass_type
)
304 # Types of boxes used to represent Java primitive types
305 var box_kinds
= new Array[MClassType]
307 # Generate a `RTClass` for each `MClass` found in model
309 # This is a global phase because we need to know all the program to build
310 # attributes, fill vft and type table.
311 fun compile_mclasses_to_java
do
312 for mclass
in mainmodule
.model
.mclasses
do
313 mclass
.compile_to_java
(new_visitor
("{mclass.rt_name}.java"))
317 # Generate a `RTMethod` for each `MMethodDef` found in model
319 # This is a separate phase.
320 fun compile_mmethods_to_java
do
321 for mmodule
in mainmodule
.in_importation
.greaters
do
322 for mclassdef
in mmodule
.mclassdefs
do
323 for mdef
in mclassdef
.mpropdefs
do
324 if mdef
isa MMethodDef then
325 mdef
.compile_to_java
(new_visitor
("{mdef.rt_name}.java"))
332 # Generate Java main that call Sys.main
333 fun compile_main_function
do
334 var v
= new_visitor
("{mainmodule.jname}_Main.java")
335 v
.add
("public class {mainmodule.jname}_Main \{")
336 v
.add
(" public static void main(String[] args) \{")
338 var main_type
= mainmodule
.sys_type
339 if main_type
!= null then
340 var mainmodule
= v
.compiler
.mainmodule
341 var glob_sys
= v
.init_instance
(main_type
)
342 var main_init
= mainmodule
.try_get_primitive_method
("init", main_type
.mclass
)
343 if main_init
!= null then
344 v
.send
(main_init
, [glob_sys
])
346 var main_method
= mainmodule
.try_get_primitive_method
("run", main_type
.mclass
) or else
347 mainmodule
.try_get_primitive_method
("main", main_type
.mclass
)
348 if main_method
!= null then
349 v
.send
(main_method
, [glob_sys
])
357 # The class visiting the AST
359 # A visitor is attached to one JavaCodeFile it writes into.
360 class JavaCompilerVisitor
363 # JavaCompiler used with this visitor
364 type COMPILER: JavaCompiler
366 # The associated compiler
367 var compiler
: JavaCompiler
369 # The file to write generated code into
370 var file
: JavaCodeFile
374 private var names
= new HashSet[String]
375 private var last
: Int = 0
377 # Return a new name based on `s` and unique in the visitor
378 fun get_name
(s
: String): String do
379 if not self.names
.has
(s
) then
383 var i
= self.last
+ 1
386 if not self.names
.has
(s2
) then
395 # Return an unique and stable identifier associated with an escapemark
396 fun escapemark_name
(e
: nullable EscapeMark): String do
398 var frame
= self.frame
400 if frame
.escapemark_names
.has_key
(e
) then return frame
.escapemark_names
[e
]
402 if name
== null then name
= "label"
403 name
= get_name
(name
)
404 frame
.escapemark_names
[e
] = name
408 # Insert a C label for associated with an escapemark
409 fun add_escape_label
(e
: nullable EscapeMark) do
410 if e
== null then return
411 if e
.escapes
.is_empty
then return
412 add
("BREAK_{escapemark_name(e)}: ")
417 # Registered variables
418 protected var variables
= new HashMap[Variable, RuntimeVariable]
420 # Return the local RuntimeVariable associated to a Nit local variable
421 fun variable
(variable
: Variable): RuntimeVariable do
422 if variables
.has_key
(variable
) then
423 return variables
[variable
]
425 var name
= get_name
("var_{variable.name}")
426 var mtype
= variable
.declared_type
.as(not null)
427 mtype
= anchor
(mtype
)
428 var res
= decl_var
(name
, mtype
)
429 variables
[variable
] = res
434 # Return a new uninitialized local RuntimeVariable with `name`
435 fun decl_var
(name
: String, mtype
: MType): RuntimeVariable do
436 var res
= new RuntimeVariable(name
, mtype
, mtype
)
437 res
.is_boxed
= not mtype
.is_java_primitive
438 add
("{mtype.java_type} {name} /* : {mtype} */;")
442 # Return a new uninitialized local RuntimeVariable
443 fun new_var
(mtype
: MType): RuntimeVariable do
444 mtype
= anchor
(mtype
)
445 var name
= self.get_name
("var")
446 return decl_var
(name
, mtype
)
451 # The current `JavaStaticFrame`
452 var frame
: nullable JavaStaticFrame = null is writable
454 # Return a new local RuntimeVariable initialized from `args[0]`
455 fun new_recv
(mtype
: MType): RuntimeVariable do
456 var res
= new_var
(mtype
)
457 add
("{res} = args[0];")
463 # Compile a call within a callsite
464 fun compile_callsite
(callsite
: CallSite, arguments
: Array[RuntimeVariable]): nullable RuntimeVariable do
465 var initializers
= callsite
.mpropdef
.initializers
466 if not initializers
.is_empty
then
467 var recv
= arguments
.first
470 for p
in initializers
do
471 if p
isa MMethod then
473 var msignature
= p
.intro
.msignature
474 if msignature
!= null then
475 for x
in msignature
.mparameters
do
476 args
.add arguments
[i
]
481 else if p
isa MAttribute then
482 info
("NOT YET IMPLEMENTED {class_name}::compile_callsite for MAttribute `{p}`")
483 #self.write_attribute(p, recv, arguments[i])
487 assert i
== arguments
.length
489 return send
(callsite
.mproperty
, [recv
])
492 return send
(callsite
.mproperty
, arguments
)
495 # Evaluate `args` as expressions in the call of `mpropdef` on `recv`.
497 # This method is used to manage varargs in signatures and returns the real array
498 # of runtime variables to use in the call.
499 fun varargize
(mpropdef
: MMethodDef, map
: nullable SignatureMap, recv
: RuntimeVariable, args
: SequenceRead[AExpr]): Array[RuntimeVariable] do
500 var msignature
= mpropdef
.new_msignature
or else mpropdef
.msignature
.as(not null)
501 var res
= new Array[RuntimeVariable]
504 if msignature
.arity
== 0 then return res
507 assert args
.length
== msignature
.arity
509 res
.add expr
(ne
, null)
514 # Eval in order of arguments, not parameters
515 var exprs
= new Array[RuntimeVariable].with_capacity
(args
.length
)
517 exprs
.add expr
(ne
, null)
520 # Fill `res` with the result of the evaluation according to the mapping
521 for i
in [0..msignature
.arity
[ do
522 var param
= msignature
.mparameters
[i
]
523 var j
= map
.map
.get_or_null
(i
)
526 res
.add
(null_instance
)
529 if param
.is_vararg
and args
[i
].vararg_decl
> 0 then
530 var vararg
= exprs
.sub
(j
, args
[i
].vararg_decl
)
531 var elttype
= param
.mtype
532 var arg
= self.vararg_instance
(mpropdef
, recv
, vararg
, elttype
)
541 # Generate a static call on a method definition (no receiver needed).
542 fun static_call
(mmethoddef
: MMethodDef, arguments
: Array[RuntimeVariable]): nullable RuntimeVariable do
543 var res
: nullable RuntimeVariable
544 var ret
= mmethoddef
.msignature
.as(not null).return_mtype
548 ret
= ret
.resolve_for
(mmethoddef
.mclassdef
.bound_mtype
, mmethoddef
.mclassdef
.bound_mtype
, mmethoddef
.mclassdef
.mmodule
, true)
549 res
= self.new_var
(ret
)
553 adapt_signature
(mmethoddef
, arguments
)
555 var rt_name
= mmethoddef
.rt_name
557 add
("{rt_name}.get{rt_name}().exec(new RTVal[]\{{arguments.join(",")}\});")
560 var ress
= new_expr
("{rt_name}.get{rt_name}().exec(new RTVal[]\{{arguments.join(",")}\});", compiler
.mainmodule
.object_type
)
565 # Generate a polymorphic send for `method` with `arguments`
566 fun send
(mmethod
: MMethod, arguments
: Array[RuntimeVariable]): nullable RuntimeVariable do
567 # Shortcut calls on primitives
568 if arguments
.first
.mcasttype
.is_java_primitive
then
569 return monomorphic_send
(mmethod
, arguments
.first
.mcasttype
, arguments
)
572 return table_send
(mmethod
, arguments
)
576 # Handle common special cases before doing the effective method invocation
577 # This methods handle the `==` and `!=` methods and the case of the null receiver.
578 # Note: a { is open in the generated C, that enclose and protect the effective method invocation.
579 # Client must not forget to close the } after them.
581 # The value returned is the result of the common special cases.
582 # If not null, client must compile it with the result of their own effective method invocation.
584 # If `before_send` can shortcut the whole message sending, a dummy `if(0){`
585 # is generated to cancel the effective method invocation that will follow
586 # TODO: find a better approach
587 private fun before_send
(res
: nullable RuntimeVariable, mmethod
: MMethodDef, arguments
: Array[RuntimeVariable]) do
588 var bool_type
= compiler
.mainmodule
.bool_type
589 var recv
= arguments
.first
590 var consider_null
= mmethod
.name
== "==" or mmethod
.name
== "!=" or mmethod
.name
== "is_same_instance"
591 if recv
.mcasttype
isa MNullableType or recv
.mcasttype
isa MNullType then
592 add
("if ({recv} == null || {recv}.is_null()) \{")
593 if mmethod
.name
== "==" or mmethod
.name
== "is_same_instance" then
594 if res
== null then res
= new_var
(bool_type
)
595 var arg
= arguments
[1]
596 if arg
.mcasttype
isa MNullableType then
597 add
("{res} = ({arg} == null || {arg}.is_null());")
598 else if arg
.mcasttype
isa MNullType then
599 add
("{res} = true; /* is null */")
601 add
("{res} = false; /* {arg.inspect} cannot be null */")
603 else if mmethod
.name
== "!=" then
604 if res
== null then res
= new_var
(bool_type
)
605 # res = self.new_var(bool_type)
606 var arg
= arguments
[1]
607 if arg
.mcasttype
isa MNullableType then
608 add
("{res} = ({arg} != null && !{arg}.is_null());")
609 else if arg
.mcasttype
isa MNullType then
610 add
("{res} = false; /* is null */")
612 add
("{res} = true; /* {arg.inspect} cannot be null */")
615 add_abort
("Receiver is null")
621 add
"/* recv ({recv}) cannot be null since it's a {recv.mcasttype}"
623 if consider_null
then
624 var arg
= arguments
[1]
625 if arg
.mcasttype
isa MNullType then
626 if res
== null then res
= new_var
(bool_type
)
627 if mmethod
.name
== "!=" then
628 add
("{res} = true; /* arg is null and recv is not */")
629 else # `==` and `is_same_instance`
630 add
("{res} = false; /* arg is null but recv is not */")
632 add
("\}") # closes the null case
633 add
("if (false) \{") # what follow is useless, Javac will drop it
638 # Perform a method call through vft
639 private fun table_send
(mmethod
: TableCallable, arguments
: Array[RuntimeVariable]): nullable RuntimeVariable do
642 if mmethod
isa MMethod then
644 name
= mmethod
.full_name
645 else if mmethod
isa MMethodDef then
647 name
= mmethod
.full_name
652 var recv
= arguments
.first
653 var rect
= mdef
.mclassdef
.bound_mtype
654 var msignature
= mdef
.msignature
.as(not null)
655 msignature
= msignature
.resolve_for
(rect
, rect
, compiler
.mainmodule
, true)
656 adapt_signature
(mdef
, arguments
)
658 var res
: nullable RuntimeVariable
659 var ret
= msignature
.return_mtype
663 res
= self.new_var
(ret
)
666 before_send
(res
, mdef
, arguments
)
668 add
"/* concrete call to {mdef} */"
670 var ress
= new_expr
("{recv}.rtclass.vft.get(\"{name}\
").exec(new RTVal[]\{{arguments.join(",")}\});", compiler
.mainmodule
.object_type
)
673 add
("{recv}.rtclass.vft.get(\"{name}\
").exec(new RTVal[]\{{arguments.join(",")}\});")
676 add
("\}") # closes the null case
681 # Generate a super call from a method definition
682 fun supercall
(m
: MMethodDef, recvtype
: MClassType, args
: Array[RuntimeVariable]): nullable RuntimeVariable do
683 return table_send
(m
, args
)
686 # Generate a monomorphic send for the method `m`, the type `t` and the arguments `args`
687 fun monomorphic_send
(m
: MMethod, t
: MType, args
: Array[RuntimeVariable]): nullable RuntimeVariable do
688 assert t
isa MClassType
689 var propdef
= m
.lookup_first_definition
(self.compiler
.mainmodule
, t
)
690 return self.static_call
(propdef
, args
)
695 # Add a line (will be suffixed by `\n`)
696 fun add
(line
: String) do file
.lines
.add
("{line}\n")
698 # Add a new partial line (no `\n` suffix)
699 fun addn
(line
: String) do file
.lines
.add
(line
)
701 # Compile a statement (if any)
702 fun stmt
(nexpr
: nullable AExpr) do
703 if nexpr
== null then return
704 if nexpr
.mtype
== null and not nexpr
.is_typed
then
705 # Untyped expression.
706 # Might mean dead code or invalid code
708 add_abort
("FATAL: bad statement executed.")
712 var old
= self.current_node
718 # Compile an expression an return its result
719 # `mtype` is the expected return type, pass null if no specific type is expected.
720 fun expr
(nexpr
: AExpr, mtype
: nullable MType): RuntimeVariable do
721 var old
= current_node
725 if nexpr
.mtype
!= null then
726 res
= nexpr
.expr
(self)
730 # Untyped expression.
731 # Might mean dead code or invalid code.
733 add_abort
("FATAL: bad expression executed.")
734 # and return a placebo result to please the C compiler
735 if mtype
== null then mtype
= compiler
.mainmodule
.object_type
738 self.current_node
= old
742 if mtype
!= null then
743 mtype
= anchor
(mtype
)
744 res
= autobox
(res
, mtype
)
751 # Alias for `self.expr(nexpr, self.bool_type)`
752 fun expr_bool
(nexpr
: AExpr): RuntimeVariable do
753 return expr
(nexpr
, compiler
.mainmodule
.bool_type
)
756 # Correctly assign a left and a right value
757 # Boxing and unboxing is performed if required
758 fun assign
(left
, right
: RuntimeVariable) do
759 add
("{left} = {autobox(right, left.mtype)};")
762 # Generate a return with `value`
763 fun ret
(value
: RuntimeVariable) do
764 var frame
= self.frame
766 var returnvar
= frame
.returnvar
767 if returnvar
!= null then
768 assign
(returnvar
, value
)
770 self.add
("break {frame.returnlabel.as(not null)};")
773 # Return a new local RuntimeVariable initialized with the Java expression `jexpr`.
775 # `mtype` is used for the Java return variable initialization.
776 fun new_expr
(jexpr
: String, mtype
: MType): RuntimeVariable do
777 var res
= new_var
(mtype
)
778 add
("{res} = {jexpr};")
782 # Generate generic abort
784 # Used by aborts, asserts, casts, etc.
785 fun add_abort
(message
: String) do
786 add
("System.err.print(\"Runtime error
: {message}\
");")
790 # Abort without displaying the cause.
792 # Used to customizable errors.
793 private fun add_raw_abort
do
794 var node
= current_node
796 add
("System.err.print(\" ({node.location.short_location})\
");")
798 add
("System.err.println(\"\
");")
799 add
("System.exit(1);")
803 fun add_cast
(value
: RuntimeVariable, mtype
: MType) do
804 var res
= type_test
(value
, mtype
)
805 add
("if (!{res}) \{")
806 add
("System.err.print(\"Runtime error
: Cast failed
. Expected `{mtype.to_s.escape_to_c}`, got
`\" + {value}.rtclass.class_name + \"`\
");")
813 # Anchor a type to the main module and the current receiver
814 fun anchor
(mtype
: MType): MType do
815 if not mtype
.need_anchor
then return mtype
816 return mtype
.anchor_to
(compiler
.mainmodule
, frame
.as(not null).receiver
)
819 # Adapt the arguments of a method according to targetted `MMethodDef`
820 fun adapt_signature
(m
: MMethodDef, args
: Array[RuntimeVariable]) do
821 var msignature
= m
.msignature
.as(not null).resolve_for
(
822 m
.mclassdef
.bound_mtype
,
823 m
.mclassdef
.bound_mtype
,
824 m
.mclassdef
.mmodule
, true)
825 args
.first
= autobox
(args
.first
, compiler
.mainmodule
.object_type
)
826 for i
in [0..msignature
.arity
[ do
827 args
[i
+1] = autobox
(args
[i
+ 1], compiler
.mainmodule
.object_type
)
831 # Box primitive `value` to `mtype`.
832 private fun box
(value
: RuntimeVariable, mtype
: MType): RuntimeVariable do
833 if value
.is_boxed
then return value
834 var obj_type
= compiler
.mainmodule
.object_type
835 if value
.mtype
isa MNullType then
836 return new_expr
("new RTVal(null, null)", compiler
.mainmodule
.model
.null_type
)
838 var mbox
= value
.mtype
.as(MClassType).mclass
839 return new_expr
("new RTVal({mbox.rt_name}.get{mbox.rt_name}(), {value})", obj_type
)
842 # Unbox primitive `value` to `mtype`.
843 private fun unbox
(value
: RuntimeVariable, mtype
: MType): RuntimeVariable do
844 if not value
.is_boxed
then return value
845 if not mtype
.is_java_primitive
then return value
846 if compiler
.box_kinds
.has
(mtype
) then
847 return new_expr
("({mtype.java_type}){value}.value", mtype
)
849 info
"NOT YET IMPLEMENTED unbox for {value} ({mtype})"
854 # Box or unbox primitive `value` to `mtype` if needed.
855 private fun autobox
(value
: RuntimeVariable, mtype
: MType): RuntimeVariable do
856 if mtype
.is_java_primitive
then return unbox
(value
, mtype
)
857 return box
(value
, mtype
)
860 # Can this `value` be a primitive Java value?
861 private fun can_be_primitive
(value
: RuntimeVariable): Bool do
862 var t
= value
.mcasttype
.undecorate
863 if not t
isa MClassType then return false
864 var k
= t
.mclass
.kind
865 return k
== interface_kind
or t
.is_java_primitive
868 # Generate a polymorphic subtype test
869 fun type_test
(value
: RuntimeVariable, mtype
: MType): RuntimeVariable do
870 add
("/* {value.inspect} isa {mtype} */")
871 var res
= self.new_var
(compiler
.mainmodule
.bool_type
)
873 # check color is in table
874 var maybenull
= (value
.mcasttype
isa MNullableType or value
.mcasttype
isa MNullType)
876 add
("if({value} == null || {value}.is_null()) \{")
877 add
("{res} = true && {mtype isa MNullableType};")
880 if mtype
isa MNullableType then mtype
= mtype
.mtype
881 var mclass
= mtype
.as(MClassType).mclass
882 add
("{res} = {value}.rtclass.supers.get(\"{mclass.jname}\
") == {mclass.rt_name}.get{mclass.rt_name}();")
889 # Generate the code required to dynamically check if 2 objects share the same runtime type
890 fun is_same_type_test
(value1
, value2
: RuntimeVariable): RuntimeVariable do
891 var res
= self.new_var
(compiler
.mainmodule
.bool_type
)
892 add
("{res} = {value1}.rtclass == {value2}.rtclass;")
898 # Generate an integer value
899 fun int_instance
(value
: Int): RuntimeVariable do
900 var t
= compiler
.mainmodule
.int_type
901 return new RuntimeVariable(value
.to_s
, t
, t
)
904 # Generate a byte value
905 fun byte_instance
(value
: Byte): RuntimeVariable do
906 var t
= compiler
.mainmodule
.byte_type
907 return new RuntimeVariable(value
.to_s
, t
, t
)
910 # Generate a char value
911 fun char_instance
(value
: Char): RuntimeVariable do
912 var t
= compiler
.mainmodule
.char_type
913 return new RuntimeVariable("'{value.to_s.escape_to_c}'", t
, t
)
916 # Generate a float value
918 # FIXME pass a Float, not a string
919 fun float_instance
(value
: String): RuntimeVariable do
920 var t
= compiler
.mainmodule
.float_type
921 return new RuntimeVariable(value
.to_s
, t
, t
)
924 # Generate an integer value
925 fun bool_instance
(value
: Bool): RuntimeVariable do
926 var t
= compiler
.mainmodule
.bool_type
927 return new RuntimeVariable(value
.to_s
, t
, t
)
930 # Generate the `null` value
931 fun null_instance
: RuntimeVariable do
932 var t
= compiler
.mainmodule
.model
.null_type
933 return new RuntimeVariable("null", t
, t
)
936 # Get an instance of a array for a vararg
937 fun vararg_instance
(mpropdef
: MPropDef, recv
: RuntimeVariable, varargs
: Array[RuntimeVariable], elttype
: MType): RuntimeVariable do
938 # TODO handle dynamic types
939 info
("NOT YET IMPLEMENTED vararg_instance")
941 # TODO return array_instance(varargs, elttype)
946 # Generate a alloc-instance + init-attributes
947 fun init_instance
(mtype
: MClassType): RuntimeVariable do
948 var rt_name
= mtype
.mclass
.rt_name
949 var res
= new_expr
("new RTVal({rt_name}.get{rt_name}())", mtype
)
950 generate_init_attr
(self, res
, mtype
)
954 # Generate code that initialize the attributes on a new instance
955 fun generate_init_attr
(v
: JavaCompilerVisitor, recv
: RuntimeVariable, mtype
: MClassType) do
956 var cds
= mtype
.collect_mclassdefs
(v
.compiler
.mainmodule
).to_a
957 v
.compiler
.mainmodule
.linearize_mclassdefs
(cds
)
959 for npropdef
in v
.compiler
.modelbuilder
.collect_attr_propdef
(cd
) do
960 npropdef
.init_expr
(v
, recv
)
965 # Generate a Nit "is" for two runtime_variables
966 fun equal_test
(value1
, value2
: RuntimeVariable): RuntimeVariable do
967 var res
= new_var
(compiler
.mainmodule
.bool_type
)
968 if value2
.mtype
.is_java_primitive
and not value1
.mtype
.is_java_primitive
then
973 if value1
.mtype
.is_java_primitive
then
974 if value2
.mtype
== value1
.mtype
then
975 add
("{res} = {value1} == {value2}; /* == with two primitives */")
976 else if value2
.mtype
.is_java_primitive
then
977 add
("{res} = true; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
978 # else if value1.mtype.is_tagged then
979 # add("{res} = ({value2} != NULL) && ({autobox(value2, value1.mtype)} == {value1});")
981 var rt_name
= value1
.mtype
.as(MClassType).mclass
.rt_name
982 add
("{res} = ({value2} != null) && ({value2}.rtclass == {rt_name}.get{rt_name}());")
984 add
("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
989 var maybe_null
= true
990 var test
= new Array[String]
991 var t1
= value1
.mcasttype
992 if t1
isa MNullableType then
993 test
.add
("{value1} != null && !{value1}.is_null()")
998 var t2
= value2
.mcasttype
999 if t2
isa MNullableType then
1000 test
.add
("{value2} != null && !{value2}.is_null()")
1006 var incompatible
= false
1008 if t1
.is_java_primitive
then
1011 # No need to compare class
1012 else if t2
.is_java_primitive
then
1014 else if can_be_primitive
(value2
) then
1015 if t1
.is_java_primitive
then
1016 self.add
("{res} = {value1} == {value2}; /* t1 is primitive and t2 can be */")
1019 # if not compiler.modelbuilder.toolcontext.opt_no_tag_primitives.value then
1020 # test.add("(!{extract_tag(value2)})")
1022 test
.add
("{value1}.rtclass == {value2}.rtclass")
1026 else if t2
.is_java_primitive
then
1028 if can_be_primitive
(value1
) then
1029 if t2
.is_java_primitive
then
1030 self.add
("{res} = {value1} == {value2}; /* t2 is primitive and t1 can be */")
1033 test
.add
("{value1}.rtclass == {value2}.rtclass")
1041 if incompatible
then
1043 self.add
("{res} = {value1} == {value2}; /* incompatible types {t1} vs. {t2}; but may be NULL*/")
1046 self.add
("{res} = false; /* incompatible types {t1} vs. {t2}; cannot be NULL */")
1050 if primitive
!= null then
1051 if primitive
.is_java_primitive
then
1052 self.add
("{res} = {value1} == {value2};")
1055 test
.add
("({value1}.value == {value2}.value")
1056 else if can_be_primitive
(value1
) and can_be_primitive
(value2
) then
1057 test
.add
("{value1}.rtclass == {value2}.rtclass")
1058 var s
= new Array[String]
1059 for b
in compiler
.box_kinds
do
1060 var rt_name
= b
.mclass
.rt_name
1061 s
.add
"({value1}.rtclass == {rt_name}.get{rt_name}()) && ({value1}.value.equals({value2}.value))"
1062 if b
.mclass
.name
== "Float" then
1063 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)"
1067 self.add
("{res} = {value1} == {value2}; /* both can be primitive */")
1070 test
.add
("({s.join(" || ")})")
1072 self.add
("{res} = {value1} == {value2}; /* no primitives */")
1075 self.add
("{res} = {value1} == {value2} || ({test.join(" && ")});")
1081 # Generate a polymorphic attribute is_set test
1082 fun isset_attribute
(a
: MAttribute, recv
: RuntimeVariable): RuntimeVariable do
1083 # TODO self.check_recv_notnull(recv)
1084 var res
= new_var
(compiler
.mainmodule
.bool_type
)
1086 # What is the declared type of the attribute?
1087 var mtype
= a
.intro
.static_mtype
.as(not null)
1088 var intromclassdef
= a
.intro
.mclassdef
1089 mtype
= mtype
.resolve_for
(intromclassdef
.bound_mtype
, intromclassdef
.bound_mtype
, intromclassdef
.mmodule
, true)
1091 if mtype
isa MNullableType then
1092 add
("{res} = true; /* easy isset: {a} on {recv.inspect} */")
1095 add
("{res} = {recv}.attrs.get(\"{a.jname}\
") != null; /* {a} on {recv.inspect} */")
1099 # Generate a polymorphic attribute read
1100 fun read_attribute
(a
: MAttribute, recv
: RuntimeVariable): RuntimeVariable do
1101 # TODO check_recv_notnull(recv)
1102 # TODO compile_check(v)
1103 # What is the declared type of the attribute?
1104 var ret
= a
.intro
.static_mtype
.as(not null)
1105 var intromclassdef
= a
.intro
.mclassdef
1106 ret
= ret
.resolve_for
(intromclassdef
.bound_mtype
, intromclassdef
.bound_mtype
, intromclassdef
.mmodule
, true)
1108 # Check for Uninitialized attribute
1109 if not ret
isa MNullableType then check_attribute
(a
, recv
)
1111 return new_expr
("{recv}.attrs.get(\"{a.jname}\
")", ret
)
1114 # Generate a polymorphic attribute write
1115 fun write_attribute
(a
: MAttribute, recv
: RuntimeVariable, value
: RuntimeVariable) do
1116 # TODO check_recv_notnull(recv)
1117 add
"{recv}.attrs.put(\"{a.jname}\
", {autobox(value, compiler.mainmodule.object_type)});"
1120 # Check uninitialized attribute
1121 fun check_attribute
(a
: MAttribute, recv
: RuntimeVariable) do
1122 add
"if({recv}.attrs.get(\"{a.jname}\
") == null) \{"
1123 add_abort
"Uninitialized attribute {a.name}"
1129 # Display a info message
1130 fun info
(str
: String) do compiler
.modelbuilder
.toolcontext
.info
(str
, 0)
1133 # A file containing Java code.
1137 var filename
: String
1140 var lines
: List[String] = new List[String]
1144 # A Java compatible name for `self`
1145 private fun jname
: String do return name
.to_cmangle
1148 # Handler for runtime classes generation
1150 # We need 3 kinds of runtime structures:
1151 # * `RTClass` to represent a global class
1152 # * `RTMethod` to represent a method definition
1153 # * `RTVal` to represent runtime variables
1154 class JavaRuntimeModel
1156 # Compile JavaRuntimeModel structures
1157 fun compile_rtmodel
(compiler
: JavaCompiler) do
1158 compile_rtclass
(compiler
)
1159 compile_rtmethod
(compiler
)
1160 compile_rtval
(compiler
)
1163 # Compile the abstract runtime class structure
1165 # Runtime classes have 3 attributes:
1166 # * `class_name`: the class name as a String
1167 # * `vft`: the virtual function table for the class (flattened)
1168 # * `supers`: the super type table (used for type tests)
1169 fun compile_rtclass
(compiler
: JavaCompiler) do
1170 var v
= compiler
.new_visitor
("RTClass.java")
1171 v
.add
("import java.util.HashMap;")
1172 v
.add
("public abstract class RTClass \{")
1173 v
.add
(" public String class_name;")
1174 v
.add
(" public HashMap<String, RTMethod> vft = new HashMap<>();")
1175 v
.add
(" public HashMap<String, RTClass> supers = new HashMap<>();")
1176 v
.add
(" protected RTClass() \{\}")
1180 # Compile the abstract runtime method structure
1182 # Method body is executed through the `exec` method:
1183 # * `exec` always take an array of RTVal as arg, the first one must be the receiver
1184 # * `exec` always returns a RTVal (or null if the Nit return type is void)
1185 fun compile_rtmethod
(compiler
: JavaCompiler) do
1186 var v
= compiler
.new_visitor
("RTMethod.java")
1187 v
.add
("public abstract class RTMethod \{")
1188 v
.add
(" protected RTMethod() \{\}")
1189 v
.add
(" public abstract RTVal exec(RTVal[] args);")
1193 # Compile the runtime value structure
1195 # RTVal both represents object instances and primitives values:
1196 # * object instances:
1197 # * `rtclass` the class of the RTVal is instance of
1198 # * `attrs` contains the attributes of the instance
1199 # * primitive values:
1200 # * `rtclass` represents the class of the primitive value Nit type
1201 # * `value` contains the primitive value of the instance
1203 # * they must have both `rtclass` and `value` as null
1204 fun compile_rtval
(compiler
: JavaCompiler) do
1205 var v
= compiler
.new_visitor
("RTVal.java")
1206 v
.add
("import java.util.HashMap;")
1207 v
.add
("public class RTVal \{")
1208 v
.add
(" public RTClass rtclass;")
1209 v
.add
(" public HashMap<String, RTVal> attrs = new HashMap<>();")
1210 v
.add
(" Object value;")
1211 v
.add
(" public RTVal(RTClass rtclass) \{")
1212 v
.add
(" this.rtclass = rtclass;")
1214 v
.add
(" public RTVal(RTClass rtclass, Object value) \{")
1215 v
.add
(" this.rtclass = rtclass;")
1216 v
.add
(" this.value = value;")
1218 v
.add
(" public boolean is_null() \{ return rtclass == null && value == null; \}")
1223 # A runtime variable hold a runtime value in Java.
1224 # Runtime variables are associated to Nit local variables and intermediate results in Nit expressions.
1225 class RuntimeVariable
1227 # The name of the variable in the Java code
1230 # The static type of the variable (as declard in Java)
1233 # The current casted type of the variable (as known in Nit)
1234 var mcasttype
: MType is writable
1236 # If the variable exaclty a mcasttype?
1237 # false (usual value) means that the variable is a mcasttype or a subtype.
1238 var is_exact
: Bool = false is writable
1240 # Is this variable declared as a RTVal or a Java primitive one?
1241 var is_boxed
= false
1243 redef fun to_s
do return name
1248 if self.is_exact
then
1249 exact_str
= " exact"
1254 if self.mtype
== self.mcasttype
then
1255 type_str
= "{mtype}{exact_str}"
1257 type_str
= "{mtype}({mcasttype}{exact_str})"
1259 return "<{name}:{type_str}>"
1263 # The static context of a visited property in a `JavaCompilerVisitor`
1264 class JavaStaticFrame
1265 # The associated visitor
1266 var visitor
: JavaCompilerVisitor
1268 # The executed property.
1269 # A Method in case of a call, an attribute in case of a default initialization.
1270 var mpropdef
: MPropDef
1272 # The static type of the receiver
1273 var receiver
: MClassType
1275 # Arguments of the method (the first is the receiver)
1276 var arguments
: Array[RuntimeVariable]
1278 # The runtime_variable associated to the return (in a function)
1279 var returnvar
: nullable RuntimeVariable = null is writable
1281 # The label at the end of the property
1282 var returnlabel
: nullable String = null is writable
1284 # Labels associated to a each escapemarks.
1285 # Because of inlinings, escape-marks must be associated to their context (the frame)
1286 private var escapemark_names
= new HashMap[EscapeMark, String]
1289 redef class Location
1290 # Return a shortened version of the location with `"{file}:{line_start}"`
1291 fun short_location
: String do
1292 var file
= self.file
1293 if file
== null then return "<no file>:{line_start}"
1294 return "{file.filename.escape_to_c}:{line_start}"
1299 # Return the Java type associated to a given Nit static type
1300 fun java_type
: String do return "RTVal"
1302 # Is the associated Java type a primitive one?
1304 # ENSURE `result == (java_type != "Object")`
1305 var is_java_primitive
: Bool is lazy
do return java_type
!= "RTVal"
1308 redef class MClassType
1310 redef var java_type
is lazy
do
1311 if mclass
.name
== "Int" then
1313 else if mclass
.name
== "Bool" then
1315 else if mclass
.name
== "Char" then
1317 else if mclass
.name
== "Float" then
1319 else if mclass
.name
== "Byte" then
1321 else if mclass
.name
== "NativeString" then
1323 else if mclass
.name
== "NativeArray" then
1333 private fun rt_name
: String do return "RTClass_{intro_mmodule.jname}_{jname}"
1335 # Generate a Java RTClass for a Nit MClass
1336 fun compile_to_java
(v
: JavaCompilerVisitor) do
1337 v
.add
("public class {rt_name} extends RTClass \{")
1338 v
.add
(" protected static RTClass instance;")
1339 v
.add
(" private {rt_name}() \{")
1340 v
.add
(" this.class_name = \"{name}\
";")
1342 compile_type_table
(v
)
1344 v
.add
(" public static RTClass get{rt_name}() \{")
1345 v
.add
(" if(instance == null) \{")
1346 v
.add
(" instance = new {rt_name}();")
1348 v
.add
(" return instance;")
1353 # Compile the virtual function table for the mclass
1354 private fun compile_vft
(v
: JavaCompilerVisitor) do
1355 # TODO handle generics
1356 if mclass_type
.need_anchor
then return
1357 var mclassdefs
= mclass_type
.collect_mclassdefs
(v
.compiler
.mainmodule
).to_a
1358 v
.compiler
.mainmodule
.linearize_mclassdefs
(mclassdefs
)
1360 var mainmodule
= v
.compiler
.mainmodule
1361 for mclassdef
in mclassdefs
.reversed
do
1362 for mprop
in mclassdef
.intro_mproperties
do
1363 var mpropdef
= mprop
.lookup_first_definition
(mainmodule
, intro
.bound_mtype
)
1364 if not mpropdef
isa MMethodDef then continue
1365 var rt_name
= mpropdef
.rt_name
1366 v
.add
("this.vft.put(\"{mprop.full_name}\
", {rt_name}.get{rt_name}());")
1368 # fill super next definitions
1369 while mpropdef
.has_supercall
do
1370 var prefix
= mpropdef
.full_name
1371 mpropdef
= mpropdef
.lookup_next_definition
(mainmodule
, intro
.bound_mtype
)
1372 rt_name
= mpropdef
.rt_name
1373 v
.add
("this.vft.put(\"{prefix}\
", {rt_name}.get{rt_name}());")
1379 # Compile the type table for the MClass
1380 fun compile_type_table
(v
: JavaCompilerVisitor) do
1381 for pclass
in in_hierarchy
(v
.compiler
.mainmodule
).greaters
do
1382 if pclass
== self then
1383 v
.add
("supers.put(\"{pclass.jname}\
", this);")
1385 v
.add
("supers.put(\"{pclass.jname}\
", {pclass.rt_name}.get{pclass.rt_name}());")
1391 # Used as a common type between MMethod and MMethodDef for `table_send`
1392 private interface TableCallable
1399 redef class MMethodDef
1403 private fun rt_name
: String do
1404 return "RTMethod_{mclassdef.mmodule.jname}_{mclassdef.mclass.jname}_{mproperty.jname}"
1407 # Generate a Java RTMethod for `self`
1408 fun compile_to_java
(v
: JavaCompilerVisitor) do
1409 v
.add
("public class {rt_name} extends RTMethod \{")
1410 v
.add
(" protected static RTMethod instance;")
1411 v
.add
(" public static RTMethod get{rt_name}() \{")
1412 v
.add
(" if(instance == null) \{")
1413 v
.add
(" instance = new {rt_name}();")
1415 v
.add
(" return instance;")
1418 v
.add
(" public RTVal exec(RTVal[] args) \{")
1419 compile_inside_to_java
(v
)
1424 # Compile the body of this function
1425 fun compile_inside_to_java
(v
: JavaCompilerVisitor) do
1427 var modelbuilder
= v
.compiler
.modelbuilder
1428 var node
= modelbuilder
.mpropdef2node
(self)
1430 var recv
= mclassdef
.bound_mtype
1431 var arguments
= new Array[RuntimeVariable]
1432 var frame
= new JavaStaticFrame(v
, self, recv
, arguments
)
1435 var selfvar
= v
.decl_var
("self", recv
)
1436 arguments
.add
(selfvar
)
1437 var boxed
= v
.new_expr
("args[0]", v
.compiler
.mainmodule
.object_type
)
1438 v
.add
"{selfvar} = {v.autobox(boxed, recv)};"
1440 var msignature
= self.msignature
1442 if msignature
!= null then
1443 ret
= msignature
.return_mtype
1445 var retvar
= v
.decl_var
("ret", ret
)
1446 if ret
.name
== "Int" then v
.add
"{retvar} = 0;"
1447 if ret
.name
== "Float" then v
.add
"{retvar} = 0.0;"
1448 if ret
.name
== "Bool" then v
.add
"{retvar} = false;"
1449 if ret
.name
== "Char" then v
.add
"{retvar} = 0;"
1450 if ret
.name
== "Byte" then v
.add
"{retvar} = 0;"
1451 frame
.returnvar
= retvar
1454 frame
.returnlabel
= v
.get_name
("RET_LABEL")
1456 v
.current_node
= node
1458 v
.add_abort
("Abstract method `{mproperty.name}` called on `\" + {selfvar}.rtclass
.class_name
+\
"`")
1459 v
.add
("return null;")
1462 v
.current_node
= null
1464 v
.add
("{frame.returnlabel.as(not null)}: \{")
1466 if node
isa APropdef then
1467 node
.compile_to_java
(v
, self, arguments
)
1468 else if node
isa AClassdef then
1469 node
.compile_to_java
(v
, self, arguments
)
1476 v
.add
("return {v.autobox(frame.returnvar.as(not null), v.compiler.mainmodule.object_type)};")
1478 v
.add
("return null;")
1483 redef class AClassdef
1484 private fun compile_to_java
(v
: JavaCompilerVisitor, mpropdef
: MMethodDef, arguments
: Array[RuntimeVariable]) do
1485 if mpropdef
== self.mfree_init
then
1486 assert mpropdef
.mproperty
.is_root_init
1487 if not mpropdef
.is_intro
then
1488 v
.supercall
(mpropdef
, arguments
.first
.mtype
.as(MClassType), arguments
)
1496 redef class APropdef
1498 # Compile that property definition to java code
1499 fun compile_to_java
(v
: JavaCompilerVisitor, mpropdef
: MMethodDef, arguments
: Array[RuntimeVariable]) do
1500 v
.info
("NOT YET IMPLEMENTED {class_name}::compile_to_java")
1504 redef class AMethPropdef
1505 redef fun compile_to_java
(v
, mpropdef
, arguments
) do
1506 if mpropdef
.msignature
!= null then
1508 for mparam
in mpropdef
.msignature
.as(not null).mparameters
do
1509 var variable
= n_signature
.as(not null).n_params
[i
].variable
1510 if variable
== null then continue
1511 var argvar
= v
.variable
(variable
)
1512 v
.assign
(argvar
, v
.new_expr
("args[{i + 1}]", v
.compiler
.mainmodule
.object_type
))
1513 arguments
.add
(argvar
)
1518 # Call the implicit super-init
1519 var auto_super_inits
= self.auto_super_inits
1520 if auto_super_inits
!= null then
1521 var args
= [arguments
.first
]
1522 for auto_super_init
in auto_super_inits
do
1523 assert auto_super_init
.mproperty
!= mpropdef
.mproperty
1525 for i
in [0..auto_super_init
.msignature
.arity
+1[ do
1526 args
.add
(arguments
[i
])
1528 assert auto_super_init
.mproperty
!= mpropdef
.mproperty
1529 v
.compile_callsite
(auto_super_init
, args
)
1532 if auto_super_call
then
1533 v
.supercall
(mpropdef
, arguments
.first
.mtype
.as(MClassType), arguments
)
1536 compile_inside_to_java
(v
, mpropdef
, arguments
)
1539 # Compile the inside of the method body
1540 private fun compile_inside_to_java
(v
: JavaCompilerVisitor, mpropdef
: MMethodDef, arguments
: Array[RuntimeVariable]) do
1541 # Compile intern methods
1542 if mpropdef
.is_intern
then
1543 if compile_intern_to_java
(v
, mpropdef
, arguments
) then return
1544 v
.info
("NOT YET IMPLEMENTED compile_intern for {mpropdef}")
1545 v
.ret
(v
.null_instance
)
1549 # Compile block if any
1550 var n_block
= n_block
1551 if n_block
!= null then
1557 # Compile an intern method using Java primitives
1558 fun compile_intern_to_java
(v
: JavaCompilerVisitor, mpropdef
: MMethodDef, arguments
: Array[RuntimeVariable]): Bool do
1559 var pname
= mpropdef
.mproperty
.name
1560 var cname
= mpropdef
.mclassdef
.mclass
.name
1561 var ret
= mpropdef
.msignature
.as(not null).return_mtype
1562 if cname
== "Int" then
1563 if pname
== "output" then
1564 v
.add
("System.out.println({arguments[0]});")
1565 v
.ret
(v
.null_instance
)
1567 else if pname
== "object_id" then
1568 v
.ret
(arguments
.first
)
1570 else if pname
== "+" then
1571 v
.ret
(v
.new_expr
("{arguments[0]} + {arguments[1]}", ret
.as(not null)))
1573 else if pname
== "-" then
1574 v
.ret
(v
.new_expr
("{arguments[0]} - {arguments[1]}", ret
.as(not null)))
1576 else if pname
== "unary -" then
1577 v
.ret
(v
.new_expr
("-{arguments[0]}", ret
.as(not null)))
1579 else if pname
== "unary +" then
1582 else if pname
== "*" then
1583 v
.ret
(v
.new_expr
("{arguments[0]} * {arguments[1]}", ret
.as(not null)))
1585 else if pname
== "/" then
1586 v
.ret
(v
.new_expr
("{arguments[0]} / {arguments[1]}", ret
.as(not null)))
1588 else if pname
== "%" then
1589 v
.ret
(v
.new_expr
("{arguments[0]} % {arguments[1]}", ret
.as(not null)))
1591 else if pname
== "<<" then
1592 v
.ret
(v
.new_expr
("{arguments[0]} << {arguments[1]}", ret
.as(not null)))
1594 else if pname
== ">>" then
1595 v
.ret
(v
.new_expr
("{arguments[0]} >> {arguments[1]}", ret
.as(not null)))
1597 else if pname
== "==" then
1598 v
.ret
(v
.equal_test
(arguments
[0], arguments
[1]))
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)))
1604 else if pname
== "<" then
1605 v
.ret
(v
.new_expr
("{arguments[0]} < {arguments[1]}", ret
.as(not null)))
1607 else if pname
== ">" then
1608 v
.ret
(v
.new_expr
("{arguments[0]} > {arguments[1]}", ret
.as(not null)))
1610 else if pname
== "<=" then
1611 v
.ret
(v
.new_expr
("{arguments[0]} <= {arguments[1]}", ret
.as(not null)))
1613 else if pname
== ">=" then
1614 v
.ret
(v
.new_expr
("{arguments[0]} >= {arguments[1]}", ret
.as(not null)))
1616 else if pname
== "to_f" then
1617 v
.ret
(v
.new_expr
("(double){arguments[0]}", ret
.as(not null)))
1619 else if pname
== "to_b" then
1620 v
.ret
(v
.new_expr
("(byte){arguments[0]}", ret
.as(not null)))
1622 else if pname
== "ascii" then
1623 v
.ret
(v
.new_expr
("(char){arguments[0]}", ret
.as(not null)))
1626 else if cname
== "Char" then
1627 if pname
== "output" then
1628 v
.add
("System.out.print({arguments[0]});")
1629 v
.ret
(v
.null_instance
)
1631 else if pname
== "object_id" then
1632 v
.ret
(v
.new_expr
("(int){arguments[0]}", ret
.as(not null)))
1634 else if pname
== "successor" then
1635 v
.ret
(v
.new_expr
("(char)({arguments[0]} + {arguments[1]})", ret
.as(not null)))
1637 else if pname
== "predecessor" then
1638 v
.ret
(v
.new_expr
("(char)({arguments[0]} - {arguments[1]})", ret
.as(not null)))
1640 else if pname
== "==" then
1641 v
.ret
(v
.equal_test
(arguments
[0], arguments
[1]))
1643 else if pname
== "!=" then
1644 var res
= v
.equal_test
(arguments
[0], arguments
[1])
1645 v
.ret
(v
.new_expr
("!{res}", ret
.as(not null)))
1647 else if pname
== "<" then
1648 v
.ret
(v
.new_expr
("{arguments[0]} < {arguments[1]}", ret
.as(not null)))
1650 else if pname
== ">" then
1651 v
.ret
(v
.new_expr
("{arguments[0]} > {arguments[1]}", ret
.as(not null)))
1653 else if pname
== "<=" then
1654 v
.ret
(v
.new_expr
("{arguments[0]} <= {arguments[1]}", ret
.as(not null)))
1656 else if pname
== ">=" then
1657 v
.ret
(v
.new_expr
("{arguments[0]} >= {arguments[1]}", ret
.as(not null)))
1659 else if pname
== "to_i" then
1660 v
.ret
(v
.new_expr
("(int){arguments[0]}", ret
.as(not null)))
1662 else if pname
== "ascii" then
1663 v
.ret
(v
.new_expr
("(int){arguments[0]}", ret
.as(not null)))
1666 else if cname
== "Byte" then
1667 if pname
== "output" then
1668 v
.add
("System.out.println({arguments[0]});")
1669 v
.ret
(v
.null_instance
)
1671 else if pname
== "object_id" then
1672 v
.ret
(v
.new_expr
("(int){arguments[0]}", ret
.as(not null)))
1674 else if pname
== "+" then
1675 v
.ret
(v
.new_expr
("(byte)({arguments[0]} + {arguments[1]})", ret
.as(not null)))
1677 else if pname
== "-" then
1678 v
.ret
(v
.new_expr
("(byte)({arguments[0]} - {arguments[1]})", ret
.as(not null)))
1680 else if pname
== "unary -" then
1681 v
.ret
(v
.new_expr
("(byte)(-{arguments[0]})", ret
.as(not null)))
1683 else if pname
== "unary +" then
1686 else if pname
== "*" then
1687 v
.ret
(v
.new_expr
("(byte)({arguments[0]} * {arguments[1]})", ret
.as(not null)))
1689 else if pname
== "/" then
1690 v
.ret
(v
.new_expr
("(byte)({arguments[0]} / {arguments[1]})", ret
.as(not null)))
1692 else if pname
== "%" then
1693 v
.ret
(v
.new_expr
("(byte)({arguments[0]} % {arguments[1]})", ret
.as(not null)))
1695 else if pname
== "<<" then
1696 v
.ret
(v
.new_expr
("(byte)({arguments[0]} << {arguments[1]})", ret
.as(not null)))
1698 else if pname
== ">>" then
1699 v
.ret
(v
.new_expr
("(byte)({arguments[0]} >> {arguments[1]})", ret
.as(not null)))
1701 else if pname
== "==" then
1702 v
.ret
(v
.equal_test
(arguments
[0], arguments
[1]))
1704 else if pname
== "!=" then
1705 var res
= v
.equal_test
(arguments
[0], arguments
[1])
1706 v
.ret
(v
.new_expr
("!{res}", ret
.as(not null)))
1708 else if pname
== "<" then
1709 v
.ret
(v
.new_expr
("{arguments[0]} < {arguments[1]}", ret
.as(not null)))
1711 else if pname
== ">" then
1712 v
.ret
(v
.new_expr
("{arguments[0]} > {arguments[1]}", ret
.as(not null)))
1714 else if pname
== "<=" then
1715 v
.ret
(v
.new_expr
("{arguments[0]} <= {arguments[1]}", ret
.as(not null)))
1717 else if pname
== ">=" then
1718 v
.ret
(v
.new_expr
("{arguments[0]} >= {arguments[1]}", ret
.as(not null)))
1720 else if pname
== "to_i" then
1721 v
.ret
(v
.new_expr
("(int){arguments[0]}", ret
.as(not null)))
1723 else if pname
== "to_f" then
1724 v
.ret
(v
.new_expr
("(double){arguments[0]}", ret
.as(not null)))
1726 else if pname
== "ascii" then
1727 v
.ret
(v
.new_expr
("{arguments[0]}", ret
.as(not null)))
1730 else if cname
== "Bool" then
1731 if pname
== "output" then
1732 v
.add
("System.out.println({arguments[0]});")
1733 v
.ret
(v
.null_instance
)
1735 else if pname
== "object_id" then
1736 v
.ret
(v
.new_expr
("{arguments[0]}?1:0", ret
.as(not null)))
1738 else if pname
== "==" then
1739 v
.ret
(v
.equal_test
(arguments
[0], arguments
[1]))
1741 else if pname
== "!=" then
1742 var res
= v
.equal_test
(arguments
[0], arguments
[1])
1743 v
.ret
(v
.new_expr
("!{res}", ret
.as(not null)))
1746 else if cname
== "Float" then
1747 if pname
== "output" then
1748 v
.add
"if({arguments[0]} == Double.POSITIVE_INFINITY) \{"
1749 v
.add
"System.out.println(\"inf\
");"
1750 v
.add
"\} else if({arguments[0]} == Double.POSITIVE_INFINITY) \{"
1751 v
.add
"System.out.println(\"-inf\
");"
1753 var df
= v
.get_name
("df")
1754 v
.add
"java.text.DecimalFormat {df} = new java.text.DecimalFormat(\"0.000000\
");"
1755 v
.add
"System.out.println({df}.format({arguments[0]}));"
1757 v
.ret
(v
.null_instance
)
1759 else if pname
== "object_id" then
1760 v
.ret
(v
.new_expr
("(int){arguments[0]}", ret
.as(not null)))
1762 else if pname
== "+" then
1763 v
.ret
(v
.new_expr
("{arguments[0]} + {arguments[1]}", ret
.as(not null)))
1765 else if pname
== "-" then
1766 v
.ret
(v
.new_expr
("{arguments[0]} - {arguments[1]}", ret
.as(not null)))
1768 else if pname
== "unary -" then
1769 v
.ret
(v
.new_expr
("-{arguments[0]}", ret
.as(not null)))
1771 else if pname
== "unary +" then
1774 else if pname
== "succ" then
1775 v
.ret
(v
.new_expr
("{arguments[0]} + 1", ret
.as(not null)))
1777 else if pname
== "prec" then
1778 v
.ret
(v
.new_expr
("{arguments[0]} - 1", ret
.as(not null)))
1780 else if pname
== "*" then
1781 v
.ret
(v
.new_expr
("{arguments[0]} * {arguments[1]}", ret
.as(not null)))
1783 else if pname
== "/" then
1784 v
.ret
(v
.new_expr
("{arguments[0]} / {arguments[1]}", ret
.as(not null)))
1786 else if pname
== "==" then
1787 v
.ret
(v
.equal_test
(arguments
[0], arguments
[1]))
1789 else if pname
== "!=" then
1790 var res
= v
.equal_test
(arguments
[0], arguments
[1])
1791 v
.ret
(v
.new_expr
("!{res}", ret
.as(not null)))
1793 else if pname
== "<" then
1794 v
.ret
(v
.new_expr
("{arguments[0]} < {arguments[1]}", ret
.as(not null)))
1796 else if pname
== ">" then
1797 v
.ret
(v
.new_expr
("{arguments[0]} > {arguments[1]}", ret
.as(not null)))
1799 else if pname
== "<=" then
1800 v
.ret
(v
.new_expr
("{arguments[0]} <= {arguments[1]}", ret
.as(not null)))
1802 else if pname
== ">=" then
1803 v
.ret
(v
.new_expr
("{arguments[0]} >= {arguments[1]}", ret
.as(not null)))
1805 else if pname
== "to_i" then
1806 v
.ret
(v
.new_expr
("(int){arguments[0]}", ret
.as(not null)))
1808 else if pname
== "to_b" then
1809 v
.ret
(v
.new_expr
("(byte){arguments[0]}", ret
.as(not null)))
1813 if pname
== "exit" then
1814 v
.add
("System.exit({arguments[1]});")
1815 v
.ret
(v
.null_instance
)
1817 else if pname
== "sys" then
1819 var main_type
= v
.compiler
.mainmodule
.sys_type
.as(not null)
1820 var sys
= main_type
.mclass
1821 v
.ret
(v
.new_expr
("new RTVal({sys.rt_name}.get{sys.rt_name}())", main_type
))
1823 else if pname
== "object_id" then
1824 v
.ret
(v
.new_expr
("{arguments[0]}.hashCode()", ret
.as(not null)))
1826 else if pname
== "is_same_type" then
1827 v
.ret
(v
.is_same_type_test
(arguments
[0], arguments
[1]))
1829 else if pname
== "is_same_instance" then
1830 v
.ret
(v
.equal_test
(arguments
[0], arguments
[1]))
1832 else if pname
== "output_class_name" then
1833 v
.add
("System.out.println({arguments[0]}.rtclass.class_name);")
1834 v
.ret
(v
.null_instance
)
1841 redef class AAttrPropdef
1842 redef fun compile_to_java
(v
, mpropdef
, arguments
) do
1843 v
.current_node
= self
1844 if mpropdef
== mreadpropdef
then
1845 compile_getter
(v
, mpropdef
, arguments
)
1846 else if mpropdef
== mwritepropdef
then
1847 compile_setter
(v
, mpropdef
, arguments
)
1851 v
.current_node
= null
1854 # Compile the setter method
1855 private fun compile_setter
(v
: JavaCompilerVisitor, mpropdef
: MPropDef, arguments
: Array[RuntimeVariable]) do
1856 var mtype
= v
.compiler
.mainmodule
.object_type
1857 var recv
= arguments
.first
1858 var val
= v
.new_expr
("args[1]", mtype
)
1859 v
.write_attribute
(self.mpropdef
.as(not null).mproperty
, recv
, val
)
1860 v
.ret v
.null_instance
1863 # Compile the getter method
1864 private fun compile_getter
(v
: JavaCompilerVisitor, mpropdef
: MPropDef, arguments
: Array[RuntimeVariable]) do
1865 var recv
= arguments
.first
1866 v
.ret v
.read_attribute
(self.mpropdef
.as(not null).mproperty
, recv
)
1869 private fun init_expr
(v
: JavaCompilerVisitor, recv
: RuntimeVariable) do
1870 if has_value
and not is_lazy
and not n_expr
isa ANullExpr then evaluate_expr
(v
, recv
)
1873 # Evaluate, store and return the default value of the attribute
1874 private fun evaluate_expr
(v
: JavaCompilerVisitor, recv
: RuntimeVariable): RuntimeVariable do
1876 var frame
= new JavaStaticFrame(v
, self.mreadpropdef
.as(not null), recv
.mcasttype
.undecorate
.as(MClassType), [recv
])
1880 var mtype
= self.mtype
1881 assert mtype
!= null
1883 var nexpr
= self.n_expr
1884 var nblock
= self.n_block
1885 if nexpr
!= null then
1886 value
= v
.expr
(nexpr
, mtype
)
1887 else if nblock
!= null then
1888 value
= v
.new_var
(mtype
)
1889 frame
.returnvar
= value
1890 frame
.returnlabel
= v
.get_name
("RET_LABEL")
1891 v
.add
("{frame.returnlabel.as(not null)}: \{")
1898 v
.write_attribute
(self.mpropdef
.as(not null).mproperty
, recv
, value
)
1905 # Try to compile self as an expression
1906 # Do not call this method directly, use `v.expr` instead
1907 private fun expr
(v
: JavaCompilerVisitor): nullable RuntimeVariable do
1908 v
.info
("NOT YET IMPLEMENTED {class_name}::expr")
1912 # Try to compile self as a statement
1913 # Do not call this method directly, use `v.stmt` instead
1914 private fun stmt
(v
: JavaCompilerVisitor) do expr
(v
)
1917 redef class ABlockExpr
1920 for e
in self.n_expr
do v
.stmt
(e
)
1924 var last
= self.n_expr
.last
1925 for e
in self.n_expr
do
1926 if e
== last
then break
1929 return v
.expr
(last
, null)
1933 redef class ASendExpr
1934 redef fun expr
(v
) do
1935 var recv
= v
.expr
(n_expr
, null)
1936 var callsite
= callsite
.as(not null)
1937 var args
= v
.varargize
(callsite
.mpropdef
, callsite
.signaturemap
, recv
, raw_arguments
)
1938 return v
.compile_callsite
(callsite
, args
)
1942 redef class ANewExpr
1945 var mtype
= self.recvtype
1946 assert mtype
!= null
1948 if mtype
.mclass
.name
== "NativeArray" then
1949 # TODO handle native arrays
1950 v
.info
("NOT YET IMPLEMENTED new NativeArray")
1953 var recv
= v
.init_instance
(mtype
)
1955 var callsite
= self.callsite
1956 if callsite
== null then return recv
1958 var args
= v
.varargize
(callsite
.mpropdef
, callsite
.signaturemap
, recv
, self.n_args
.n_exprs
)
1959 var res2
= v
.compile_callsite
(callsite
, args
)
1960 if res2
!= null then
1967 redef class ASuperExpr
1971 assert frame
!= null
1972 var recv
= frame
.arguments
.first
1974 var callsite
= self.callsite
1975 if callsite
!= null then
1978 if self.n_args
.n_exprs
.is_empty
then
1979 # Add automatic arguments for the super init call
1981 for i
in [0..callsite
.msignature
.arity
[ do
1982 args
.add
(frame
.arguments
[i
+1])
1985 args
= v
.varargize
(callsite
.mpropdef
, callsite
.signaturemap
, recv
, self.n_args
.n_exprs
)
1989 var res
= v
.compile_callsite
(callsite
, args
)
1993 var mpropdef
= self.mpropdef
.as(not null)
1996 if self.n_args
.n_exprs
.is_empty
then
1997 args
= frame
.arguments
1999 args
= v
.varargize
(mpropdef
, signaturemap
, recv
, self.n_args
.n_exprs
)
2002 # Standard call-next-method
2003 return v
.supercall
(mpropdef
, recv
.mtype
.as(MClassType), args
)
2007 redef class ASelfExpr
2008 redef fun expr
(v
) do return v
.frame
.as(not null).arguments
.first
2011 redef class AImplicitSelfExpr
2012 redef fun expr
(v
) do return v
.frame
.as(not null).arguments
.first
2015 redef class AAttrExpr
2016 redef fun expr
(v
) do
2017 var recv
= v
.expr
(self.n_expr
, null)
2018 var mproperty
= self.mproperty
.as(not null)
2019 return v
.read_attribute
(mproperty
, recv
)
2023 redef class AAttrAssignExpr
2024 redef fun expr
(v
) do
2025 var recv
= v
.expr
(self.n_expr
, null)
2026 var i
= v
.expr
(self.n_value
, null)
2027 var mproperty
= self.mproperty
.as(not null)
2028 v
.write_attribute
(mproperty
, recv
, i
)
2033 redef class AAttrReassignExpr
2034 redef fun stmt
(v
) do
2035 var recv
= v
.expr
(self.n_expr
, null)
2036 var value
= v
.expr
(self.n_value
, null)
2037 var mproperty
= self.mproperty
.as(not null)
2038 var attr
= v
.read_attribute
(mproperty
, recv
)
2039 var res
= v
.compile_callsite
(self.reassign_callsite
.as(not null), [attr
, value
])
2041 v
.write_attribute
(mproperty
, recv
, res
)
2045 redef class AIssetAttrExpr
2046 redef fun expr
(v
) do
2047 var recv
= v
.expr
(self.n_expr
, null)
2048 var mproperty
= self.mproperty
.as(not null)
2049 return v
.isset_attribute
(mproperty
, recv
)
2053 redef class AReturnExpr
2054 redef fun stmt
(v
) do
2055 var nexpr
= self.n_expr
2057 assert frame
!= null
2058 if nexpr
!= null then
2059 v
.ret
(v
.expr
(nexpr
, frame
.returnvar
.as(not null).mtype
))
2061 v
.ret
(v
.null_instance
)
2067 redef fun stmt
(v
) do
2068 var cond
= v
.expr_bool
(self.n_expr
)
2069 v
.add
("if ({cond})\{")
2076 redef fun expr
(v
) do
2077 var res
= v
.new_var
(self.mtype
.as(not null))
2078 var cond
= v
.expr_bool
(self.n_expr
)
2079 v
.add
("if ({cond})\{")
2080 v
.assign
(res
, v
.expr
(self.n_then
.as(not null), null))
2082 v
.assign
(res
, v
.expr
(self.n_else
.as(not null), null))
2091 v
.add_escape_label
(break_mark
)
2093 v
.stmt
(self.n_block
)
2098 redef class AWhileExpr
2101 v
.add_escape_label
(break_mark
)
2102 v
.add_escape_label
(continue_mark
)
2104 var cond
= v
.expr_bool
(self.n_expr
)
2105 v
.add
("if (!{cond}) break;")
2106 v
.stmt
(self.n_block
)
2111 redef class ALoopExpr
2114 v
.add_escape_label
(break_mark
)
2115 v
.add_escape_label
(continue_mark
)
2117 v
.stmt
(self.n_block
)
2122 redef class AEscapeExpr
2123 redef fun stmt
(v
) do v
.add
("break BREAK_{v.escapemark_name(escapemark)};")
2126 redef class AVardeclExpr
2127 redef fun stmt
(v
) do
2128 var variable
= self.variable
.as(not null)
2129 var ne
= self.n_expr
2130 var decl
= v
.variable
(variable
)
2132 var i
= v
.expr
(ne
, variable
.declared_type
)
2138 redef class AVarExpr
2139 redef fun expr
(v
) do
2140 return v
.variable
(self.variable
.as(not null))
2144 redef class AVarAssignExpr
2145 redef fun expr
(v
) do
2146 var variable
= self.variable
.as(not null)
2147 var i
= v
.expr
(self.n_value
, variable
.declared_type
)
2148 v
.assign
(v
.variable
(variable
), i
)
2154 redef class AAssertExpr
2155 redef fun stmt
(v
) do
2156 var cond
= v
.expr_bool
(self.n_expr
)
2157 v
.add
("if (!{cond}) \{")
2161 v
.add_abort
("Assert '{nid.text}' failed")
2163 v
.add_abort
("Assert failed")
2169 redef class AImpliesExpr
2170 redef fun expr
(v
) do
2171 var res
= v
.new_var
(mtype
.as(not null))
2172 var i1
= v
.expr_bool
(n_expr
)
2173 v
.add
("if (!{i1}) \{")
2174 v
.add
("{res} = true;")
2176 var i2
= v
.expr_bool
(n_expr2
)
2177 v
.add
("{res} = {i2};")
2183 redef class AOrElseExpr
2186 var res
= v
.new_var
(self.mtype
.as(not null))
2187 var i1
= v
.expr
(self.n_expr
, null)
2188 v
.add
("if ({i1} != null && !{i1}.is_null()) \{")
2191 var i2
= v
.expr
(self.n_expr2
, null)
2199 redef fun expr
(v
) do
2200 var res
= v
.new_var
(self.mtype
.as(not null))
2201 var i1
= v
.expr_bool
(self.n_expr
)
2202 v
.add
("if ({i1}) \{")
2203 v
.add
("{res} = true;")
2205 var i2
= v
.expr_bool
(self.n_expr2
)
2206 v
.add
("{res} = {i2};")
2212 redef class AAndExpr
2213 redef fun expr
(v
) do
2214 var res
= v
.new_var
(self.mtype
.as(not null))
2215 var i1
= v
.expr_bool
(self.n_expr
)
2216 v
.add
("if (!{i1}) \{")
2217 v
.add
("{res} = false;")
2219 var i2
= v
.expr_bool
(self.n_expr2
)
2220 v
.add
("{res} = {i2};")
2226 redef class ANotExpr
2227 redef fun expr
(v
) do
2228 var cond
= v
.expr_bool
(self.n_expr
)
2229 return v
.new_expr
("!{cond}", self.mtype
.as(not null))
2233 redef class AIntegerExpr
2234 redef fun expr
(v
) do
2235 if value
isa Int then
2236 return v
.int_instance
(self.value
.as(Int))
2237 else if value
isa Byte then
2238 return v
.byte_instance
(self.value
.as(Byte))
2246 redef class AFloatExpr
2247 redef fun expr
(v
) do return v
.float_instance
("{self.n_float.text}") # FIXME use value, not n_float
2250 redef class ACharExpr
2251 redef fun expr
(v
) do return v
.char_instance
(self.value
.as(not null))
2254 redef class ATrueExpr
2255 redef fun expr
(v
) do return v
.bool_instance
(true)
2258 redef class AFalseExpr
2259 redef fun expr
(v
) do return v
.bool_instance
(false)
2262 redef class ANullExpr
2263 redef fun expr
(v
) do return v
.null_instance
2266 redef class AAsCastExpr
2269 var i
= v
.expr
(n_expr
, null)
2270 v
.add_cast
(i
, mtype
.as(not null))
2275 redef class AAsNotnullExpr
2276 redef fun expr
(v
) do
2277 var i
= v
.expr
(n_expr
, null)
2278 if i
.mtype
.is_java_primitive
then return i
2280 v
.add
("if ({i} == null || {i}.is_null()) \{")
2281 v
.add_abort
("Cast failed")
2287 redef class AIsaExpr
2290 var i
= v
.expr
(self.n_expr
, null)
2291 var cast_type
= self.cast_type
2292 if cast_type
== null then return null # no-no on broken node
2293 return v
.type_test
(i
, cast_type
)
2297 redef class AParExpr
2298 redef fun expr
(v
) do return v
.expr
(self.n_expr
, null)
2301 redef class AAbortExpr
2302 redef fun stmt
(v
) do v
.add_abort
("Aborted")
2305 redef class ADebugTypeExpr
2306 redef fun stmt
(v
) do end # do nothing