nitc :: AbstractCompilerVisitor :: _compiler
The associated compilernitc :: AbstractCompilerVisitor :: _current_node
The current visited AST nodenitc :: AbstractCompilerVisitor :: _frame
The currentStaticFrame
nitc :: AbstractCompilerVisitor :: _last
nitc :: AbstractCompilerVisitor :: adapt_signature
Adapt the arguments of a method according to targettedMMethodDef
nitc :: AbstractCompilerVisitor :: add
Add a line in the main part of the generated Cnitc :: AbstractCompilerVisitor :: add_cast
Add a dynamic castnitc :: AbstractCompilerVisitor :: add_escape_label
Insert a C label for associated with an escapemarknitc :: AbstractCompilerVisitor :: add_extern
Look for a needed .h and .c file for a given modulenitc :: AbstractCompilerVisitor :: add_raw_abort
Generate abort without a message.nitc :: AbstractCompilerVisitor :: add_raw_throw
Generate a long jump if there is a catch block.nitc :: AbstractCompilerVisitor :: array_instance
Generate an array valuenitc :: AbstractCompilerVisitor :: assign
Correctly assign a left and a right valuenitc :: AbstractCompilerVisitor :: autoadapt
Unsafely cast a value to a new typenitc :: AbstractCompilerVisitor :: autobox
Box or unbox a value to another type iff a C type conversion is needednitc :: AbstractCompilerVisitor :: bool_instance
Generate an integer valuenitc :: AbstractCompilerVisitor :: bool_type
Alias for self.compiler.mainmodule.bool_typenitc :: AbstractCompilerVisitor :: box_extern
Box extern classes to be used in the generated codenitc :: AbstractCompilerVisitor :: byte_instance
Generate a byte valuenitc :: AbstractCompilerVisitor :: c_string_instance
Generates a CString instance fully escaped in C-style \xHH fashionnitc :: AbstractCompilerVisitor :: call
Generate a static call on a method definitionnitc :: AbstractCompilerVisitor :: char_instance
Generate a char valuenitc :: AbstractCompilerVisitor :: check_recv_notnull
Add a check and an abort for a null receiver if needednitc :: AbstractCompilerVisitor :: class_name_string
Return a "const char*" variable associated to the classname of the dynamic type of an objectnitc :: AbstractCompilerVisitor :: compiler=
The associated compilernitc :: AbstractCompilerVisitor :: current_node
The current visited AST nodenitc :: AbstractCompilerVisitor :: current_node=
The current visited AST nodenitc :: AbstractCompilerVisitor :: debug
Safely show a debug message on the current node and repeat the message in the C code as a commentnitc :: AbstractCompilerVisitor :: declare_once
Add a declaration in the local-headernitc :: AbstractCompilerVisitor :: equal_test
Generate a Nit "is" for two runtime_variablesnitc :: AbstractCompilerVisitor :: escapemark_name
Return an unique and stable identifier associated with an escapemarknitc :: AbstractCompilerVisitor :: expr
Compile an expression an return its resultnitc :: AbstractCompilerVisitor :: expr_bool
Alias forself.expr(nexpr, self.bool_type)
nitc :: AbstractCompilerVisitor :: float_instance
Generate a float valuenitc :: AbstractCompilerVisitor :: frame=
The currentStaticFrame
nitc :: AbstractCompilerVisitor :: get_property
Force to get the primitive property namedname
in the instance recv
or abort
nitc :: AbstractCompilerVisitor :: init_instance
Generate a alloc-instance + init-attributesnitc :: AbstractCompilerVisitor :: init_instance_or_extern
Allocate and init attributes of an instance of a standard or extern classnitc :: AbstractCompilerVisitor :: int16_instance
Generate an int16 valuenitc :: AbstractCompilerVisitor :: int32_instance
Generate an int32 valuenitc :: AbstractCompilerVisitor :: int8_instance
Generate an int8 valuenitc :: AbstractCompilerVisitor :: int_instance
Generate an integer valuenitc :: AbstractCompilerVisitor :: is_same_type_test
Generate the code required to dynamically check if 2 objects share the same runtime typenitc :: AbstractCompilerVisitor :: isset_attribute
Generate a polymorphic attribute is_set testnitc :: AbstractCompilerVisitor :: last
nitc :: AbstractCompilerVisitor :: last=
nitc :: AbstractCompilerVisitor :: maybe_null
Can value be null? (according to current knowledge)nitc :: AbstractCompilerVisitor :: monomorphic_send
Generate a monomorphic send for the methodm
, the type t
and the arguments args
nitc :: AbstractCompilerVisitor :: monomorphic_super_send
Generate a monomorphic super send from the methodm
, the type t
and the arguments args
nitc :: AbstractCompilerVisitor :: native_array_get
Return an element of a native array.nitc :: AbstractCompilerVisitor :: native_array_set
Store an element in a native array.nitc :: AbstractCompilerVisitor :: new_expr
Return a new local runtime_variable initialized with the C expressioncexpr
.
nitc :: AbstractCompilerVisitor :: new_named_var
Return a new uninitialized named runtime_variablenitc :: AbstractCompilerVisitor :: new_var
Return a new uninitialized local runtime_variablenitc :: AbstractCompilerVisitor :: new_var_extern
The difference withnew_var
is the C static type of the local variable
nitc :: AbstractCompilerVisitor :: null_instance
Generate thenull
value
nitc :: AbstractCompilerVisitor :: object_type
Alias for self.compiler.mainmodule.object_typenitc :: AbstractCompilerVisitor :: read_attribute
Generate a polymorphic attribute readnitc :: AbstractCompilerVisitor :: require_declaration
Request the presence of a global declarationnitc :: AbstractCompilerVisitor :: ret
Generate a return with the values
nitc :: AbstractCompilerVisitor :: ret_to_c
Return aRuntimeVarible
to C user code
nitc :: AbstractCompilerVisitor :: routine_ref_call
Call the underlying referenced functionnitc :: AbstractCompilerVisitor :: routine_ref_instance
Instantiate a new routine pointernitc :: AbstractCompilerVisitor :: send
Generate a polymorphic send for the methodm
and the arguments args
nitc :: AbstractCompilerVisitor :: set_finalizer
Set a GC finalizer onrecv
, only if recv
isa Finalizable
nitc :: AbstractCompilerVisitor :: stmt
Compile a statement (if any)nitc :: AbstractCompilerVisitor :: string_instance
Generate a string valuenitc :: AbstractCompilerVisitor :: supercall
Generate a super call from a method definitionnitc :: AbstractCompilerVisitor :: type_test
Generate a polymorphic subtype testnitc :: AbstractCompilerVisitor :: uint16_instance
Generate a uint16 valuenitc :: AbstractCompilerVisitor :: uint32_instance
Generate a uint32 valuenitc :: AbstractCompilerVisitor :: unbox_extern
Unbox extern classes to be used in extern code (legacy NI and FFI)nitc :: AbstractCompilerVisitor :: unbox_signature_extern
Unbox all the arguments of a method when implementedextern
or intern
nitc :: AbstractCompilerVisitor :: var_from_c
Create aRuntimeVariable
for this C variable originating from C user code
nitc :: AbstractCompilerVisitor :: vararg_instance
Get an instance of a array for a varargnitc :: AbstractCompilerVisitor :: varargize
Evaluateargs
as expressions in the call of mpropdef
on recv
.
nitc :: AbstractCompilerVisitor :: variable
Return the local runtime_variable associated to a Nit local variablenitc :: AbstractCompilerVisitor :: write_attribute
Generate a polymorphic attribute writenitc $ AbstractCompilerVisitor :: SELF
Type of this instance, automatically specialized in every classnitc :: memory_logger $ AbstractCompilerVisitor :: nit_alloc
Allocatesize
bytes with the low_level nit_alloc
C function
nitc :: AbstractCompilerVisitor :: _compiler
The associated compilernitc :: AbstractCompilerVisitor :: _current_node
The current visited AST nodenitc :: AbstractCompilerVisitor :: _frame
The currentStaticFrame
nitc :: AbstractCompilerVisitor :: _last
nitc :: AbstractCompilerVisitor :: adapt_signature
Adapt the arguments of a method according to targettedMMethodDef
nitc :: AbstractCompilerVisitor :: add
Add a line in the main part of the generated Cnitc :: AbstractCompilerVisitor :: add_cast
Add a dynamic castnitc :: AbstractCompilerVisitor :: add_escape_label
Insert a C label for associated with an escapemarknitc :: AbstractCompilerVisitor :: add_extern
Look for a needed .h and .c file for a given modulenitc :: AbstractCompilerVisitor :: add_raw_abort
Generate abort without a message.nitc :: AbstractCompilerVisitor :: add_raw_throw
Generate a long jump if there is a catch block.nitc :: AbstractCompilerVisitor :: array_instance
Generate an array valuenitc :: AbstractCompilerVisitor :: assign
Correctly assign a left and a right valuenitc :: AbstractCompilerVisitor :: autoadapt
Unsafely cast a value to a new typenitc :: AbstractCompilerVisitor :: autobox
Box or unbox a value to another type iff a C type conversion is needednitc :: AbstractCompilerVisitor :: bool_instance
Generate an integer valuenitc :: AbstractCompilerVisitor :: bool_type
Alias for self.compiler.mainmodule.bool_typenitc :: AbstractCompilerVisitor :: box_extern
Box extern classes to be used in the generated codenitc :: AbstractCompilerVisitor :: byte_instance
Generate a byte valuenitc :: AbstractCompilerVisitor :: c_string_instance
Generates a CString instance fully escaped in C-style \xHH fashionnitc :: AbstractCompilerVisitor :: call
Generate a static call on a method definitionnitc :: AbstractCompilerVisitor :: char_instance
Generate a char valuenitc :: AbstractCompilerVisitor :: check_recv_notnull
Add a check and an abort for a null receiver if neededcore :: Object :: class_factory
Implementation used byget_class
to create the specific class.
nitc :: AbstractCompilerVisitor :: class_name_string
Return a "const char*" variable associated to the classname of the dynamic type of an objectnitc :: AbstractCompilerVisitor :: compiler=
The associated compilernitc :: AbstractCompilerVisitor :: current_node
The current visited AST nodenitc :: AbstractCompilerVisitor :: current_node=
The current visited AST nodenitc :: AbstractCompilerVisitor :: debug
Safely show a debug message on the current node and repeat the message in the C code as a commentnitc :: AbstractCompilerVisitor :: declare_once
Add a declaration in the local-headercore :: Object :: defaultinit
nitc :: AbstractCompilerVisitor :: equal_test
Generate a Nit "is" for two runtime_variablesnitc :: AbstractCompilerVisitor :: escapemark_name
Return an unique and stable identifier associated with an escapemarknitc :: AbstractCompilerVisitor :: expr
Compile an expression an return its resultnitc :: AbstractCompilerVisitor :: expr_bool
Alias forself.expr(nexpr, self.bool_type)
nitc :: AbstractCompilerVisitor :: float_instance
Generate a float valuenitc :: AbstractCompilerVisitor :: frame=
The currentStaticFrame
nitc :: AbstractCompilerVisitor :: get_property
Force to get the primitive property namedname
in the instance recv
or abort
nitc :: AbstractCompilerVisitor :: init_instance
Generate a alloc-instance + init-attributesnitc :: AbstractCompilerVisitor :: init_instance_or_extern
Allocate and init attributes of an instance of a standard or extern classnitc :: AbstractCompilerVisitor :: int16_instance
Generate an int16 valuenitc :: AbstractCompilerVisitor :: int32_instance
Generate an int32 valuenitc :: AbstractCompilerVisitor :: int8_instance
Generate an int8 valuenitc :: AbstractCompilerVisitor :: int_instance
Generate an integer valuecore :: Object :: is_same_instance
Return true ifself
and other
are the same instance (i.e. same identity).
core :: Object :: is_same_serialized
Isself
the same as other
in a serialization context?
core :: Object :: is_same_type
Return true ifself
and other
have the same dynamic type.
nitc :: AbstractCompilerVisitor :: is_same_type_test
Generate the code required to dynamically check if 2 objects share the same runtime typenitc :: AbstractCompilerVisitor :: isset_attribute
Generate a polymorphic attribute is_set testnitc :: AbstractCompilerVisitor :: last
nitc :: AbstractCompilerVisitor :: last=
nitc :: AbstractCompilerVisitor :: maybe_null
Can value be null? (according to current knowledge)nitc :: AbstractCompilerVisitor :: monomorphic_send
Generate a monomorphic send for the methodm
, the type t
and the arguments args
nitc :: AbstractCompilerVisitor :: monomorphic_super_send
Generate a monomorphic super send from the methodm
, the type t
and the arguments args
nitc :: AbstractCompilerVisitor :: native_array_get
Return an element of a native array.nitc :: AbstractCompilerVisitor :: native_array_set
Store an element in a native array.core :: Object :: native_class_name
The class name of the object in CString format.nitc :: AbstractCompilerVisitor :: new_expr
Return a new local runtime_variable initialized with the C expressioncexpr
.
nitc :: AbstractCompilerVisitor :: new_named_var
Return a new uninitialized named runtime_variablenitc :: AbstractCompilerVisitor :: new_var
Return a new uninitialized local runtime_variablenitc :: AbstractCompilerVisitor :: new_var_extern
The difference withnew_var
is the C static type of the local variable
nitc :: AbstractCompilerVisitor :: null_instance
Generate thenull
value
nitc :: AbstractCompilerVisitor :: object_type
Alias for self.compiler.mainmodule.object_typecore :: Object :: output_class_name
Display class name on stdout (debug only).nitc :: AbstractCompilerVisitor :: read_attribute
Generate a polymorphic attribute readnitc :: AbstractCompilerVisitor :: require_declaration
Request the presence of a global declarationnitc :: AbstractCompilerVisitor :: ret
Generate a return with the values
nitc :: AbstractCompilerVisitor :: ret_to_c
Return aRuntimeVarible
to C user code
nitc :: AbstractCompilerVisitor :: routine_ref_call
Call the underlying referenced functionnitc :: AbstractCompilerVisitor :: routine_ref_instance
Instantiate a new routine pointernitc :: AbstractCompilerVisitor :: send
Generate a polymorphic send for the methodm
and the arguments args
nitc :: AbstractCompilerVisitor :: set_finalizer
Set a GC finalizer onrecv
, only if recv
isa Finalizable
nitc :: AbstractCompilerVisitor :: stmt
Compile a statement (if any)nitc :: AbstractCompilerVisitor :: string_instance
Generate a string valuenitc :: AbstractCompilerVisitor :: supercall
Generate a super call from a method definitionnitc :: AbstractCompilerVisitor :: type_test
Generate a polymorphic subtype testnitc :: AbstractCompilerVisitor :: uint16_instance
Generate a uint16 valuenitc :: AbstractCompilerVisitor :: uint32_instance
Generate a uint32 valuenitc :: AbstractCompilerVisitor :: unbox_extern
Unbox extern classes to be used in extern code (legacy NI and FFI)nitc :: AbstractCompilerVisitor :: unbox_signature_extern
Unbox all the arguments of a method when implementedextern
or intern
nitc :: AbstractCompilerVisitor :: var_from_c
Create aRuntimeVariable
for this C variable originating from C user code
nitc :: AbstractCompilerVisitor :: vararg_instance
Get an instance of a array for a varargnitc :: AbstractCompilerVisitor :: varargize
Evaluateargs
as expressions in the call of mpropdef
on recv
.
nitc :: AbstractCompilerVisitor :: variable
Return the local runtime_variable associated to a Nit local variablenitc :: AbstractCompilerVisitor :: write_attribute
Generate a polymorphic attribute writenitc :: SeparateCompilerVisitor
A visitor on the AST of property definition that generate the C code of a separate compilation process.
# A visitor on the AST of property definition that generate the C code.
abstract class AbstractCompilerVisitor
type COMPILER: AbstractCompiler
# The associated compiler
var compiler: COMPILER
# The current visited AST node
var current_node: nullable ANode = null is writable
# The current `StaticFrame`
var frame: nullable StaticFrame = null is writable
# Alias for self.compiler.mainmodule.object_type
fun object_type: MClassType do return self.compiler.mainmodule.object_type
# Alias for self.compiler.mainmodule.bool_type
fun bool_type: MClassType do return self.compiler.mainmodule.bool_type
var writer: CodeWriter is noinit
init
do
self.writer = new CodeWriter(compiler.files.last)
end
# 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
return self.compiler.modelbuilder.force_get_primitive_method(self.current_node, name, recv.mclass, self.compiler.mainmodule)
end
fun compile_callsite(callsite: CallSite, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
do
if callsite.is_broken then return null
return self.send(callsite.mproperty, arguments)
end
fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable is abstract
fun native_array_def(pname: String, ret_type: nullable MType, arguments: Array[RuntimeVariable]): Bool do return false
# 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
# Instantiate a new routine pointer
fun routine_ref_instance(routine_mclass_type: MClassType, recv: RuntimeVariable, callsite: CallSite): RuntimeVariable is abstract
# Call the underlying referenced function
fun routine_ref_call(mmethoddef: MMethodDef, args: Array[RuntimeVariable]) is abstract
# Allocate `size` bytes with the low_level `nit_alloc` C function
#
# This method can be redefined to inject statistic or tracing code.
#
# `tag` if any, is used to mark the class of the allocated object.
fun nit_alloc(size: String, tag: nullable String): String
do
return "nit_alloc({size})"
end
# 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.
fun varargize(mpropdef: MMethodDef, map: nullable SignatureMap, recv: RuntimeVariable, args: SequenceRead[AExpr]): Array[RuntimeVariable]
do
var msignature = mpropdef.msignature.as(not null)
var res = new Array[RuntimeVariable]
res.add(recv)
if msignature.arity == 0 then return res
if map == null then
assert args.length == msignature.arity
for ne in args do
res.add self.expr(ne, null)
end
return res
end
# Eval in order of arguments, not parameters
var exprs = new Array[RuntimeVariable].with_capacity(args.length)
for ne in args do
exprs.add self.expr(ne, null)
end
# Fill `res` with the result of the evaluation according to the mapping
for i in [0..msignature.arity[ do
var param = msignature.mparameters[i]
var j = map.map.get_or_null(i)
if j == null then
# default value
res.add(null_instance)
continue
end
if param.is_vararg and args[i].vararg_decl > 0 then
var vararg = exprs.sub(j, args[i].vararg_decl)
var elttype = param.mtype
var arg = self.vararg_instance(mpropdef, recv, vararg, elttype)
res.add(arg)
continue
end
res.add exprs[j]
end
return res
end
# Type handling
# Anchor a type to the main module and the current receiver
fun anchor(mtype: MType): MType
do
if not mtype.need_anchor then return mtype
return mtype.anchor_to(self.compiler.mainmodule, self.frame.receiver)
end
fun resolve_for(mtype: MType, recv: RuntimeVariable): MType
do
if not mtype.need_anchor then return mtype
return mtype.resolve_for(recv.mcasttype, self.frame.receiver, self.compiler.mainmodule, true)
end
# 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: `result.name == value.name`
fun autoadapt(value: RuntimeVariable, mtype: MType): RuntimeVariable
do
mtype = self.anchor(mtype)
var valmtype = value.mcasttype
# CPrimitive is the best you can do
if valmtype.is_c_primitive then
return value
end
# Do nothing if useless autocast
if valmtype.is_subtype(self.compiler.mainmodule, null, mtype) then
return value
end
# Just as_not_null if the target is not nullable.
#
# eg `nullable PreciseType` adapted to `Object` gives precisetype.
if valmtype isa MNullableType and valmtype.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then
mtype = valmtype.mtype
end
var res = new RuntimeVariable(value.name, value.mtype, mtype)
return res
end
# Generate a super call from a method definition
fun supercall(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable is abstract
# Adapt the arguments of a method according to targetted `MMethodDef`
fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable]) is abstract
# Unbox all the arguments of a method when implemented `extern` or `intern`
fun unbox_signature_extern(m: MMethodDef, args: Array[RuntimeVariable]) is abstract
# Box or unbox a value to another type iff a C type conversion is needed
# ENSURE: `result.mtype.ctype == mtype.ctype`
fun autobox(value: RuntimeVariable, mtype: MType): RuntimeVariable is abstract
# Box extern classes to be used in the generated code
fun box_extern(value: RuntimeVariable, mtype: MType): RuntimeVariable is abstract
# Unbox extern classes to be used in extern code (legacy NI and FFI)
fun unbox_extern(value: RuntimeVariable, mtype: MType): RuntimeVariable is abstract
# Generate a polymorphic subtype test
fun type_test(value: RuntimeVariable, mtype: MType, tag: String): RuntimeVariable is abstract
# Generate the code required to dynamically check if 2 objects share the same runtime type
fun is_same_type_test(value1, value2: RuntimeVariable): RuntimeVariable is abstract
# Generate a Nit "is" for two runtime_variables
fun equal_test(value1, value2: RuntimeVariable): RuntimeVariable is abstract
# Sends
# 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`
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`
fun monomorphic_send(m: MMethod, t: MType, args: Array[RuntimeVariable]): nullable RuntimeVariable
do
assert t isa MClassType
var propdef = m.lookup_first_definition(self.compiler.mainmodule, t)
return self.call(propdef, t, args)
end
# Generate a monomorphic super send from the method `m`, the type `t` and the arguments `args`
fun monomorphic_super_send(m: MMethodDef, t: MType, args: Array[RuntimeVariable]): nullable RuntimeVariable
do
assert t isa MClassType
m = m.lookup_next_definition(self.compiler.mainmodule, t)
return self.call(m, t, args)
end
# Attributes handling
# Generate a polymorphic attribute is_set test
fun isset_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable is abstract
# Generate a polymorphic attribute read
fun read_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable is abstract
# Generate a polymorphic attribute write
fun write_attribute(a: MAttribute, recv: RuntimeVariable, value: RuntimeVariable) is abstract
# Checks
# Can value be null? (according to current knowledge)
fun maybe_null(value: RuntimeVariable): Bool
do
return value.mcasttype isa MNullableType or value.mcasttype isa MNullType
end
# Add a check and an abort for a null receiver if needed
fun check_recv_notnull(recv: RuntimeVariable)
do
if self.compiler.modelbuilder.toolcontext.opt_no_check_null.value then return
if maybe_null(recv) then
self.add("if (unlikely({recv} == NULL)) \{")
self.add_abort("Receiver is null")
self.add("\}")
end
end
# Names handling
private var names = new HashSet[String]
private var last: Int = 0
# 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
self.names.add(s)
return s
end
var i = self.last + 1
loop
var s2 = s + i.to_s
if not self.names.has(s2) then
self.last = i
self.names.add(s2)
return s2
end
i = i + 1
end
end
# Return an unique and stable identifier associated with an escapemark
fun escapemark_name(e: nullable EscapeMark): String
do
assert e != null
if frame.escapemark_names.has_key(e) then return frame.escapemark_names[e]
var name = e.name
if name == null then name = "label"
name = get_name(name)
frame.escapemark_names[e] = name
return name
end
# Insert a C label for associated with an escapemark
fun add_escape_label(e: nullable EscapeMark)
do
if e == null then return
if e.escapes.is_empty then return
add("BREAK_{escapemark_name(e)}: (void)0;")
end
# Return a "const char*" variable associated to the classname of the dynamic type of an object
# NOTE: we do not return a `RuntimeVariable` "CString" as the class may not exist in the module/program
fun class_name_string(value: RuntimeVariable): String is abstract
# Variables handling
protected var variables = new HashMap[Variable, RuntimeVariable]
# Return the local runtime_variable associated to a Nit local variable
fun variable(variable: Variable): RuntimeVariable
do
if self.variables.has_key(variable) then
return self.variables[variable]
else
var name = self.get_name("var_{variable.name}")
var mtype = variable.declared_type.as(not null)
mtype = self.anchor(mtype)
var res = new RuntimeVariable(name, mtype, mtype)
self.add_decl("{mtype.ctype} {name} /* var {variable}: {mtype} */;")
self.variables[variable] = res
return res
end
end
# Return a new uninitialized local runtime_variable
fun new_var(mtype: MType): RuntimeVariable
do
mtype = self.anchor(mtype)
var name = self.get_name("var")
var res = new RuntimeVariable(name, mtype, mtype)
self.add_decl("{mtype.ctype} {name} /* : {mtype} */;")
return res
end
# The difference with `new_var` is the C static type of the local variable
fun new_var_extern(mtype: MType): RuntimeVariable
do
mtype = self.anchor(mtype)
var name = self.get_name("var")
var res = new RuntimeVariable(name, mtype, mtype)
self.add_decl("{mtype.ctype_extern} {name} /* : {mtype} for extern */;")
return res
end
# Return a new uninitialized named runtime_variable
fun new_named_var(mtype: MType, name: String): RuntimeVariable
do
mtype = self.anchor(mtype)
var res = new RuntimeVariable(name, mtype, mtype)
self.add_decl("{mtype.ctype} {name} /* : {mtype} */;")
return res
end
# Correctly assign a left and a right value
# Boxing and unboxing is performed if required
fun assign(left, right: RuntimeVariable)
do
right = self.autobox(right, left.mtype)
self.add("{left} = {right};")
end
# Generate instances
# Generate a alloc-instance + init-attributes
fun init_instance(mtype: MClassType): RuntimeVariable is abstract
# Allocate and init attributes of an instance of a standard or extern class
#
# Does not support universals and the pseudo-internal `NativeArray` class.
fun init_instance_or_extern(mtype: MClassType): RuntimeVariable
do
var recv
var ctype = mtype.ctype
assert mtype.mclass.name != "NativeArray"
if not mtype.is_c_primitive then
recv = init_instance(mtype)
else if ctype == "char*" then
recv = new_expr("NULL/*special!*/", mtype)
else
recv = new_expr("({ctype})0/*special!*/", mtype)
end
return recv
end
# Set a GC finalizer on `recv`, only if `recv` isa Finalizable
fun set_finalizer(recv: RuntimeVariable)
do
var mtype = recv.mtype
var finalizable_type = compiler.mainmodule.finalizable_type
if finalizable_type != null and not mtype.need_anchor and
mtype.is_subtype(compiler.mainmodule, null, finalizable_type) then
add "gc_register_finalizer({recv});"
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 t = mmodule.int_type
var res = new RuntimeVariable("{value.to_s}l", t, t)
return res
end
# Generate a byte value
fun byte_instance(value: Byte): RuntimeVariable
do
var t = mmodule.byte_type
var res = new RuntimeVariable("((unsigned char){value.to_s})", t, t)
return res
end
# Generate an int8 value
fun int8_instance(value: Int8): RuntimeVariable
do
var t = mmodule.int8_type
var res = new RuntimeVariable("INT8_C({value.to_s})", t, t)
return res
end
# Generate an int16 value
fun int16_instance(value: Int16): RuntimeVariable
do
var t = mmodule.int16_type
var res = new RuntimeVariable("INT16_C({value.to_s})", t, t)
return res
end
# Generate a uint16 value
fun uint16_instance(value: UInt16): RuntimeVariable
do
var t = mmodule.uint16_type
var res = new RuntimeVariable("UINT16_C({value.to_s})", t, t)
return res
end
# Generate an int32 value
fun int32_instance(value: Int32): RuntimeVariable
do
var t = mmodule.int32_type
var res = new RuntimeVariable("INT32_C({value.to_s})", t, t)
return res
end
# Generate a uint32 value
fun uint32_instance(value: UInt32): RuntimeVariable
do
var t = mmodule.uint32_type
var res = new RuntimeVariable("UINT32_C({value.to_s})", t, t)
return res
end
# Generate a char value
fun char_instance(value: Char): RuntimeVariable
do
var t = mmodule.char_type
if value.code_point < 128 then
return new RuntimeVariable("'{value.to_s.escape_to_c}'", t, t)
else
return new RuntimeVariable("{value.code_point}", t, t)
end
end
# Generate a float value
#
# FIXME pass a Float, not a string
fun float_instance(value: Float): RuntimeVariable
do
var t = mmodule.float_type
var res = new RuntimeVariable("{value.to_hexa_exponential_notation}", t, t)
return res
end
# Generate an integer value
fun bool_instance(value: Bool): RuntimeVariable
do
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
# Generates a CString instance fully escaped in C-style \xHH fashion
fun c_string_instance(ns: CString, len: Int): RuntimeVariable do
var mtype = mmodule.c_string_type
var nat = new_var(mtype)
var byte_esc = new Buffer.with_cap(len * 4)
for i in [0 .. len[ do
byte_esc.append("\\x{ns[i].to_hex}")
end
self.add("{nat} = \"{byte_esc}\";")
return nat
end
# Generate a string value
fun string_instance(string: String): RuntimeVariable
do
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 = mmodule.c_string_type
var nat = self.new_var(native_mtype)
self.add("{nat} = \"{string.escape_to_c}\";")
var byte_length = self.int_instance(string.byte_length)
var unilen = self.int_instance(string.length)
self.add("{res} = {self.send(self.get_property("to_s_unsafe", native_mtype), [nat, byte_length, unilen, value_instance(false), value_instance(false)]).as(not null)};")
self.add("{name} = {res};")
self.add("\}")
return res
end
fun value_instance(object: Object): RuntimeVariable
do
if object isa Int then
return int_instance(object)
else if object isa Bool then
return bool_instance(object)
else if object isa String then
return string_instance(object)
else
abort
end
end
# Generate an array value
fun array_instance(array: Array[RuntimeVariable], elttype: MType): RuntimeVariable is abstract
# Get an instance of a array for a vararg
fun vararg_instance(mpropdef: MPropDef, recv: RuntimeVariable, varargs: Array[RuntimeVariable], elttype: MType): RuntimeVariable is abstract
# Code generation
# Add a line in the main part of the generated C
fun add(s: String) do self.writer.lines.add(s)
# Add a line in the
# (used for local or global declaration)
fun add_decl(s: String) do self.writer.decl_lines.add(s)
# Request the presence of a global declaration
fun require_declaration(key: String)
do
var reqs = self.writer.file.required_declarations
if reqs.has(key) then return
reqs.add(key)
var node = current_node
if node != null then compiler.requirers_of_declarations[key] = node
end
# Add a declaration in the local-header
# The declaration is ensured to be present once
fun declare_once(s: String)
do
self.compiler.provide_declaration(s, s)
self.require_declaration(s)
end
# Look for a needed .h and .c file for a given module
# This is used for the legacy FFI
fun add_extern(mmodule: MModule)
do
var file = mmodule.filepath
file = file.strip_extension(".nit")
var tryfile = file + ".nit.h"
if tryfile.file_exists then
self.declare_once("#include \"{tryfile.basename}\"")
self.compiler.files_to_copy.add(tryfile)
end
tryfile = file + "_nit.h"
if tryfile.file_exists then
self.declare_once("#include \"{tryfile.basename}\"")
self.compiler.files_to_copy.add(tryfile)
end
if self.compiler.seen_extern.has(file) then return
self.compiler.seen_extern.add(file)
tryfile = file + ".nit.c"
if not tryfile.file_exists then
tryfile = file + "_nit.c"
if not tryfile.file_exists then return
end
var f = new ExternCFile(tryfile.basename, "")
self.compiler.extern_bodies.add(f)
self.compiler.files_to_copy.add(tryfile)
end
# 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)
self.add("{res} = {cexpr};")
return res
end
# Generate generic abort
# used by aborts, asserts, casts, etc.
fun add_abort(message: String)
do
add_raw_throw
self.add("PRINT_ERROR(\"Runtime error: %s\", \"{message.escape_to_c}\");")
add_raw_abort
end
# Generate a long jump if there is a catch block.
#
# This method should be called before the error messages and before a `add_raw_abort`.
fun add_raw_throw
do
self.add("\{")
self.add("struct catch_stack_t *catchStack = getCatchStack();")
self.add("if(catchStack->cursor >= 0)\{")
self.add(" longjmp(catchStack->envs[catchStack->cursor], 1);")
self.add("\}")
self.add("\}")
end
# Generate abort without a message.
#
# Used when one need a more complex message.
# Do not forget to call `add_raw_abort` before the display of a custom user message.
fun add_raw_abort
do
var current_node = self.current_node
if current_node != null and current_node.location.file != null and
current_node.location.file.mmodule != null then
var f = "FILE_{self.current_node.location.file.mmodule.c_name}"
self.require_declaration(f)
self.add("PRINT_ERROR(\" (%s:%d)\\n\", {f}, {current_node.location.line_start});")
else
self.add("PRINT_ERROR(\"\\n\");")
end
self.add("fatal_exit(1);")
end
# Add a dynamic cast
fun add_cast(value: RuntimeVariable, mtype: MType, tag: String)
do
var res = self.type_test(value, mtype, tag)
self.add("if (unlikely(!{res})) \{")
self.add_raw_throw
var cn = self.class_name_string(value)
self.add("PRINT_ERROR(\"Runtime error: Cast failed. Expected `%s`, got `%s`\", \"{mtype.to_s.escape_to_c}\", {cn});")
self.add_raw_abort
self.add("\}")
end
# Generate a return with the value `s`
fun ret(s: RuntimeVariable)
do
self.assign(self.frame.returnvar.as(not null), s)
self.add("goto {self.frame.returnlabel.as(not null)};")
end
# Compile a statement (if any)
fun stmt(nexpr: nullable AExpr)
do
if nexpr == null then return
if nexpr.is_broken then
# Untyped expression.
# Might mean dead code or invalid code
# so aborts
add_abort("FATAL: bad statement executed.")
return
end
var narray = nexpr.comprehension
if narray != null then
var recv = frame.comprehension.as(not null)
var val = expr(nexpr, narray.element_mtype)
compile_callsite(narray.push_callsite.as(not null), [recv, val])
return
end
var old = self.current_node
self.current_node = nexpr
nexpr.stmt(self)
self.current_node = old
end
# Compile an expression an return its result
# `mtype` is the expected return type, pass null if no specific type is expected.
fun expr(nexpr: AExpr, mtype: nullable MType): RuntimeVariable
do
var old = self.current_node
self.current_node = nexpr
var res = null
if nexpr.mtype != null then
res = nexpr.expr(self)
end
if res == null then
# Untyped expression.
# Might mean dead code or invalid code.
# so aborts
add_abort("FATAL: bad expression executed.")
# and return a placebo result to please the C compiler
if mtype == null then mtype = compiler.mainmodule.object_type
res = new_var(mtype)
self.current_node = old
return res
end
if mtype != null then
mtype = self.anchor(mtype)
res = self.autobox(res, mtype)
end
res = autoadapt(res, nexpr.mtype.as(not null))
var implicit_cast_to = nexpr.implicit_cast_to
if implicit_cast_to != null and not self.compiler.modelbuilder.toolcontext.opt_no_check_autocast.value then
add_cast(res, implicit_cast_to, "auto")
res = autoadapt(res, implicit_cast_to)
end
self.current_node = old
return res
end
# 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
fun debug(message: String)
do
var node = self.current_node
if node == null then
print "?: {message}"
else
node.debug(message)
end
self.add("/* DEBUG: {message} */")
end
end
src/compiler/abstract_compiler.nit:1320,1--2054,3
redef class AbstractCompilerVisitor
redef fun nit_alloc(size, tag)
do
if not compiler.modelbuilder.toolcontext.opt_trace_memory.value then return super
# Log time each 10ms (ie 1e7ns)
var tw = get_name("mtw")
add_decl("struct timespec {tw};")
add("clock_gettime(CLOCK_MONOTONIC, &{tw});")
add("if(mlog_last.tv_sec < {tw}.tv_sec || mlog_last.tv_nsec + 1e7 < {tw}.tv_nsec) \{")
add("mlog_last = {tw};")
add("fprintf(mlog, \"# %f\\n\", 1000.0*{tw}.tv_sec + 1e-6*{tw}.tv_nsec - (1000.0*mlog_time0.tv_sec + 1e-6*mlog_time0.tv_nsec));")
add("\}")
# Print size and tag the mlog
var str = "\"+\\t%d\\t%s\\n\", {size}, \"{tag or else "?"}\""
add("fprintf(mlog, {str});")
return super
end
end
src/compiler/memory_logger.nit:56,1--76,3
redef class AbstractCompilerVisitor
# Create a `RuntimeVariable` for this C variable originating from C user code
private fun var_from_c(name: String, mtype: MType): RuntimeVariable
do
if mtype.is_cprimitive then
return new RuntimeVariable(name, mtype, mtype)
else
return new RuntimeVariable("{name}->value", mtype, mtype)
end
end
# Return a `RuntimeVarible` to C user code
private fun ret_to_c(src: RuntimeVariable, mtype: MType)
do
if mtype.is_cprimitive then
add("return {src};")
else
add("struct nitni_instance* ret_for_c;")
add("ret_for_c = nit_alloc(sizeof(struct nitni_instance));")
add("ret_for_c->value = {src};")
add("return ret_for_c;")
end
end
end
src/compiler/compiler_ffi/light.nit:246,1--269,3