nitg: intro the nitni module
[nit.git] / src / nitni / nitni_utilities.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net>
4 #
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
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
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.
16
17 # Support utilities to use nitni and the FFI
18 import nitni_base
19
20 redef class MMethod
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
28 do
29 var cname
30 if self.is_init then
31 if self.name == "init" or self.name == "new" then
32 cname = "new_{recv_mtype.mangled_cname}"
33 else
34 cname = "new_{recv_mtype.mangled_cname}_{self.short_cname}"
35 end
36 else
37 cname = "{recv_mtype.mangled_cname}_{self.short_cname}"
38 end
39
40 if suffix != null then cname = "{cname}{suffix}"
41
42 if length.long then cname = "{from_mmodule.name}___{cname}"
43
44 return cname
45 end
46
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
55 do
56 var signature = self.intro.msignature
57 assert signature != null
58
59 var creturn_type
60 if self.is_init then
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)
66 else
67 creturn_type = "void"
68 end
69
70 var cname = build_cname(recv_mtype, from_mmodule, suffix, length)
71
72 var cparams = new List[String]
73 if not self.is_init then
74 cparams.add( "{call_context.name_mtype(recv_mtype)} recv" )
75 end
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}" )
79 end
80
81 return "{creturn_type} {cname}( {cparams.join(", ")} )"
82 end
83
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
93 do
94 if param_suffix == null then param_suffix = ""
95
96 var signature = self.intro.msignature
97 assert signature != null
98
99 var return_mtype = null
100 if self.is_init then
101 return_mtype = recv_mtype
102 else if signature.return_mtype != null then
103 return_mtype = signature.return_mtype
104 end
105
106 var cname = build_cname(recv_mtype, from_mmodule, suffix, length)
107
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}"))
111 end
112
113 for p in signature.mparameters do
114 cparams.add(call_context.cast_to(p.mtype, "{p.name}{param_suffix}"))
115 end
116
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)};"
121 else
122 return "{ccall};"
123 end
124 end
125 end
126
127 # Describes the context of the code to be generated by `build_ccall` and `build_csignature`
128 class CallContext
129 # Which C name to use for type `mtype`
130 fun name_mtype(mtype: MType): String do return mtype.cname_blind
131
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
134
135 # How to cast a C argument named `name` of type `mtype`
136 fun cast_to(mtype: MType, name: String): String do return name
137 end
138
139 redef class Object
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)
144 end
145
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
150 end