nitg: Modified compilation routine to avoid use of String contructors
[nit.git] / src / abstract_compiler.nit
index dbadcbe..5a5597c 100644 (file)
@@ -20,6 +20,7 @@ module abstract_compiler
 import literal
 import typing
 import auto_super_init
+import frontend
 
 # Add compiling options
 redef class ToolContext
@@ -440,8 +441,8 @@ abstract class AbstractCompiler
 
        # Display stats about compilation process
        # Metrics used:
-       #       * type tests against resolved types (x isa Collection[Animal])
-       #       * type tests against unresolved types (x isa Collection[E])
+       #       * type tests against resolved types (`x isa Collection[Animal]`)
+       #       * type tests against unresolved types (`x isa Collection[E]`)
        #       * type tests skipped
        #       * type tests total
        #       *
@@ -524,7 +525,7 @@ abstract class AbstractCompilerVisitor
        # The current visited AST node
        var current_node: nullable ANode writable = null
 
-       # The current Frame
+       # The current `Frame`
        var frame: nullable Frame writable
 
        # Alias for self.compiler.mainmodule.object_type
@@ -541,10 +542,10 @@ abstract class AbstractCompilerVisitor
                self.writer = new CodeWriter(compiler.files.last)
        end
 
-       # Force to get the primitive class named `name' or abort
+       # Force to get the primitive class named `name` or abort
        fun get_class(name: String): MClass do return self.compiler.mainmodule.get_primitive_class(name)
 
-       # Force to get the primitive property named `name' in the instance `recv' or abort
+       # Force to get the primitive property named `name` in the instance `recv` or abort
        fun get_property(name: String, recv: MType): MMethod
        do
                assert recv isa MClassType
@@ -560,7 +561,7 @@ abstract class AbstractCompilerVisitor
 
        fun native_array_def(pname: String, ret_type: nullable MType, arguments: Array[RuntimeVariable]) is abstract
 
-       # Transform varargs, in raw arguments, into a single argument of type Array
+       # Transform varargs, in raw arguments, into a single argument of type `Array`
        # Note: this method modify the given `args`
        # If there is no vararg, then `args` is not modified.
        fun varargize(mpropdef: MPropDef, msignature: MSignature, args: Array[RuntimeVariable])
@@ -612,8 +613,8 @@ abstract class AbstractCompilerVisitor
 
        # Unsafely cast a value to a new type
        # ie the result share the same C variable but my have a different mcasttype
-       # NOTE: if the adaptation is useless then `value' is returned as it.
-       # ENSURE: return.name == value.name
+       # NOTE: if the adaptation is useless then `value` is returned as it.
+       # ENSURE: `(return).name == value.name`
        fun autoadapt(value: RuntimeVariable, mtype: MType): RuntimeVariable
        do
                mtype = self.anchor(mtype)
@@ -654,10 +655,10 @@ abstract class AbstractCompilerVisitor
        #  Generate a static call on a method definition
        fun call(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable is abstract
 
-       #  Generate a polymorphic send for the method `m' and the arguments `args'
+       #  Generate a polymorphic send for the method `m` and the arguments `args`
        fun send(m: MMethod, args: Array[RuntimeVariable]): nullable RuntimeVariable is abstract
 
-       # Generate a monomorphic send for the method `m', the type `t' and the arguments `args'
+       # Generate a monomorphic send for the method `m`, the type `t` and the arguments `args`
        fun monomorphic_send(m: MMethod, t: MType, args: Array[RuntimeVariable]): nullable RuntimeVariable
        do
                assert t isa MClassType
@@ -699,7 +700,7 @@ abstract class AbstractCompilerVisitor
        private var names: HashSet[String] = new HashSet[String]
        private var last: Int = 0
 
-       # Return a new name based on `s' and unique in the visitor
+       # Return a new name based on `s` and unique in the visitor
        fun get_name(s: String): String
        do
                if not self.names.has(s) then
@@ -733,7 +734,7 @@ abstract class AbstractCompilerVisitor
        private var escapemark_names = new HashMap[EscapeMark, String]
 
        # Return a "const char*" variable associated to the classname of the dynamic type of an object
-       # NOTE: we do not return a RuntimeVariable "NativeString" as the class may not exist in the module/program
+       # NOTE: we do not return a `RuntimeVariable` "NativeString" as the class may not exist in the module/program
        fun class_name_string(value: RuntimeVariable): String is abstract
 
        # Variables handling
@@ -806,13 +807,11 @@ abstract class AbstractCompilerVisitor
                self.add("if ({name}) \{")
                self.add("{res} = {name};")
                self.add("\} else \{")
-               var nat = self.new_var(self.get_class("NativeString").mclass_type)
+               var native_mtype = self.get_class("NativeString").mclass_type
+               var nat = self.new_var(native_mtype)
                self.add("{nat} = \"{string.escape_to_c}\";")
-               var res2 = self.init_instance(mtype)
-               self.add("{res} = {res2};")
                var length = self.int_instance(string.length)
-               self.send(self.get_property("with_native", mtype), [res, nat, length])
-               self.check_init_instance(res, mtype)
+               self.add("{res} = {self.monomorphic_send(self.get_property("to_s_with_length", native_mtype), native_mtype, [nat, length]).as(not null)};")
                self.add("{name} = {res};")
                self.add("\}")
                return res
@@ -848,7 +847,7 @@ abstract class AbstractCompilerVisitor
        end
 
        # look for a needed .h and .c file for a given .nit source-file
-       # FIXME: bad API, parameter should be a MModule, not its source-file
+       # FIXME: bad API, parameter should be a `MModule`, not its source-file
        fun add_extern(file: String)
        do
                file = file.strip_extension(".nit")
@@ -872,7 +871,7 @@ abstract class AbstractCompilerVisitor
                self.compiler.extern_bodies.add(f)
        end
 
-       # Return a new local runtime_variable initialized with the C expression `cexpr'.
+       # Return a new local runtime_variable initialized with the C expression `cexpr`.
        fun new_expr(cexpr: String, mtype: MType): RuntimeVariable
        do
                var res = new_var(mtype)
@@ -892,7 +891,7 @@ abstract class AbstractCompilerVisitor
                self.add("exit(1);")
        end
 
-       # Generate a return with the value `s'
+       # Generate a return with the value `s`
        fun ret(s: RuntimeVariable)
        do
                self.assign(self.frame.returnvar.as(not null), s)
@@ -933,7 +932,7 @@ abstract class AbstractCompilerVisitor
                return res
        end
 
-       # Alias for `self.expr(nexpr, self.bool_type)'
+       # Alias for `self.expr(nexpr, self.bool_type)`
        fun expr_bool(nexpr: AExpr): RuntimeVariable do return expr(nexpr, bool_type)
 
        # Safely show a debug message on the current node and repeat the message in the C code as a comment
@@ -979,7 +978,7 @@ abstract class AbstractRuntimeFunction
        # May inline the body or generate a C function call
        fun call(v: VISITOR, arguments: Array[RuntimeVariable]): nullable RuntimeVariable is abstract
 
-       # Generate the code for the RuntimeFunction
+       # Generate the code for the `AbstractRuntimeFunction`
        # Warning: compile more than once compilation makes CC unhappy
        fun compile_to_c(compiler: COMPILER) is abstract
 end
@@ -987,7 +986,7 @@ end
 # A runtime variable hold a runtime value in C.
 # Runtime variables are associated to Nit local variables and intermediate results in Nit expressions.
 #
-# The tricky point is that a single C variable can be associated to more than one RuntimeVariable because the static knowledge of the type of an expression can vary in the C code.
+# The tricky point is that a single C variable can be associated to more than one `RuntimeVariable` because the static knowledge of the type of an expression can vary in the C code.
 class RuntimeVariable
        # The name of the variable in the C code
        var name: String
@@ -1031,7 +1030,7 @@ class RuntimeVariable
        end
 end
 
-# A frame correspond to a visited property in a GlobalCompilerVisitor
+# A frame correspond to a visited property in a `GlobalCompilerVisitor`
 class Frame
 
        type VISITOR: AbstractCompilerVisitor
@@ -1783,7 +1782,7 @@ end
 
 redef class AExpr
        # Try to compile self as an expression
-       # Do not call this method directly, use `v.expr' instead
+       # Do not call this method directly, use `v.expr` instead
        private fun expr(v: AbstractCompilerVisitor): nullable RuntimeVariable
        do
                v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{location.to_s}\\n\");")
@@ -1798,7 +1797,7 @@ redef class AExpr
        end
 
        # Try to compile self as a statement
-       # Do not call this method directly, use `v.stmt' instead
+       # Do not call this method directly, use `v.stmt` instead
        private fun stmt(v: AbstractCompilerVisitor)
        do
                var res = expr(v)
@@ -1910,6 +1909,18 @@ redef class AIfExpr
                v.stmt(self.n_else)
                v.add("\}")
        end
+
+       redef fun expr(v)
+       do
+               var res = v.new_var(self.mtype.as(not null))
+               var cond = v.expr_bool(self.n_expr)
+               v.add("if ({cond})\{")
+               v.assign(res, v.expr(self.n_then.as(not null), null))
+               v.add("\} else \{")
+               v.assign(res, v.expr(self.n_else.as(not null), null))
+               v.add("\}")
+               return res
+       end
 end
 
 redef class AIfexprExpr
@@ -2112,15 +2123,15 @@ redef class AEeExpr
 end
 
 redef class AIntExpr
-       redef fun expr(v) do return v.new_expr("{self.n_number.text}", self.mtype.as(not null))
+       redef fun expr(v) do return v.new_expr("{self.value.to_s}", self.mtype.as(not null))
 end
 
 redef class AFloatExpr
-       redef fun expr(v) do return v.new_expr("{self.n_float.text}", self.mtype.as(not null))
+       redef fun expr(v) do return v.new_expr("{self.n_float.text}", self.mtype.as(not null)) # FIXME use value, not n_float
 end
 
 redef class ACharExpr
-       redef fun expr(v) do return v.new_expr("{self.n_char.text}", self.mtype.as(not null))
+       redef fun expr(v) do return v.new_expr("'{self.value.to_s.escape_to_c}'", self.mtype.as(not null))
 end
 
 redef class AArrayExpr
@@ -2392,7 +2403,7 @@ end
 # Utils
 
 redef class Array[E]
-       # Return a new Array with the elements only contened in 'self' and not in 'o'
+       # Return a new `Array` with the elements only contened in self and not in `o`
        fun -(o: Array[E]): Array[E] do
                var res = new Array[E]
                for e in self do if not o.has(e) then res.add(e)
@@ -2401,7 +2412,7 @@ redef class Array[E]
 end
 
 redef class MModule
-       # All 'mproperties' associated to all 'mclassdefs' of `mclass`
+       # All `MProperty` associated to all `MClassDef` of `mclass`
        fun properties(mclass: MClass): Set[MProperty] do
                if not self.properties_cache.has_key(mclass) then
                        var properties = new HashSet[MProperty]