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 mmethoddef
= lookup_first_definition
(from_mmodule
, recv_mtype
)
57 var signature
= mmethoddef
.msignature
58 assert signature
!= null
62 creturn_type
= call_context
.name_mtype
(recv_mtype
)
63 else if signature
.return_mtype
!= null then
64 var ret_mtype
= signature
.return_mtype
65 ret_mtype
= ret_mtype
.resolve_for
(recv_mtype
, recv_mtype
, from_mmodule
, true)
66 creturn_type
= call_context
.name_mtype
(ret_mtype
)
71 var cname
= build_cname
(recv_mtype
, from_mmodule
, suffix
, length
)
73 var cparams
= new List[String]
74 if not self.is_init
then
75 cparams
.add
( "{call_context.name_mtype(recv_mtype)} recv" )
77 for p
in signature
.mparameters
do
78 var param_mtype
= p
.mtype
.resolve_for
(recv_mtype
, recv_mtype
, from_mmodule
, true)
79 cparams
.add
( "{call_context.name_mtype(param_mtype)} {p.name}" )
82 return "{creturn_type} {cname}( {cparams.join(", ")} )"
85 # Build a C function call for the FFI implementation (uses friendly naming).
86 # * On a specific static receiver mype `recv_mtype`
87 # * In referene to the module `from_module` (used for type resolving and as a possible prefix)
88 # * Has a possible `suffix` to the method name (may be "__super", "__impl", null, etc.)
89 # * With a specified length indicating whether it uses the sort name or the long name with
90 # the module name as prefix
91 # * The `call_context` identifying which types and casts to use (see `CallContext` and its instances)
92 # * Possible suffix to the parameters `param_suffix`
93 fun build_ccall
(recv_mtype
: MClassType, from_mmodule
: MModule, suffix
: nullable String, length
: SignatureLength, call_context
: CallContext, param_suffix
: nullable String): String
95 if param_suffix
== null then param_suffix
= ""
97 var mmethoddef
= lookup_first_definition
(from_mmodule
, recv_mtype
)
98 var signature
= mmethoddef
.msignature
99 assert signature
!= null
101 var return_mtype
= null
103 return_mtype
= recv_mtype
104 else if signature
.return_mtype
!= null then
105 return_mtype
= signature
.return_mtype
106 return_mtype
= return_mtype
.resolve_for
(recv_mtype
, recv_mtype
, from_mmodule
, true)
109 var cname
= build_cname
(recv_mtype
, from_mmodule
, suffix
, length
)
111 var cparams
= new List[String]
112 if not self.is_init
then
113 cparams
.add
(call_context
.cast_to
(recv_mtype
, "recv{param_suffix}"))
116 for p
in signature
.mparameters
do
117 var param_mtype
= p
.mtype
.resolve_for
(recv_mtype
, recv_mtype
, from_mmodule
, true)
118 cparams
.add
(call_context
.cast_to
(param_mtype
, "{p.name}{param_suffix}"))
121 var joined_cparams
= cparams
.join
(", ")
122 var ccall
= "{cname}({joined_cparams})"
123 if return_mtype
!= null then
124 return "return {call_context.cast_from(return_mtype, ccall)};"
131 # Describes the context of the code to be generated by `build_ccall` and `build_csignature`
133 # Which C name to use for type `mtype`
134 fun name_mtype
(mtype
: MType): String do return mtype
.cname_blind
136 # How to cast a returned C variable named `name` of type `mtype`
137 fun cast_from
(mtype
: MType, name
: String): String do return name
139 # How to cast a C argument named `name` of type `mtype`
140 fun cast_to
(mtype
: MType, name
: String): String do return name
144 # Call context to use
145 protected fun internal_call_context
: CallContext do return new CallContext
146 protected fun long_signature
: SignatureLength do return once
new SignatureLength(true)
147 protected fun short_signature
: SignatureLength do return once
new SignatureLength(false)
150 # Length of the signature of a C function (long version hase the module name as prefix)
151 class SignatureLength
152 private var long
: Bool
153 private init(long
: Bool) do self.long
= long