X-Git-Url: http://nitlanguage.org diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index 1ec7761..522230f 100644 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@ -1085,9 +1085,6 @@ abstract class AbstractCompilerVisitor self.writer = new CodeWriter(compiler.files.last) end - # 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 fun get_property(name: String, recv: MType): MMethod do @@ -1129,6 +1126,14 @@ abstract class AbstractCompilerVisitor fun native_array_def(pname: String, ret_type: nullable MType, arguments: Array[RuntimeVariable]) is abstract + # Return an element of a native array. + # The method is unsafe and is just a direct wrapper for the specific implementation of native arrays + fun native_array_get(native_array: RuntimeVariable, index: Int): RuntimeVariable is abstract + + # Store an element in a native array. + # The method is unsafe and is just a direct wrapper for the specific implementation of native arrays + fun native_array_set(native_array: RuntimeVariable, index: Int, value: RuntimeVariable) is abstract + # Evaluate `args` as expressions in the call of `mpropdef` on `recv`. # This method is used to manage varargs in signatures and returns the real array # of runtime variables to use in the call. @@ -1402,7 +1407,7 @@ abstract class AbstractCompilerVisitor var recv var ctype = mtype.ctype assert mtype.mclass.name != "NativeArray" - if ctype == "val*" then + if not mtype.is_c_primitive then recv = init_instance(mtype) else if ctype == "char*" then recv = new_expr("NULL/*special!*/", mtype) @@ -1423,37 +1428,64 @@ abstract class AbstractCompilerVisitor end end + # The currently processed module + # + # alias for `compiler.mainmodule` + fun mmodule: MModule do return compiler.mainmodule + # Generate an integer value fun int_instance(value: Int): RuntimeVariable do - var res = self.new_var(self.get_class("Int").mclass_type) - self.add("{res} = {value};") + var t = mmodule.int_type + var res = new RuntimeVariable("{value.to_s}l", t, t) + return res + end + + # Generate a char value + fun char_instance(value: Char): RuntimeVariable + do + var t = mmodule.char_type + var res = new RuntimeVariable("'{value.to_s.escape_to_c}'", t, t) + return res + end + + # Generate a float value + # + # FIXME pass a Float, not a string + fun float_instance(value: String): RuntimeVariable + do + var t = mmodule.float_type + var res = new RuntimeVariable("{value}", t, t) return res end # Generate an integer value fun bool_instance(value: Bool): RuntimeVariable do - var res = self.new_var(self.get_class("Bool").mclass_type) - if value then - self.add("{res} = 1;") - else - self.add("{res} = 0;") - end + var s = if value then "1" else "0" + var res = new RuntimeVariable(s, bool_type, bool_type) + return res + end + + # Generate the `null` value + fun null_instance: RuntimeVariable + do + var t = compiler.mainmodule.model.null_type + var res = new RuntimeVariable("((val*)NULL)", t, t) return res end # Generate a string value fun string_instance(string: String): RuntimeVariable do - var mtype = self.get_class("String").mclass_type + var mtype = mmodule.string_type var name = self.get_name("varonce") self.add_decl("static {mtype.ctype} {name};") var res = self.new_var(mtype) self.add("if (likely({name}!=NULL)) \{") self.add("{res} = {name};") self.add("\} else \{") - var native_mtype = self.get_class("NativeString").mclass_type + var native_mtype = mmodule.native_string_type var nat = self.new_var(native_mtype) self.add("{nat} = \"{string.escape_to_c}\";") var length = self.int_instance(string.length) @@ -1761,12 +1793,16 @@ redef class MType # Short name of the `ctype` to use in unions fun ctypename: String do return "val" + + # Is the associated C type a primitive one? + # + # ENSURE `result == (ctype != "val*")` + fun is_c_primitive: Bool do return false end redef class MClassType - redef fun ctype: String - do + redef var ctype is lazy do if mclass.name == "Int" then return "long" else if mclass.name == "Bool" then @@ -1784,6 +1820,8 @@ redef class MClassType end end + redef var is_c_primitive is lazy do return ctype != "val*" + redef fun ctype_extern: String do if mclass.kind == extern_kind then @@ -2273,7 +2311,7 @@ redef class AAttrPropdef if is_lazy then var set var ret = self.mpropdef.static_mtype - var useiset = ret.ctype == "val*" and not ret isa MNullableType + var useiset = not ret.is_c_primitive and not ret isa MNullableType var guard = self.mlazypropdef.mproperty if useiset then set = v.isset_attribute(self.mpropdef.mproperty, recv) @@ -2288,7 +2326,7 @@ redef class AAttrPropdef v.assign(res, value) if not useiset then - var true_v = v.new_expr("1", v.bool_type) + var true_v = v.bool_instance(true) v.write_attribute(guard, arguments.first, true_v) end v.add("\}") @@ -2301,9 +2339,9 @@ redef class AAttrPropdef v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1]) if is_lazy then var ret = self.mpropdef.static_mtype - var useiset = ret.ctype == "val*" and not ret isa MNullableType + var useiset = not ret.is_c_primitive and not ret isa MNullableType if not useiset then - v.write_attribute(self.mlazypropdef.mproperty, arguments.first, v.new_expr("1", v.bool_type)) + v.write_attribute(self.mlazypropdef.mproperty, arguments.first, v.bool_instance(true)) end end else @@ -2701,15 +2739,15 @@ redef class AOrElseExpr end redef class AIntExpr - redef fun expr(v) do return v.new_expr("{self.value.to_s}", self.mtype.as(not null)) + redef fun expr(v) do return v.int_instance(self.value.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)) # FIXME use value, not n_float + redef fun expr(v) do return v.float_instance("{self.n_float.text}") # FIXME use value, not n_float end redef class ACharExpr - redef fun expr(v) do return v.new_expr("'{self.value.to_s.escape_to_c}'", self.mtype.as(not null)) + redef fun expr(v) do return v.char_instance(self.value.as(not null)) end redef class AArrayExpr @@ -2737,14 +2775,35 @@ end redef class ASuperstringExpr redef fun expr(v) do - var array = new Array[RuntimeVariable] + var type_string = mtype.as(not null) + + # Collect elements of the superstring + var array = new Array[AExpr] for ne in self.n_exprs do + # Drop literal empty string. + # They appears in things like "{a}" that is ["", a, ""] if ne isa AStringFormExpr and ne.value == "" then continue # skip empty sub-strings - var i = v.expr(ne, null) - array.add(i) + array.add(ne) end - var a = v.array_instance(array, v.object_type) - var res = v.send(v.get_property("to_s", a.mtype), [a]) + + # The native array that will contains the elements to_s-ized. + # For fast concatenation. + var a = v.native_array_instance(type_string, v.int_instance(array.length)) + + # Stringify the elements and put them in the native array + var to_s_method = v.get_property("to_s", v.object_type) + for i in [0..array.length[ do + var ne = array[i] + var e = v.expr(ne, null) + # Skip the `to_s` if the element is already a String + if not e.mcasttype.is_subtype(v.compiler.mainmodule, null, type_string) then + e = v.send(to_s_method, [e]).as(not null) + end + v.native_array_set(a, i, e) + end + + # Fast join the native string to get the result + var res = v.send(v.get_property("native_to_s", a.mtype), [a]) return res end end @@ -2774,15 +2833,15 @@ redef class AOrangeExpr end redef class ATrueExpr - redef fun expr(v) do return v.new_expr("1", self.mtype.as(not null)) + redef fun expr(v) do return v.bool_instance(true) end redef class AFalseExpr - redef fun expr(v) do return v.new_expr("0", self.mtype.as(not null)) + redef fun expr(v) do return v.bool_instance(false) end redef class ANullExpr - redef fun expr(v) do return v.new_expr("NULL", self.mtype.as(not null)) + redef fun expr(v) do return v.null_instance end redef class AIsaExpr @@ -2810,7 +2869,7 @@ redef class AAsNotnullExpr var i = v.expr(self.n_expr, null) if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return i - if i.mtype.ctype != "val*" then return i + if i.mtype.is_c_primitive then return i v.add("if (unlikely({i} == NULL)) \{") v.add_abort("Cast failed")