--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2012 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Native interface related services (used underneath the FFI)
+#
+# All nitni properties may not be visible to the user but they are
+# shared between engines
+module nitni_base
+
+import parser
+import modelbuilder # builder only for externcalls
+
+redef class MMethod
+ # Short name of this method in C (without the class name)
+ fun short_cname: String do
+ var nit_name = name
+
+ if nit_name == "+" then return "_plus"
+ if nit_name == "-" then return "_minus"
+ if nit_name == "*" then return "_star"
+ if nit_name == "/" then return "_slash"
+ if nit_name == "%" then return "_percent"
+ if nit_name == "[]" then return "_index"
+ if nit_name == "[]=" then return "_index_assign"
+ if nit_name == "==" then return "_equal"
+ if nit_name == "<" then return "_less"
+ if nit_name == ">" then return "_geater"
+ if nit_name == "<=" then return "_less_or_equal"
+ if nit_name == ">=" then return "_greater_or_equal"
+ if nit_name == "!=" then return "_not_equal"
+ if nit_name == "<<" then return "_left"
+ if nit_name == ">>" then return "_right"
+ if nit_name == "<=>" then return "_starship"
+
+ if nit_name.last == '=' then return "{nit_name.substring(0, nit_name.length-1)}__assign"
+ return nit_name
+ end
+end
+
+redef class AModule
+ # Mangled name of this module in C
+ fun cname: String do return mmodule.name
+end
+
+redef class MMethodDef
+ # Name of the function to callback this method from C,
+ # also used in other functions names used for this method.
+ fun cname: String do return "{mclassdef.mclass.name}_{mproperty.short_cname}"
+end
+
+redef class MType
+ # Representation of this type in pure C on the FFI extern side
+ # Object -> Object
+ # Pointer -> void*
+ fun cname: String is abstract
+
+ # Representation of this type in C for the internal of the system
+ # Hides extern types.
+ fun cname_blind: String is abstract
+
+ # Representation of this type in mangled C
+ # Object -> Object
+ # Pointer -> Pointer
+ fun mangled_cname: String is abstract
+
+ # Does this types has a primitive reprensentation
+ # type Object is_primitive? false
+ # type Pointer is_primitive? true
+ fun is_cprimitive: Bool is abstract
+end
+
+redef class MClassType
+ redef fun cname
+ do
+ var name = mclass.name
+ if name == "Bool" then return "int"
+ if name == "Char" then return "char"
+ if name == "Float" then return "double"
+ if name == "Int" then return "int"
+ if name == "NativeString" then return "char*"
+ if mclass.kind == extern_kind then
+ var ctype = mclass.ctype
+ assert ctype != null
+ return ctype
+ end
+ return mangled_cname
+ end
+
+ redef fun cname_blind do
+ var name = mclass.name
+ if name == "Bool" then return "int"
+ if name == "Char" then return "char"
+ if name == "Float" then return "double"
+ if name == "Int" then return "int"
+ if name == "NativeString" then return "char*"
+ if mclass.kind == extern_kind then return "void*"
+ return "struct nitni_instance *"
+ end
+
+ redef fun mangled_cname do return mclass.name
+
+ redef fun is_cprimitive do return mclass.kind == extern_kind or
+ (once ["Bool", "Char", "Float", "Int", "NativeString"]).has(mclass.name)
+end
+
+redef class MNullableType
+ redef fun cname do return mangled_cname
+ redef fun cname_blind do return "struct nitni_instance *"
+ redef fun mangled_cname do return "nullable_{mtype.mangled_cname}"
+ redef fun is_cprimitive do return false
+end
+
+redef class MVirtualType
+ redef fun mangled_cname: String do return to_s
+end
+
+redef class MGenericType
+ redef fun cname do return mangled_cname
+ redef fun mangled_cname
+ do
+ var base = super
+
+ var params = new Array[String]
+ for arg in arguments do params.add(arg.mangled_cname)
+
+ return "{base}_of_{params.join("_")}"
+ end
+end
+
+redef class MClass
+ fun ctype: nullable String
+ do
+ assert kind == extern_kind
+ return "void*"
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2012-2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# nitni services related to callbacks (used underneath the FFI)
+module nitni_callbacks
+
+import modelbuilder
+intrude import rapid_type_analysis
+
+import nitni_base
+
+redef class ToolContext
+ var verify_nitni_callback_phase: Phase = new VerifyNitniCallbacksPhase(self, [typing_phase])
+end
+
+# * checks for the validity of callbacks
+# * store the callbacks on each method
+class VerifyNitniCallbacksPhase
+ super Phase
+
+ redef fun process_npropdef(npropdef)
+ do
+ if not npropdef isa AExternPropdef then return
+
+ npropdef.verify_nitni_callbacks(toolcontext)
+ end
+end
+
+# Provides a better API but mainly the same content as AExternCalls
+class ForeignCallbackSet
+ # set of imported functions, cached to avoid repetitions
+ var callbacks: Set[ MExplicitCall ] = new HashSet[ MExplicitCall ]
+
+ # set of imported functions, cached to avoid repetitions
+ var supers: Set[ MExplicitSuper ] = new HashSet[ MExplicitSuper ]
+
+ # set of relevant types, cached to avoid repetitions
+ var types: Set[ MType ] = new HashSet[ MType ]
+
+ # set of imported casts and as, cached to avoid repetitions
+ var casts: Set[ MExplicitCast ] = new HashSet[ MExplicitCast ]
+
+ # Utility function, must be called only when all other maps are filled
+ private var all_cached: nullable Set[NitniCallback] = null
+ fun all: Set[NitniCallback]
+ do
+ var cached = all_cached
+ if cached != null then return cached
+
+ var set = new HashSet[NitniCallback]
+ set.add_all(callbacks)
+ set.add_all(supers)
+ set.add_all(types)
+ set.add_all(casts)
+
+ self.all_cached = set
+ return set
+ end
+
+ # Integrate content from the `other` set into this one
+ fun join(other: ForeignCallbackSet)
+ do
+ callbacks.add_all( other.callbacks )
+ supers.add_all( other.supers )
+ types.add_all( other.types )
+ casts.add_all( other.casts )
+ end
+end
+
+redef class AExternPropdef
+ private var foreign_callbacks_cache: nullable ForeignCallbackSet = null
+
+ # All foreign callbacks from this method
+ fun foreign_callbacks: ForeignCallbackSet
+ do
+ var fcs = foreign_callbacks_cache
+ assert fcs != null else print "Error: attempting to access nitni callbacks before phase 'verify_nitni_callback_phase'."
+ return fcs
+ end
+
+ # Verifiy the validity of the explicit callbacks to Nit
+ # also fills the set returned by foreign_callbacks
+ fun verify_nitni_callbacks(toolcontext: ToolContext)
+ do
+ if foreign_callbacks_cache != null then return
+
+ var fcs = new ForeignCallbackSet
+
+ var mmodule = mpropdef.mclassdef.mmodule
+
+ # receiver
+ var recv_type = mpropdef.mclassdef.bound_mtype
+ fcs.types.add(recv_type)
+
+ # return type
+ var rmt = mpropdef.msignature.return_mtype
+ if rmt != null then
+ if rmt isa MParameterType or rmt isa MVirtualType then
+ var mclass_type = mpropdef.mclassdef.bound_mtype
+ rmt = rmt.anchor_to(mmodule, mclass_type)
+ end
+ var mtype = rmt.resolve_for(recv_type, recv_type, mmodule, true)
+ fcs.types.add(mtype)
+ end
+
+ # params
+ for p in mpropdef.msignature.mparameters do
+ var mtype = p.mtype.resolve_for(recv_type, recv_type, mmodule, true)
+ if mtype isa MParameterType or mtype isa MVirtualType then
+ var mclass_type = mpropdef.mclassdef.bound_mtype
+ mtype = mtype.anchor_to(mmodule, mclass_type)
+ end
+ fcs.types.add( mtype )
+ end
+
+ # explicit callbacks
+ if n_extern_calls != null then
+ for ec in n_extern_calls.n_extern_calls do
+ ec.verify_and_collect(self, fcs, toolcontext)
+ end
+ end
+
+ # store result
+ foreign_callbacks_cache = fcs
+ end
+
+ redef fun accept_rapid_type_visitor(v)
+ do
+ for cb in foreign_callbacks.callbacks do v.add_send(cb.recv_mtype, cb.mproperty.as(MMethod))
+ for cast in foreign_callbacks.casts do v.add_cast_type(cast.to)
+ for sup in foreign_callbacks.supers do
+ v.analysis.add_super_send(sup.from.mclassdef.mclass.mclass_type, sup.from.as(MMethodDef))
+ end
+ for t in foreign_callbacks.types do if t isa MClassType then v.add_type t
+ end
+end
+
+# Classification for all nitni callbacks
+interface NitniCallback
+end
+
+redef class MType
+ super NitniCallback
+end
+
+# A prossible call from C, declared explictly after the `import` keyword
+class MExplicitCall
+ super NitniCallback
+
+ # Previously resolved mtype
+ var recv_mtype: MClassType
+ var mproperty: MProperty
+ var from_mmodule: MModule
+
+ fun fill_type_for( callback_set: ForeignCallbackSet, from: MModule )
+ do
+ var first = mproperty.lookup_first_definition( from, recv_mtype )
+ var mclassdef = first.mclassdef
+ var bound_mtype = mclassdef.bound_mtype
+
+ # receiver / constructor return
+ recv_mtype = recv_mtype.resolve_for(bound_mtype, bound_mtype, from, true)
+ recv_mtype = recv_mtype.anchor_to(from, bound_mtype)
+ callback_set.types.add( recv_mtype )
+
+ if first isa MMethodDef then
+ var rmt = first.msignature.return_mtype
+ if rmt != null then
+ rmt = rmt.resolve_for(bound_mtype, bound_mtype, from, true)
+ rmt = rmt.anchor_to(from, bound_mtype)
+ callback_set.types.add( rmt )
+ end
+
+ for p in first.msignature.mparameters do
+ var param_mtype = p.mtype.resolve_for(recv_mtype, recv_mtype, from, true)
+ param_mtype = param_mtype.resolve_for(bound_mtype, bound_mtype, from, true)
+ param_mtype = param_mtype.anchor_to(from, bound_mtype)
+ callback_set.types.add( param_mtype )
+ end
+ end
+ end
+
+ # Signature of this call in C as seen by user
+ fun csignature: String
+ do
+ var mproperty = self.mproperty
+ if mproperty isa MMethod then
+ var signature = mproperty.intro.msignature
+ assert signature != null
+
+ var creturn_type
+ if mproperty.is_init then
+ creturn_type = recv_mtype.cname
+ else if signature.return_mtype != null then
+ var ret_mtype = signature.return_mtype
+ ret_mtype = ret_mtype.resolve_for(recv_mtype, recv_mtype, from_mmodule, true)
+ creturn_type = ret_mtype.cname
+ else
+ creturn_type = "void"
+ end
+
+ var cname
+ if mproperty.is_init then
+ if mproperty.name == "init" or mproperty.name == "new" then
+ cname = "new_{recv_mtype.mangled_cname}"
+ else
+ cname = "new_{recv_mtype.mangled_cname}_{mproperty.short_cname}"
+ end
+ else
+ cname = "{recv_mtype.mangled_cname}_{mproperty.short_cname}"
+ end
+
+ var cparams = new List[String]
+ if not mproperty.is_init then
+ cparams.add( "{recv_mtype.cname} self" )
+ end
+ for p in signature.mparameters do
+ var param_mtype = p.mtype.resolve_for(recv_mtype, recv_mtype, from_mmodule, true)
+ cparams.add( "{param_mtype.cname} {p.name}" )
+ end
+
+ return "{creturn_type} {cname}( {cparams.join(", ")} )"
+ else
+ print "Type of callback from foreign code not yet supported."
+ abort
+ end
+ end
+
+ redef fun hash do return recv_mtype.hash + 1024 * mproperty.hash
+ redef fun ==(o) do return o isa MExplicitCall and recv_mtype == o.recv_mtype and mproperty == o.mproperty
+end
+
+class MExplicitSuper
+ super NitniCallback
+
+ var from: MPropDef
+
+ redef fun hash do return from.hash
+ redef fun ==(o) do return o isa MExplicitSuper and from == o.from
+end
+
+class MExplicitCast
+ super NitniCallback
+
+ var from: MType
+ var to: MType
+
+ fun check_cname: String do return "{from.mangled_cname}_is_a_{to.mangled_cname}"
+
+ fun cast_cname: String do return "{from.mangled_cname}_as_{to.mangled_cname}"
+
+ redef fun hash do return from.hash + 1024 * to.hash
+ redef fun ==(o) do return o isa MExplicitCast and from == o.from and to == o.to
+end
+
+redef class AExternCall
+ # Verify this explicit declaration of call from C and collect all relevant callbacks
+ fun verify_and_collect(npropdef: AExternPropdef, callback_set: ForeignCallbackSet,
+ toolcontext: ToolContext) is abstract
+end
+
+redef class ALocalPropExternCall
+ redef fun verify_and_collect(npropdef, callback_set, toolcontext)
+ do
+ var mmodule = npropdef.mpropdef.mclassdef.mmodule
+ var mclass_type = npropdef.mpropdef.mclassdef.bound_mtype
+ var m_name = n_methid.collect_text
+ var method = toolcontext.modelbuilder.try_get_mproperty_by_name2( self,
+ mmodule, mclass_type, m_name )
+
+ if method == null then
+ toolcontext.error(location, "Local method {m_name} not found.")
+ return
+ end
+
+ var explicit_call = new MExplicitCall(mclass_type, method, mmodule)
+ callback_set.callbacks.add(explicit_call)
+
+ explicit_call.fill_type_for(callback_set, mmodule)
+ end
+end
+
+redef class AFullPropExternCall
+ redef fun verify_and_collect(npropdef, callback_set, toolcontext)
+ do
+ var mmodule = npropdef.mpropdef.mclassdef.mmodule
+ var mclassdef = npropdef.mpropdef.mclassdef
+ var nclassdef = toolcontext.modelbuilder.mclassdef2nclassdef[mclassdef]
+ var mclass_type = mclassdef.bound_mtype
+ var mtype = toolcontext.modelbuilder.resolve_mtype(nclassdef, n_type)
+
+ if mtype == null then return
+
+ if mtype isa MParameterType or mtype isa MVirtualType then
+ mtype = mtype.anchor_to(mmodule, mclass_type)
+ end
+
+ if mtype isa MNullableType then
+ toolcontext.error(location, "Type {n_type.collect_text} is nullable and thus cannot be the receiver." )
+ return
+ end
+
+ var m_name = n_methid.collect_text
+ var method = toolcontext.modelbuilder.try_get_mproperty_by_name2( self,
+ mmodule, mtype, m_name )
+
+ if method == null then
+ toolcontext.error(location, "Method {m_name} not found in {n_type.collect_text}." )
+ return
+ end
+
+ var explicit_call = new MExplicitCall(mtype.as(MClassType), method, mmodule)
+ callback_set.callbacks.add(explicit_call)
+ explicit_call.fill_type_for(callback_set, mmodule)
+ end
+end
+
+redef class AInitPropExternCall
+ redef fun verify_and_collect(npropdef, callback_set, toolcontext)
+ do
+ var mmodule = npropdef.mpropdef.mclassdef.mmodule
+ var mclassdef = npropdef.mpropdef.mclassdef
+ var nclassdef = toolcontext.modelbuilder.mclassdef2nclassdef[mclassdef]
+ var mtype = toolcontext.modelbuilder.resolve_mtype(nclassdef, n_type)
+ if mtype == null then return
+
+ if not mtype isa MClassType then
+ toolcontext.error(location, "Type {n_type.collect_text} is not a class and thus cannot be used to instanciate a new instance." )
+ return
+ end
+
+ var meth_name = "init"
+ var meth = toolcontext.modelbuilder.try_get_mproperty_by_name2( self,
+ mmodule, mtype, meth_name )
+
+ if meth == null then
+ toolcontext.error(location, "Method {meth_name} not found in {n_type.collect_text}." )
+ return
+ end
+
+ var explicit_call = new MExplicitCall(mtype, meth, mmodule)
+ callback_set.callbacks.add(explicit_call)
+ explicit_call.fill_type_for(callback_set, mmodule)
+ end
+end
+
+redef class ASuperExternCall
+ redef fun verify_and_collect(npropdef, callback_set, toolcontext)
+ do
+ callback_set.supers.add( new MExplicitSuper( npropdef.mpropdef.as(not null) ) )
+ callback_set.types.add( npropdef.mpropdef.mclassdef.mclass.mclass_type )
+ end
+end
+
+redef class ACastExternCall
+ fun from_mtype: MType is abstract
+ fun to_mtype: MType is abstract
+
+ redef fun verify_and_collect(npropdef, callback_set, toolcontext)
+ do
+ var from = from_mtype
+ var to = to_mtype
+
+ callback_set.types.add(from)
+ callback_set.types.add(to)
+
+ callback_set.casts.add(new MExplicitCast(from, to))
+ end
+end
+
+redef class ACastAsExternCall
+ redef fun from_mtype do return n_from_type.mtype.as(not null)
+ redef fun to_mtype do return n_to_type.mtype.as(not null)
+
+ redef fun verify_and_collect(npropdef, callback_set, toolcontext)
+ do
+ var parent_aclassdef = npropdef.parent.as(AClassdef)
+ toolcontext.modelbuilder.resolve_mtype_unchecked(parent_aclassdef, n_from_type, true)
+ toolcontext.modelbuilder.resolve_mtype_unchecked(parent_aclassdef, n_to_type, true)
+ super
+ end
+end
+
+redef class AAsNullableExternCall
+ redef fun from_mtype do return n_type.mtype.as(not null)
+ redef fun to_mtype do return n_type.mtype.as_nullable
+
+ redef fun verify_and_collect(npropdef, callback_set, toolcontext)
+ do
+ var parent_aclassdef = npropdef.parent.as(AClassdef)
+ toolcontext.modelbuilder.resolve_mtype_unchecked(parent_aclassdef, n_type, true)
+ super
+ end
+end
+
+redef class AAsNotNullableExternCall
+ redef fun from_mtype do return n_type.mtype.as_nullable
+ redef fun to_mtype do
+ var mtype = n_type.mtype.as(not null)
+ if mtype isa MNullableType then return mtype.mtype
+ return mtype
+ end
+
+ redef fun verify_and_collect(npropdef, callback_set, toolcontext)
+ do
+ var parent_aclassdef = npropdef.parent.as(AClassdef)
+ toolcontext.modelbuilder.resolve_mtype_unchecked(parent_aclassdef, n_type, true)
+ super
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Support utilities to use nitni and the FFI
+import nitni_base
+
+redef class MMethod
+ # Build a C function name for the FFI implementation (uses friendly naming).
+ # * On a specific static receiver mype `recv_mtype`
+ # * In referene to the module `from_module` (used for type resolving and as a possible prefix)
+ # * Has a possible `suffix` to the method name (may be "__super", "__impl", null, etc.)
+ # * With a specified length indicating whether it uses the sort name or the long name with
+ # the module name as prefix
+ fun build_cname(recv_mtype: MClassType, from_mmodule: MModule, suffix: nullable String, length: SignatureLength): String
+ do
+ var cname
+ if self.is_init then
+ if self.name == "init" or self.name == "new" then
+ cname = "new_{recv_mtype.mangled_cname}"
+ else
+ cname = "new_{recv_mtype.mangled_cname}_{self.short_cname}"
+ end
+ else
+ cname = "{recv_mtype.mangled_cname}_{self.short_cname}"
+ end
+
+ if suffix != null then cname = "{cname}{suffix}"
+
+ if length.long then cname = "{from_mmodule.name}___{cname}"
+
+ return cname
+ end
+
+ # Build a C function signature for the FFI implementation (uses friendly naming).
+ # * On a specific static receiver mype `recv_mtype`
+ # * In referene to the module `from_module` (used for type resolving and as a possible prefix)
+ # * Has a possible `suffix` to the method name (may be "__super", "__impl", null, etc.)
+ # * With a specified length indicating whether it uses the sort name or the long name with
+ # the module name as prefix
+ # * The `call_context` identifying which types and casts to use (see `CallContext` and its instances)
+ fun build_csignature(recv_mtype: MClassType, from_mmodule: MModule, suffix: nullable String, length: SignatureLength, call_context: CallContext): String
+ do
+ var signature = self.intro.msignature
+ assert signature != null
+
+ var creturn_type
+ if self.is_init then
+ creturn_type = call_context.name_mtype(recv_mtype)
+ else if signature.return_mtype != null then
+ var ret_mtype = signature.return_mtype
+ ret_mtype = ret_mtype.resolve_for(recv_mtype, recv_mtype, from_mmodule, true)
+ creturn_type = call_context.name_mtype(ret_mtype)
+ else
+ creturn_type = "void"
+ end
+
+ var cname = build_cname(recv_mtype, from_mmodule, suffix, length)
+
+ var cparams = new List[String]
+ if not self.is_init then
+ cparams.add( "{call_context.name_mtype(recv_mtype)} recv" )
+ end
+ for p in signature.mparameters do
+ var param_mtype = p.mtype.resolve_for(recv_mtype, recv_mtype, from_mmodule, true)
+ cparams.add( "{call_context.name_mtype(param_mtype)} {p.name}" )
+ end
+
+ return "{creturn_type} {cname}( {cparams.join(", ")} )"
+ end
+
+ # Build a C function call for the FFI implementation (uses friendly naming).
+ # * On a specific static receiver mype `recv_mtype`
+ # * In referene to the module `from_module` (used for type resolving and as a possible prefix)
+ # * Has a possible `suffix` to the method name (may be "__super", "__impl", null, etc.)
+ # * With a specified length indicating whether it uses the sort name or the long name with
+ # the module name as prefix
+ # * The `call_context` identifying which types and casts to use (see `CallContext` and its instances)
+ # * Possible suffix to the parameters `param_suffix`
+ fun build_ccall(recv_mtype: MClassType, from_mmodule: MModule, suffix: nullable String, length: SignatureLength, call_context: CallContext, param_suffix: nullable String): String
+ do
+ if param_suffix == null then param_suffix = ""
+
+ var signature = self.intro.msignature
+ assert signature != null
+
+ var return_mtype = null
+ if self.is_init then
+ return_mtype = recv_mtype
+ else if signature.return_mtype != null then
+ return_mtype = signature.return_mtype
+ end
+
+ var cname = build_cname(recv_mtype, from_mmodule, suffix, length)
+
+ var cparams = new List[String]
+ if not self.is_init then
+ cparams.add(call_context.cast_to(recv_mtype, "recv{param_suffix}"))
+ end
+
+ for p in signature.mparameters do
+ cparams.add(call_context.cast_to(p.mtype, "{p.name}{param_suffix}"))
+ end
+
+ var joined_cparams = cparams.join(", ")
+ var ccall = "{cname}({joined_cparams})"
+ if return_mtype != null then
+ return "return {call_context.cast_from(return_mtype, ccall)};"
+ else
+ return "{ccall};"
+ end
+ end
+end
+
+# Describes the context of the code to be generated by `build_ccall` and `build_csignature`
+class CallContext
+ # Which C name to use for type `mtype`
+ fun name_mtype(mtype: MType): String do return mtype.cname_blind
+
+ # How to cast a returned C variable named `name` of type `mtype`
+ fun cast_from(mtype: MType, name: String): String do return name
+
+ # How to cast a C argument named `name` of type `mtype`
+ fun cast_to(mtype: MType, name: String): String do return name
+end
+
+redef class Object
+ # Call context to use
+ protected fun internal_call_context: CallContext do return new CallContext
+ protected fun long_signature: SignatureLength do return once new SignatureLength(true)
+ protected fun short_signature: SignatureLength do return once new SignatureLength(false)
+end
+
+# Length of the signature of a C function (long version hase the module name as prefix)
+class SignatureLength
+ private var long: Bool
+ private init(long: Bool) do self.long = long
+end