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
30 redef class ToolContext
32 # Where to output the generated binary
33 var opt_output
= new OptionString("Output file", "-o", "--output")
35 # Where to output tmp files
36 var opt_compile_dir
= new OptionString("Directory used to generate temporary files", "--compile-dir")
40 option_context
.add_option
(opt_output
, opt_compile_dir
)
44 redef class ModelBuilder
46 # Start the Java compiler
47 fun run_java_compiler
(mainmodule
: MModule, runtime_type_analysis
: RapidTypeAnalysis) do
49 toolcontext
.info
("*** GENERATING JAVA ***", 1)
51 var compiler
= new JavaCompiler(mainmodule
, self, runtime_type_analysis
)
52 compiler
.do_compilation
55 toolcontext
.info
("*** END GENERATING JAVA: {time1-time0} ***", 2)
56 write_and_make
(compiler
)
59 # Write Java code and compile it into an executable jar
60 fun write_and_make
(compiler
: JavaCompiler) do
62 toolcontext
.info
("*** WRITING JAVA ***", 1)
64 compiler
.compile_dir
.mkdir
66 var jfiles
= write_java_files
(compiler
)
69 toolcontext
.info
("*** END WRITING JAVA: {time1-time0} ***", 2)
72 toolcontext
.info
("*** COMPILING JAVA ***", 1)
74 build_with_make
(compiler
, jfiles
)
75 write_shell_script
(compiler
)
78 toolcontext
.info
("*** END COMPILING JAVA: {time1-time0} ***", 2)
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
)
88 jfiles
.add
(f
.filename
)
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)
101 if toolcontext
.verbose_level
>= 3 then
102 res
= sys
.system
("make -B -C {compile_dir} -f {outname}.mk 2>&1")
104 res
= sys
.system
("make -B -C {compile_dir} -f {outname}.mk 2>&1 > /dev/null")
106 if res
!= 0 then toolcontext
.error
(null, "make failed! Error code: {res}.")
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")
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
)
121 makefile
.write
("JC = javac\n")
122 makefile
.write
("JAR = jar\n\n")
124 makefile
.write
("all: {outpath}.jar\n\n")
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")
129 makefile
.write
("{compiler.mainmodule.jname}_Main.class:\n")
130 makefile
.write
("\t$(JC) {jfiles.join(" ")}\n\n")
132 makefile
.write
("clean:\n")
133 makefile
.write
("\trm {ofiles.join(" ")} 2>/dev/null\n\n")
136 toolcontext
.info
("Generated makefile: {makename}", 2)
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")
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")
156 sys
.system
("chmod +x {outname}")
160 # Compiler that translates Nit code to Java code
162 # The main module of the program currently compiled
163 var mainmodule
: MModule
165 # Modelbuilder used to know the model and the AST
166 var modelbuilder
: ModelBuilder
168 # The result of the RTA (used to know live types and methods)
169 var runtime_type_analysis
: RapidTypeAnalysis
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"
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
185 # The list of all associated files
186 # Used to generate .java files
187 var files
: Array[JavaCodeFile] = new Array[JavaCodeFile]
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
)
197 # Kind of visitor to use
198 type VISITOR: JavaCompilerVisitor
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
))
205 # RuntimeModel representation
206 private var rt_model
: JavaRuntimeModel is lazy
do return new JavaRuntimeModel
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)
213 # compile class structures
214 compile_mclasses_to_java
216 # compile method structures
217 compile_mmethods_to_java
220 modelbuilder
.toolcontext
.info
("NOT YET IMPLEMENTED", 0)
223 # Generate a `RTClass` for each `MClass` found in model
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"))
233 # Generate a `RTMethod` for each `MMethodDef` found in model
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"))
249 # The class visiting the AST
251 # A visitor is attached to one JavaCodeFile it writes into.
252 class JavaCompilerVisitor
255 # JavaCompiler used with this visitor
256 type COMPILER: JavaCompiler
258 # The associated compiler
259 var compiler
: JavaCompiler
261 # The file to write generated code into
262 var file
: JavaCodeFile
266 private var names
= new HashSet[String]
267 private var last
: Int = 0
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
275 var i
= self.last
+ 1
278 if not self.names
.has
(s2
) then
289 # Registered variables
290 protected var variables
= new HashMap[Variable, RuntimeVariable]
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
]
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
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} */;")
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
)
322 # The current `JavaStaticFrame`
323 var frame
: nullable JavaStaticFrame = null is writable
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];")
334 # Add a line (will be suffixed by `\n`)
335 fun add
(line
: String) do file
.lines
.add
("{line}\n")
337 # Add a new partial line (no `\n` suffix)
338 fun addn
(line
: String) do file
.lines
.add
(line
)
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
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
356 if nexpr
.mtype
!= null then
357 res
= nexpr
.expr
(self)
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};")
371 # Return a new local RuntimeVariable initialized with the Java expression `jexpr`.
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};")
380 # Generate generic abort
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
387 add
("System.err.print(\" ({node.location.short_location})\
");")
389 add
("System.err.println(\"\
");")
390 add
("System.exit(1);")
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
)
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
)
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
)
413 # Generate a float value
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
)
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
)
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
)
435 # Display a info message
436 fun info
(str
: String) do compiler
.modelbuilder
.toolcontext
.info
(str
, 0)
439 # A file containing Java code.
446 var lines
: List[String] = new List[String]
450 # A Java compatible name for `self`
451 private fun jname
: String do return name
.to_cmangle
454 # Handler for runtime classes generation
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
462 # Compile JavaRuntimeModel structures
463 fun compile_rtmodel
(compiler
: JavaCompiler) do
464 compile_rtclass
(compiler
)
465 compile_rtmethod
(compiler
)
466 compile_rtval
(compiler
)
469 # Compile the abstract runtime class structure
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() \{\}")
486 # Compile the abstract runtime method structure
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);")
499 # Compile the runtime value structure
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
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;")
520 v
.add
(" public RTVal(RTClass rtclass, Object value) \{")
521 v
.add
(" this.rtclass = rtclass;")
522 v
.add
(" this.value = value;")
524 v
.add
(" public boolean is_null() \{ return rtclass == null && value == null; \}")
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
533 # The name of the variable in the Java code
536 # The static type of the variable (as declard in Java)
539 # The current casted type of the variable (as known in Nit)
540 var mcasttype
: MType is writable
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
546 # Is this variable declared as a RTVal or a Java primitive one?
549 redef fun to_s
do return name
554 if self.is_exact
then
560 if self.mtype
== self.mcasttype
then
561 type_str
= "{mtype}{exact_str}"
563 type_str
= "{mtype}({mcasttype}{exact_str})"
565 return "<{name}:{type_str}>"
569 # The static context of a visited property in a `JavaCompilerVisitor`
570 class JavaStaticFrame
571 # The associated visitor
572 var visitor
: JavaCompilerVisitor
574 # The executed property.
575 # A Method in case of a call, an attribute in case of a default initialization.
576 var mpropdef
: MPropDef
578 # The static type of the receiver
579 var receiver
: MClassType
581 # Arguments of the method (the first is the receiver)
582 var arguments
: Array[RuntimeVariable]
584 # The runtime_variable associated to the return (in a function)
585 var returnvar
: nullable RuntimeVariable = null is writable
587 # The label at the end of the property
588 var returnlabel
: nullable String = null is writable
592 # Return a shortened version of the location with `"{file}:{line_start}"`
593 fun short_location
: String do
595 if file
== null then return "<no file>:{line_start}"
596 return "{file.filename.escape_to_c}:{line_start}"
601 # Return the Java type associated to a given Nit static type
602 fun java_type
: String do return "RTVal"
604 # Is the associated Java type a primitive one?
606 # ENSURE `result == (java_type != "Object")`
607 var is_java_primitive
: Bool is lazy
do return java_type
!= "RTVal"
610 redef class MClassType
612 redef var java_type
is lazy
do
613 if mclass
.name
== "Int" then
615 else if mclass
.name
== "Bool" then
617 else if mclass
.name
== "Char" then
619 else if mclass
.name
== "Float" then
621 else if mclass
.name
== "Byte" then
623 else if mclass
.name
== "NativeString" then
625 else if mclass
.name
== "NativeArray" then
635 private fun rt_name
: String do return "RTClass_{intro.mmodule.jname}_{jname}"
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}\
";")
644 compile_type_table
(v
)
646 v
.add
(" public static RTClass get{rt_name}() \{")
647 v
.add
(" if(instance == null) \{")
648 v
.add
(" instance = new {rt_name}();")
650 v
.add
(" return instance;")
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
)
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}());")
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}());")
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);")
687 v
.add
("supers.put(\"{pclass.jname}\
", {pclass.rt_name}.get{pclass.rt_name}());")
693 redef class MMethodDef
696 private fun rt_name
: String do
697 return "RTMethod_{mclassdef.mmodule.jname}_{mclassdef.mclass.jname}_{mproperty.jname}"
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}();")
708 v
.add
(" return instance;")
711 v
.add
(" public RTVal exec(RTVal[] args) \{")
712 compile_inside_to_java
(v
)
717 # Compile the body of this function
718 fun compile_inside_to_java
(v
: JavaCompilerVisitor) do
720 var modelbuilder
= v
.compiler
.modelbuilder
721 var node
= modelbuilder
.mpropdef2node
(self)
724 # TODO compile abstract
725 v
.info
("NOT YET IMPLEMENTED call to abstract method")
726 v
.add
("return null;")
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;")
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")
750 redef class AMethPropdef
751 redef fun compile_to_java
(v
, mpropdef
) do
752 # TODO Call the implicit super-init
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;")
762 # Compile block if any
763 var n_block
= n_block
764 if n_block
!= null then
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")
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
)
784 redef class ABlockExpr
787 for e
in self.n_expr
do v
.stmt
(e
)
791 var last
= self.n_expr
.last
792 for e
in self.n_expr
do
793 if e
== last
then break
796 return v
.expr
(last
, null)
800 redef class ASelfExpr
801 redef fun expr
(v
) do return v
.frame
.as(not null).arguments
.first
804 redef class AImplicitSelfExpr
805 redef fun expr
(v
) do return v
.frame
.as(not null).arguments
.first
809 redef fun expr
(v
) do return v
.int_instance
(self.value
.as(not null))
812 redef class AByteExpr
813 redef fun expr
(v
) do return v
.byte_instance
(self.value
.as(not null))
816 redef class AFloatExpr
817 redef fun expr
(v
) do return v
.float_instance
("{self.n_float.text}") # FIXME use value, not n_float
820 redef class ACharExpr
821 redef fun expr
(v
) do return v
.char_instance
(self.value
.as(not null))
824 redef class ATrueExpr
825 redef fun expr
(v
) do return v
.bool_instance
(true)
828 redef class AFalseExpr
829 redef fun expr
(v
) do return v
.bool_instance
(false)
832 redef class ANullExpr
833 redef fun expr
(v
) do return v
.null_instance
836 redef class AAbortExpr
837 redef fun stmt
(v
) do v
.add_abort
("Aborted")
840 redef class ADebugTypeExpr
841 redef fun stmt
(v
) do end # do nothing