1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Support utilities to use nitni and the FFI
21 # Build a C function name for the FFI implementation (uses friendly naming).
22 # * On a specific static receiver mype `recv_mtype`
23 # * In referene to the module `from_module` (used for type resolving and as a possible prefix)
24 # * Has a possible `suffix` to the method name (may be "__super", "__impl", null, etc.)
25 # * With a specified length indicating whether it uses the sort name or the long name with
26 # the module name as prefix
27 fun build_cname
(recv_mtype
: MClassType, from_mmodule
: MModule, suffix
: nullable String, length
: SignatureLength): String
31 if self.name
== "init" or self.name
== "new" then
32 cname
= "new_{recv_mtype.mangled_cname}"
34 cname
= "new_{recv_mtype.mangled_cname}_{self.short_cname}"
37 cname
= "{recv_mtype.mangled_cname}_{self.short_cname}"
40 if suffix
!= null then cname
= "{cname}{suffix}"
42 if length
.long
then cname
= "{from_mmodule.name}___{cname}"
47 # Build a C function signature for the FFI implementation (uses friendly naming).
48 # * On a specific static receiver mype `recv_mtype`
49 # * In referene to the module `from_module` (used for type resolving and as a possible prefix)
50 # * Has a possible `suffix` to the method name (may be "__super", "__impl", null, etc.)
51 # * With a specified length indicating whether it uses the sort name or the long name with
52 # the module name as prefix
53 # * The `call_context` identifying which types and casts to use (see `CallContext` and its instances)
54 fun build_csignature
(recv_mtype
: MClassType, from_mmodule
: MModule, suffix
: nullable String, length
: SignatureLength, call_context
: CallContext): String
56 var signature
= self.intro
.msignature
57 assert signature
!= null
61 creturn_type
= call_context
.name_mtype
(recv_mtype
)
62 else if signature
.return_mtype
!= null then
63 var ret_mtype
= signature
.return_mtype
64 ret_mtype
= ret_mtype
.resolve_for
(recv_mtype
, recv_mtype
, from_mmodule
, true)
65 creturn_type
= call_context
.name_mtype
(ret_mtype
)
70 var cname
= build_cname
(recv_mtype
, from_mmodule
, suffix
, length
)
72 var cparams
= new List[String]
73 if not self.is_init
then
74 cparams
.add
( "{call_context.name_mtype(recv_mtype)} recv" )
76 for p
in signature
.mparameters
do
77 var param_mtype
= p
.mtype
.resolve_for
(recv_mtype
, recv_mtype
, from_mmodule
, true)
78 cparams
.add
( "{call_context.name_mtype(param_mtype)} {p.name}" )
81 return "{creturn_type} {cname}( {cparams.join(", ")} )"
84 # Build a C function call for the FFI implementation (uses friendly naming).
85 # * On a specific static receiver mype `recv_mtype`
86 # * In referene to the module `from_module` (used for type resolving and as a possible prefix)
87 # * Has a possible `suffix` to the method name (may be "__super", "__impl", null, etc.)
88 # * With a specified length indicating whether it uses the sort name or the long name with
89 # the module name as prefix
90 # * The `call_context` identifying which types and casts to use (see `CallContext` and its instances)
91 # * Possible suffix to the parameters `param_suffix`
92 fun build_ccall
(recv_mtype
: MClassType, from_mmodule
: MModule, suffix
: nullable String, length
: SignatureLength, call_context
: CallContext, param_suffix
: nullable String): String
94 if param_suffix
== null then param_suffix
= ""
96 var signature
= self.intro
.msignature
97 assert signature
!= null
99 var return_mtype
= null
101 return_mtype
= recv_mtype
102 else if signature
.return_mtype
!= null then
103 return_mtype
= signature
.return_mtype
106 var cname
= build_cname
(recv_mtype
, from_mmodule
, suffix
, length
)
108 var cparams
= new List[String]
109 if not self.is_init
then
110 cparams
.add
(call_context
.cast_to
(recv_mtype
, "recv{param_suffix}"))
113 for p
in signature
.mparameters
do
114 cparams
.add
(call_context
.cast_to
(p
.mtype
, "{p.name}{param_suffix}"))
117 var joined_cparams
= cparams
.join
(", ")
118 var ccall
= "{cname}({joined_cparams})"
119 if return_mtype
!= null then
120 return "return {call_context.cast_from(return_mtype, ccall)};"
127 # Describes the context of the code to be generated by `build_ccall` and `build_csignature`
129 # Which C name to use for type `mtype`
130 fun name_mtype
(mtype
: MType): String do return mtype
.cname_blind
132 # How to cast a returned C variable named `name` of type `mtype`
133 fun cast_from
(mtype
: MType, name
: String): String do return name
135 # How to cast a C argument named `name` of type `mtype`
136 fun cast_to
(mtype
: MType, name
: String): String do return name
140 # Call context to use
141 protected fun internal_call_context
: CallContext do return new CallContext
142 protected fun long_signature
: SignatureLength do return once
new SignatureLength(true)
143 protected fun short_signature
: SignatureLength do return once
new SignatureLength(false)
146 # Length of the signature of a C function (long version hase the module name as prefix)
147 class SignatureLength
148 private var long
: Bool
149 private init(long
: Bool) do self.long
= long