write_and_make(compiler)
end
- private fun write_and_make(compiler: GlobalCompiler)
+ protected fun write_and_make(compiler: GlobalCompiler)
do
var mainmodule = compiler.mainmodule
end
# Singleton that store the knowledge about the compilation process
-private class GlobalCompiler
+class GlobalCompiler
# The main module of the program
var mainmodule: MModule
var live_primitive_types: Array[MClassType]
# runtime_functions that need to be compiled
- private var todos: List[RuntimeFunction] = new List[RuntimeFunction]
+ private var todos: List[AbstractRuntimeFunction] = new List[AbstractRuntimeFunction]
# runtime_functions already seen (todo or done)
- private var seen: HashSet[RuntimeFunction] = new HashSet[RuntimeFunction]
- fun todo(m: RuntimeFunction)
+ private var seen: HashSet[AbstractRuntimeFunction] = new HashSet[AbstractRuntimeFunction]
+ fun todo(m: AbstractRuntimeFunction)
do
if seen.has(m) then return
todos.add(m)
#
# FIXME: should not be a vistor but just somewhere to store lines
# FIXME: should not have a global .h since it does not help recompilations
- var header: nullable GlobalCompilerVisitor = null
+ var header: nullable GlobalCompilerVisitor writable = null
# The list of all associated visitors
# Used to generate .c files
end
# Cache for classid (computed by declare_runtimeclass)
- private var classids: HashMap[MClassType, String] = new HashMap[MClassType, String]
+ protected var classids: HashMap[MClassType, String] = new HashMap[MClassType, String]
# Declare C structures and identifiers for a runtime class
fun declare_runtimeclass(v: GlobalCompilerVisitor, mtype: MClassType)
end
end
+redef class MParameterType
+ redef fun c_name
+ do
+ var res = self.c_name_cache
+ if res != null then return res
+ res = "FT{self.rank}"
+ self.c_name_cache = res
+ return res
+ end
+end
+
redef class MNullableType
redef fun c_name
do
# A C function associated to a Nit method
# Because of customization, a given Nit method can be compiler more that once
-private abstract class RuntimeFunction
+abstract class AbstractRuntimeFunction
# The associated Nit method
var mmethoddef: MMethodDef
# The mangled c name of the runtime_function
- fun c_name: String is abstract
+ # Subclasses should redefine `build_c_name` instead
+ fun c_name: String
+ do
+ var res = self.c_name_cache
+ if res != null then return res
+ res = self.build_c_name
+ self.c_name_cache = res
+ return res
+ end
+
+ # Non cached version of `c_name`
+ protected fun build_c_name: String is abstract
+
+ private var c_name_cache: nullable String = null
# Implements a call of the runtime_function
# May inline the body or generate a C function call
# A runtime function customized on a specific monomrph receiver type
private class CustomizedRuntimeFunction
- super RuntimeFunction
+ super AbstractRuntimeFunction
# The considered reciever
# (usually is a live type but no strong guarantee)
self.recv = recv
end
- # The mangled c name of the runtime_function
- redef fun c_name: String
+ redef fun build_c_name: String
do
var res = self.c_name_cache
if res != null then return res
return res
end
- private var c_name_cache: nullable String = null
-
redef fun ==(o)
# used in the compiler worklist
do
# 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.
-private class RuntimeVariable
+class RuntimeVariable
# The name of the variable in the C code
var name: String
var mtype: MType
# The current casted type of the variable (as known in Nit)
- var mcasttype: MType
+ var mcasttype: MType writable
# If the variable exaclty a mcasttype?
# false (usual value) means that the variable is a mcasttype or a subtype.
- var is_exact: Bool = false
+ var is_exact: Bool writable = false
init(name: String, mtype: MType, mcasttype: MType)
do
# A visitor on the AST of property definition that generate the C code.
# Because of inlining, a visitor can visit more than one property.
-private class GlobalCompilerVisitor
+class GlobalCompilerVisitor
# The associated compiler
var compiler: GlobalCompiler
# Force to get the primitive property named `name' in the instance `recv' or abort
fun get_property(name: String, recv: MType): MMethod
do
- return self.compiler.mainmodule.force_get_primitive_method(name, recv)
+ return self.compiler.modelbuilder.force_get_primitive_method(self.current_node.as(not null), name, recv, self.compiler.mainmodule)
end
# The current Frame
- var frame: nullable Frame
+ var frame: nullable Frame writable
# Anchor a type to the main module and the current receiver
fun anchor(mtype: MType): MType
if value.mtype.ctype == mtype.ctype then
return value
else if value.mtype.ctype == "val*" then
- return self.new_expr("((struct {mtype.c_name}*){value})->value /* autounbox from {value.mtype} to {mtype} */", mtype)
+ return self.new_expr("((struct {mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
else if mtype.ctype == "val*" then
var valtype = value.mtype.as(MClassType)
var res = self.new_var(mtype)
else
args = args.to_a
end
- assert args.length == m.msignature.arity + 1 # because of self
+ if args.length != m.msignature.arity + 1 then # because of self
+ add("printf(\"NOT YET IMPLEMENTED: Invalid arity for {m}. {args.length} arguments given.\\n\"); exit(1);")
+ debug("NOT YET IMPLEMENTED: Invalid arity for {m}. {args.length} arguments given.")
+ return null
+ end
args.first = recv
var rm = new CustomizedRuntimeFunction(m, recvtype)
return res
end
+ # Generate the code required to dynamically check if 2 objects share the same runtime type
+ fun is_same_type_test(value1, value2: RuntimeVariable): RuntimeVariable
+ do
+ var res = self.new_var(bool_type)
+ if value2.mtype.ctype == "val*" then
+ if value1.mtype.ctype == "val*" then
+ self.add "{res} = {value1}->classid == {value2}->classid;"
+ else
+ self.add "{res} = {self.compiler.classid(value1.mtype.as(MClassType))} == {value2}->classid;"
+ end
+ else
+ if value1.mtype.ctype == "val*" then
+ self.add "{res} = {value1}->classid == {self.compiler.classid(value2.mtype.as(MClassType))};"
+ else if value1.mcasttype == value2.mcasttype then
+ self.add "{res} = 1;"
+ else
+ self.add "{res} = 0;"
+ end
+ end
+ return res
+ end
+
+ # 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
+ fun class_name_string(value: RuntimeVariable): String
+ do
+ var res = self.get_name("var_class_name")
+ self.add_decl("const char* {res};")
+ if value.mtype.ctype == "val*" then
+ self.add "{res} = class_names[{value}->classid];"
+ else
+ self.add "{res} = class_names[{self.compiler.classid(value.mtype.as(MClassType))}];"
+ end
+ return res
+ end
+
# Generate a Nit "is" for two runtime_variables
fun equal_test(value1, value2: RuntimeVariable): RuntimeVariable
do
end
# A frame correspond to a visited property in a GlobalCompilerVisitor
-private class Frame
+class Frame
# The associated visitor
var visitor: GlobalCompilerVisitor
var arguments: Array[RuntimeVariable]
# The runtime_variable associated to the return (in a function)
- var returnvar: nullable RuntimeVariable = null
+ var returnvar: nullable RuntimeVariable writable = null
# The label at the end of the property
- var returnlabel: nullable String = null
+ var returnlabel: nullable String writable = null
end
redef class MPropDef
redef class MMethodDef
# Can the body be inlined?
- private fun can_inline(v: GlobalCompilerVisitor): Bool
+ fun can_inline(v: GlobalCompilerVisitor): Bool
do
var modelbuilder = v.compiler.modelbuilder
if modelbuilder.mpropdef2npropdef.has_key(self) then
end
# Inline the body in another visitor
- private fun compile_inside_to_c(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
+ fun compile_inside_to_c(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
do
var modelbuilder = v.compiler.modelbuilder
if modelbuilder.mpropdef2npropdef.has_key(self) then
end
redef class APropdef
- private fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
+ fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
do
v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
debug("Not yet implemented")
end
- private fun can_inline: Bool do return true
+ fun can_inline: Bool do return true
end
redef class AConcreteMethPropdef
else if pname == "object_id" then
v.ret(arguments.first)
return
+ else if pname == "+" then
+ v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
+ return
+ else if pname == "-" then
+ v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
+ return
else if pname == "==" then
v.ret(v.equal_test(arguments[0], arguments[1]))
return
v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
return
else if pname == "is_same_type" then
- if arguments[0].mtype.ctype == "val*" then
- v.ret(v.new_expr("{arguments[0]}->classid == {arguments[1]}->classid", ret.as(not null)))
- else
- v.ret(v.new_expr("{v.compiler.classid(arguments[0].mtype.as(MClassType))} == {arguments[1]}->classid", ret.as(not null)))
- end
+ v.ret(v.is_same_type_test(arguments[0], arguments[1]))
return
else if pname == "output_class_name" then
- if arguments[0].mtype.ctype == "val*" then
- v.add("printf(\"%s\\n\", class_names[{arguments.first}->classid]);")
- else
- v.add("printf(\"%s\\n\", class_names[{v.compiler.classid(arguments.first.mtype.as(MClassType))}]);")
- end
+ var nat = v.class_name_string(arguments.first)
+ v.add("printf(\"%s\\n\", {nat});")
return
else if pname == "native_class_name" then
- if arguments[0].mtype.ctype == "val*" then
- v.ret(v.new_expr("(char*)(void*)class_names[{arguments.first}->classid]", ret.as(not null)))
- else
- v.ret(v.new_expr("(char*)(void*)class_names[{v.compiler.classid(arguments.first.mtype.as(MClassType))}]", ret.as(not null)))
- end
+ var nat = v.class_name_string(arguments.first)
+ v.ret(v.new_expr("(char*){nat}", ret.as(not null)))
return
end
- v.add("printf(\"NOT IMPLEMENTED {class_name}:{mpropdef} at {location.to_s}\\n\");")
+ v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{mpropdef} at {location.to_s}\\n\");")
debug("Not implemented {mpropdef}")
end
end
end
end
- private fun init_expr(v: GlobalCompilerVisitor, recv: RuntimeVariable)
+ fun init_expr(v: GlobalCompilerVisitor, recv: RuntimeVariable)
do
var nexpr = self.n_expr
if nexpr != null then
# FIXME: we do not want an ugly static call!
var mpropdefs = mpropdef.mproperty.lookup_super_definitions(mpropdef.mclassdef.mmodule, mpropdef.mclassdef.bound_mtype)
if mpropdefs.length != 1 then
+ v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
debug("MPRODFEFS for super {mpropdef} for {recv}: {mpropdefs.join(", ")}")
end
mpropdef = mpropdefs.first