ni: cleans up code repetition in native interface and improves performance
[nit.git] / src / native_interface / ni_metamodel.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2011 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 # Information relevant to the native interface
18 module ni_metamodel
19
20 import compiling
21 import primitive_info
22 import utils
23
24 redef class MMType
25
26 # Friendly name used by frontier and custom code.
27 # It's mainly the nit class name or the primitive type when available.
28 fun friendly_extern_name: String
29 do
30 var pi = local_class.primitive_info
31 if is_nullable then
32 return "nullable_{local_class.name.to_s}"
33 else if pi == null then
34 return local_class.name.to_s
35 else if local_class.global.is_extern then
36 return local_class.name.to_s
37 else
38 return pi.cname
39 end
40 end
41
42 fun mangled_name: String
43 do
44 var pi = local_class.primitive_info
45 if is_nullable then
46 return "nullable_{local_class.name.to_s}"
47 else
48 return local_class.name.to_s
49 end
50 end
51
52 # Return the expression to convert this type from its native version.
53 fun from_native( name : String ) : String
54 do
55 if ( local_class.primitive_info != null or local_class.global.is_extern ) and
56 not is_nullable then
57 return boxtype( name )
58 else
59 var getter = "{name}->ref.val"
60
61 return boxtype( getter )
62 end
63 end
64
65 # Return the expression to convert and assign this type to its
66 # friendly/native version.
67 fun assign_to_friendly( native_name, nit_name : String ) : String
68 do
69 if ( local_class.primitive_info != null or local_class.global.is_extern ) and
70 not is_nullable then
71 return "{native_name} = {unboxtype( nit_name )}"
72 else
73 return "{native_name}->ref.val = {unboxtype( nit_name )}"
74 end
75 end
76
77 # Return the expression to convert and assign this type to its
78 # generated C version, from friendly/native.
79 fun assign_from_friendly( nit_name, native_name : String ) : String
80 do
81 if ( local_class.primitive_info != null or local_class.global.is_extern ) and
82 not is_nullable then # int, float, point/void* ...
83 return "{nit_name} = {boxtype(native_name)}"
84 else
85 return "{nit_name} = {native_name}->ref.val"
86 end
87 end
88
89 fun uses_nitni_ref : Bool do return local_class.primitive_info == null or is_nullable
90
91 fun friendly_null_getter : String
92 do
93 return "null_{as_notnull.mangled_name}"
94 end
95
96 fun local_friendly_null_getter_from( m : MMModule ) : String
97 do
98 return "{m.to_s}_{friendly_null_getter}"
99 end
100 end
101
102 redef class MMMethod
103 # Local friendly name from a given module.
104 # Used to avoid conflits between modules.
105 fun local_friendly_name_from( m : MMModule, local_class : MMLocalClass ) : String
106 do
107 return "{m.to_s}_{friendly_extern_name(local_class)}"
108 end
109
110 fun friendly_super_cname : String
111 do
112 return "{friendly_extern_name(local_class)}___super"
113 end
114
115 fun local_friendly_super_name_from( m : MMModule ) : String
116 do
117 return "{m.to_s}_{friendly_super_cname}"
118 end
119
120 private fun friendly_cparams( local_class : MMLocalClass ) : List[ String ]
121 do
122 var params = new List[String]
123
124 if not global.is_init then
125 params.add( "{local_class.get_type.friendly_extern_name} recv" )
126 end
127
128 for p in signature.params do
129 params.add( "{p.mmtype.friendly_extern_name} {p.name}" )
130 end
131
132 return params
133 end
134
135 private fun csignature_with_suffix( suffix : String, local_class : MMLocalClass ) : String
136 do
137 var name = "{friendly_extern_name(local_class)}{suffix}"
138
139 return csignature_with_name( name, local_class )
140 end
141
142 private fun csignature_with_name( name : nullable String, local_class : MMLocalClass ) : String
143 do
144 var s = new Buffer
145
146 # return type
147 if signature.return_type != null then
148 s.append( "{signature.return_type.friendly_extern_name} " )
149 else if global.is_init then
150 s.append( "{local_class.get_type.friendly_extern_name} " )
151 else
152 s.append( "void " )
153 end
154
155 # function name
156 if name == null then
157 s.append( friendly_extern_name( local_class ) )
158 else
159 s.append( name )
160 end
161
162 # params
163 var params = friendly_cparams( local_class )
164
165 s.append( "( {params.join( ", " )} )" )
166
167 return s.to_s
168 end
169
170 fun friendly_csignature( local_class : MMLocalClass ) : String
171 do
172 return csignature_with_name( null, local_class )
173 end
174
175 fun frontier_csignature_from( m : MMModule, local_class : MMLocalClass ) : String
176 do
177 return csignature_with_name( local_friendly_name_from(m, local_class), local_class )
178 end
179
180 fun friendly_super_csignature : String
181 do
182 return csignature_with_suffix( "___super", local_class )
183 end
184
185 fun frontier_super_csignature_from( m : MMModule ) : String
186 do
187 return csignature_with_name( local_friendly_super_name_from(m), local_class )
188 end
189
190 fun impl_csignature : String
191 do
192 return csignature_with_suffix( "___impl", local_class )
193 end
194
195 # below is for frontier only
196 private fun cparams : List[ String ]
197 do
198 var params = new List[String]
199 if not global.is_init then params.add( "val_t recv" )
200 for p in signature.params do params.add( "val_t {p.name}" )
201 return params
202 end
203
204 fun out_csignature : String
205 do # boxed types
206 var s = new Buffer
207
208 # return type
209 if signature.return_type != null or global.is_init then
210 s.append( "val_t " )
211 else
212 s.append( "void " )
213 end
214
215 # function name
216 if global.is_init then
217 s.append( "NEW_{local_class}_{cname}" )
218 else
219 s.append( "{friendly_extern_name(local_class)}___out" )
220 end
221
222 # params
223 s.append( "( {cparams.join( ", " )} )" )
224
225 return s.to_s
226 end
227 end
228
229 redef class MMImportedCast
230
231 var in_name : String = "value"
232
233 fun as_friendly_extern_name : String do
234 if is_about_nullable_only then
235 if is_not_null_to_nullable then # to null
236 # nullable_Object Object_as_nullable( Object o )
237 return "{from.mangled_name}_as_nullable"
238 else if is_nullable_to_not_null then # from null
239 # Object Object_as_not_null( nullable_Object o )
240 return "{to.mangled_name}_as_not_null"
241 else
242 abort
243 end
244 else # inter types
245 # String Object_as_String( Object o )
246 return "{from.mangled_name}_as_{to.mangled_name}"
247 end
248 end
249
250 fun as_local_cname( m : MMModule ) : String do
251 return "{m.to_s}_{as_friendly_extern_name}"
252 end
253
254 fun as_local_csignature( m : MMModule ) : String
255 do
256 return "{to.friendly_extern_name} {as_local_cname( m )}( {from.friendly_extern_name} {in_name} )"
257 end
258
259 fun as_friendly_csignature : String
260 do
261 return "{to.friendly_extern_name} {as_friendly_extern_name}( {from.friendly_extern_name} {in_name} )"
262 end
263
264 fun is_a_friendly_extern_name : String do
265 if is_about_nullable_only then
266 if is_not_null_to_nullable then # to null
267 abort # would always be true
268 else if is_nullable_to_not_null then # from null
269 # Object_is_null( nullable_Object o )
270 # is opposite from others
271 return "{to.mangled_name}_is_null"
272 else
273 abort
274 end
275 else # inter types
276 # Object_is_a_String( Object o )
277 return "{from.mangled_name}_is_a_{to.mangled_name}"
278 end
279 end
280
281 fun is_a_local_cname( m : MMModule ) : String do
282 return "{m.to_s}_{is_a_friendly_extern_name}"
283 end
284
285 # Signature of function to check if an object of the "from" type is of
286 # the "to" type.
287 fun is_a_local_csignature( m : MMModule ) : String
288 do
289 return "int {is_a_local_cname( m )}( {from.friendly_extern_name} {in_name} )"
290 end
291
292 fun is_a_friendly_csignature : String
293 do
294 return "int {is_a_friendly_extern_name}( {from.friendly_extern_name} {in_name} )"
295 end
296
297 redef fun hash
298 do
299 return from.hash+to.hash
300 end
301 end