src: Update init
[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 type `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" or self.name == "defaultinit" 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.c_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 type `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 mmethoddef = lookup_first_definition(from_mmodule, recv_mtype)
57 var signature = mmethoddef.msignature
58 assert signature != null
59
60 var creturn_type
61 if self.is_init then
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)
67 else
68 creturn_type = "void"
69 end
70
71 var cname = build_cname(recv_mtype, from_mmodule, suffix, length)
72
73 var cparams = new List[String]
74 if not self.is_init then
75 cparams.add( "{call_context.name_mtype(recv_mtype)} self" )
76 end
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}" )
80 end
81
82 return "{creturn_type} {cname}( {cparams.join(", ")} )"
83 end
84
85 # Build a C function call for the FFI implementation (uses friendly naming).
86 # * On a specific static receiver type `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
94 do
95 if param_suffix == null then param_suffix = ""
96
97 var mmethoddef = lookup_first_definition(from_mmodule, recv_mtype)
98 var signature = mmethoddef.msignature
99 assert signature != null
100
101 var return_mtype = null
102 if self.is_init then
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)
107 end
108
109 var cname = build_cname(recv_mtype, from_mmodule, suffix, length)
110
111 var cparams = new List[String]
112 if not self.is_init then
113 cparams.add(call_context.cast_to(recv_mtype, "self{param_suffix}"))
114 end
115
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}"))
119 end
120
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)};"
125 else
126 return "{ccall};"
127 end
128 end
129 end
130
131 # Describes the context of the code to be generated by `build_ccall` and `build_csignature`
132 class CallContext
133 # Which C name to use for type `mtype`
134 fun name_mtype(mtype: MType): String do return mtype.cname_blind
135
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
138
139 # How to cast a C argument named `name` of type `mtype`
140 fun cast_to(mtype: MType, name: String): String do return name
141 end
142
143 # Call context to use
144 fun internal_call_context: CallContext do return new CallContext
145 fun long_signature: SignatureLength do return once new SignatureLength(true)
146 fun short_signature: SignatureLength do return once new SignatureLength(false)
147
148 # Length of the signature of a C function (long version hase the module name as prefix)
149 class SignatureLength
150 private var long: Bool
151
152 # TODO: private init because singleton class.
153 end