1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2012-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 # nitni services related to callbacks (used underneath the FFI)
18 module nitni_callbacks
21 intrude import rapid_type_analysis
25 redef class ToolContext
26 var verify_nitni_callback_phase
: Phase = new VerifyNitniCallbacksPhase(self, [typing_phase
])
29 # * checks for the validity of callbacks
30 # * store the callbacks on each method
31 class VerifyNitniCallbacksPhase
34 redef fun process_npropdef
(npropdef
)
36 if not npropdef
isa AExternPropdef then return
38 npropdef
.verify_nitni_callbacks
(toolcontext
)
42 # Provides a better API but mainly the same content as AExternCalls
43 class ForeignCallbackSet
44 # set of imported functions, cached to avoid repetitions
45 var callbacks
: Set[ MExplicitCall ] = new HashSet[ MExplicitCall ]
47 # set of imported functions, cached to avoid repetitions
48 var supers
: Set[ MExplicitSuper ] = new HashSet[ MExplicitSuper ]
50 # set of relevant types, cached to avoid repetitions
51 var types
: Set[ MType ] = new HashSet[ MType ]
53 # set of imported casts and as, cached to avoid repetitions
54 var casts
: Set[ MExplicitCast ] = new HashSet[ MExplicitCast ]
56 # Utility function, must be called only when all other maps are filled
57 private var all_cached
: nullable Set[NitniCallback] = null
58 fun all
: Set[NitniCallback]
60 var cached
= all_cached
61 if cached
!= null then return cached
63 var set
= new HashSet[NitniCallback]
64 set
.add_all
(callbacks
)
73 # Integrate content from the `other` set into this one
74 fun join
(other
: ForeignCallbackSet)
76 callbacks
.add_all
( other
.callbacks
)
77 supers
.add_all
( other
.supers
)
78 types
.add_all
( other
.types
)
79 casts
.add_all
( other
.casts
)
83 redef class AExternPropdef
84 private var foreign_callbacks_cache
: nullable ForeignCallbackSet = null
86 # All foreign callbacks from this method
87 fun foreign_callbacks
: ForeignCallbackSet
89 var fcs
= foreign_callbacks_cache
90 assert fcs
!= null else print
"Error: attempting to access nitni callbacks before phase 'verify_nitni_callback_phase'."
94 # Verifiy the validity of the explicit callbacks to Nit
95 # also fills the set returned by foreign_callbacks
96 fun verify_nitni_callbacks
(toolcontext
: ToolContext)
98 if foreign_callbacks_cache
!= null then return
100 var fcs
= new ForeignCallbackSet
102 var mmodule
= mpropdef
.mclassdef
.mmodule
105 var recv_type
= mpropdef
.mclassdef
.bound_mtype
106 fcs
.types
.add
(recv_type
)
109 var rmt
= mpropdef
.msignature
.return_mtype
111 if rmt
isa MParameterType or rmt
isa MVirtualType then
112 var mclass_type
= mpropdef
.mclassdef
.bound_mtype
113 rmt
= rmt
.anchor_to
(mmodule
, mclass_type
)
115 var mtype
= rmt
.resolve_for
(recv_type
, recv_type
, mmodule
, true)
120 for p
in mpropdef
.msignature
.mparameters
do
121 var mtype
= p
.mtype
.resolve_for
(recv_type
, recv_type
, mmodule
, true)
122 if mtype
isa MParameterType or mtype
isa MVirtualType then
123 var mclass_type
= mpropdef
.mclassdef
.bound_mtype
124 mtype
= mtype
.anchor_to
(mmodule
, mclass_type
)
126 fcs
.types
.add
( mtype
)
130 if n_extern_calls
!= null then
131 for ec
in n_extern_calls
.n_extern_calls
do
132 ec
.verify_and_collect
(self, fcs
, toolcontext
)
137 foreign_callbacks_cache
= fcs
140 redef fun accept_rapid_type_visitor
(v
)
142 for cb
in foreign_callbacks
.callbacks
do v
.add_send
(cb
.recv_mtype
, cb
.mproperty
.as(MMethod))
143 for cast
in foreign_callbacks
.casts
do v
.add_cast_type
(cast
.to
)
144 for sup
in foreign_callbacks
.supers
do
145 v
.analysis
.add_super_send
(sup
.from
.mclassdef
.mclass
.mclass_type
, sup
.from
.as(MMethodDef))
147 for t
in foreign_callbacks
.types
do if t
isa MClassType then v
.add_type t
151 # Classification for all nitni callbacks
152 interface NitniCallback
159 # A prossible call from C, declared explictly after the `import` keyword
163 # Previously resolved mtype
164 var recv_mtype
: MClassType
165 var mproperty
: MProperty
166 var from_mmodule
: MModule
168 fun fill_type_for
( callback_set
: ForeignCallbackSet, from
: MModule )
170 var first
= mproperty
.lookup_first_definition
( from
, recv_mtype
)
171 var mclassdef
= first
.mclassdef
172 var bound_mtype
= mclassdef
.bound_mtype
174 # receiver / constructor return
175 recv_mtype
= recv_mtype
.resolve_for
(bound_mtype
, bound_mtype
, from
, true)
176 recv_mtype
= recv_mtype
.anchor_to
(from
, bound_mtype
)
177 callback_set
.types
.add
( recv_mtype
)
179 if first
isa MMethodDef then
180 var rmt
= first
.msignature
.return_mtype
182 rmt
= rmt
.resolve_for
(bound_mtype
, bound_mtype
, from
, true)
183 rmt
= rmt
.anchor_to
(from
, bound_mtype
)
184 callback_set
.types
.add
( rmt
)
187 for p
in first
.msignature
.mparameters
do
188 var param_mtype
= p
.mtype
.resolve_for
(recv_mtype
, recv_mtype
, from
, true)
189 param_mtype
= param_mtype
.resolve_for
(bound_mtype
, bound_mtype
, from
, true)
190 param_mtype
= param_mtype
.anchor_to
(from
, bound_mtype
)
191 callback_set
.types
.add
( param_mtype
)
196 # Signature of this call in C as seen by user
197 fun csignature
: String
199 var mproperty
= self.mproperty
200 if mproperty
isa MMethod then
201 var signature
= mproperty
.intro
.msignature
202 assert signature
!= null
205 if mproperty
.is_init
then
206 creturn_type
= recv_mtype
.cname
207 else if signature
.return_mtype
!= null then
208 var ret_mtype
= signature
.return_mtype
209 ret_mtype
= ret_mtype
.resolve_for
(recv_mtype
, recv_mtype
, from_mmodule
, true)
210 creturn_type
= ret_mtype
.cname
212 creturn_type
= "void"
216 if mproperty
.is_init
then
217 if mproperty
.name
== "init" or mproperty
.name
== "new" then
218 cname
= "new_{recv_mtype.mangled_cname}"
220 cname
= "new_{recv_mtype.mangled_cname}_{mproperty.short_cname}"
223 cname
= "{recv_mtype.mangled_cname}_{mproperty.short_cname}"
226 var cparams
= new List[String]
227 if not mproperty
.is_init
then
228 cparams
.add
( "{recv_mtype.cname} self" )
230 for p
in signature
.mparameters
do
231 var param_mtype
= p
.mtype
.resolve_for
(recv_mtype
, recv_mtype
, from_mmodule
, true)
232 cparams
.add
( "{param_mtype.cname} {p.name}" )
235 return "{creturn_type} {cname}( {cparams.join(", ")} )"
237 print
"Type of callback from foreign code not yet supported."
242 redef fun hash
do return recv_mtype
.hash
+ 1024 * mproperty
.hash
243 redef fun ==(o
) do return o
isa MExplicitCall and recv_mtype
== o
.recv_mtype
and mproperty
== o
.mproperty
251 redef fun hash
do return from
.hash
252 redef fun ==(o
) do return o
isa MExplicitSuper and from
== o
.from
261 fun check_cname
: String do return "{from.mangled_cname}_is_a_{to.mangled_cname}"
263 fun cast_cname
: String do return "{from.mangled_cname}_as_{to.mangled_cname}"
265 redef fun hash
do return from
.hash
+ 1024 * to
.hash
266 redef fun ==(o
) do return o
isa MExplicitCast and from
== o
.from
and to
== o
.to
269 redef class AExternCall
270 # Verify this explicit declaration of call from C and collect all relevant callbacks
271 fun verify_and_collect
(npropdef
: AMethPropdef, callback_set
: ForeignCallbackSet,
272 toolcontext
: ToolContext) is abstract
275 redef class ALocalPropExternCall
276 redef fun verify_and_collect
(npropdef
, callback_set
, toolcontext
)
278 var mmodule
= npropdef
.mpropdef
.mclassdef
.mmodule
279 var mclass_type
= npropdef
.mpropdef
.mclassdef
.bound_mtype
280 var m_name
= n_methid
.collect_text
281 var method
= toolcontext
.modelbuilder
.try_get_mproperty_by_name2
( self,
282 mmodule
, mclass_type
, m_name
)
284 if method
== null then
285 toolcontext
.error
(location
, "Local method {m_name} not found.")
289 var explicit_call
= new MExplicitCall(mclass_type
, method
, mmodule
)
290 callback_set
.callbacks
.add
(explicit_call
)
292 explicit_call
.fill_type_for
(callback_set
, mmodule
)
296 redef class AFullPropExternCall
297 redef fun verify_and_collect
(npropdef
, callback_set
, toolcontext
)
299 var mmodule
= npropdef
.mpropdef
.mclassdef
.mmodule
300 var mclassdef
= npropdef
.mpropdef
.mclassdef
301 var mclass_type
= mclassdef
.bound_mtype
302 var mtype
= toolcontext
.modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, n_type
)
304 if mtype
== null then return
306 if mtype
isa MParameterType or mtype
isa MVirtualType then
307 mtype
= mtype
.anchor_to
(mmodule
, mclass_type
)
310 if mtype
isa MNullableType then
311 toolcontext
.error
(location
, "Type {n_type.collect_text} is nullable and thus cannot be the receiver." )
315 var m_name
= n_methid
.collect_text
316 var method
= toolcontext
.modelbuilder
.try_get_mproperty_by_name2
( self,
317 mmodule
, mtype
, m_name
)
319 if method
== null then
320 toolcontext
.error
(location
, "Method {m_name} not found in {n_type.collect_text}." )
324 var explicit_call
= new MExplicitCall(mtype
.as(MClassType), method
, mmodule
)
325 callback_set
.callbacks
.add
(explicit_call
)
326 explicit_call
.fill_type_for
(callback_set
, mmodule
)
330 redef class AInitPropExternCall
331 redef fun verify_and_collect
(npropdef
, callback_set
, toolcontext
)
333 var mmodule
= npropdef
.mpropdef
.mclassdef
.mmodule
334 var mclassdef
= npropdef
.mpropdef
.mclassdef
335 var mtype
= toolcontext
.modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, n_type
)
336 if mtype
== null then return
338 if not mtype
isa MClassType then
339 toolcontext
.error
(location
, "Type {n_type.collect_text} is not a class and thus cannot be used to instanciate a new instance." )
343 var meth_name
= "init"
344 var meth
= toolcontext
.modelbuilder
.try_get_mproperty_by_name2
( self,
345 mmodule
, mtype
, meth_name
)
348 toolcontext
.error
(location
, "Method {meth_name} not found in {n_type.collect_text}." )
352 var explicit_call
= new MExplicitCall(mtype
, meth
, mmodule
)
353 callback_set
.callbacks
.add
(explicit_call
)
354 explicit_call
.fill_type_for
(callback_set
, mmodule
)
358 redef class ASuperExternCall
359 redef fun verify_and_collect
(npropdef
, callback_set
, toolcontext
)
361 callback_set
.supers
.add
( new MExplicitSuper( npropdef
.mpropdef
.as(not null) ) )
362 callback_set
.types
.add
( npropdef
.mpropdef
.mclassdef
.mclass
.mclass_type
)
363 npropdef
.mpropdef
.has_supercall
= true
367 redef class ACastExternCall
368 fun from_mtype
: MType is abstract
369 fun to_mtype
: MType is abstract
371 redef fun verify_and_collect
(npropdef
, callback_set
, toolcontext
)
373 var from
= from_mtype
376 callback_set
.types
.add
(from
)
377 callback_set
.types
.add
(to
)
379 callback_set
.casts
.add
(new MExplicitCast(from
, to
))
383 redef class ACastAsExternCall
384 redef fun from_mtype
do return n_from_type
.mtype
.as(not null)
385 redef fun to_mtype
do return n_to_type
.mtype
.as(not null)
387 redef fun verify_and_collect
(npropdef
, callback_set
, toolcontext
)
389 var mclassdef
= npropdef
.mpropdef
.mclassdef
390 var mmodule
= mclassdef
.mmodule
391 toolcontext
.modelbuilder
.resolve_mtype_unchecked
(mmodule
, mclassdef
, n_from_type
, true)
392 toolcontext
.modelbuilder
.resolve_mtype_unchecked
(mmodule
, mclassdef
, n_to_type
, true)
397 redef class AAsNullableExternCall
398 redef fun from_mtype
do return n_type
.mtype
.as(not null)
399 redef fun to_mtype
do return n_type
.mtype
.as_nullable
401 redef fun verify_and_collect
(npropdef
, callback_set
, toolcontext
)
403 var mclassdef
= npropdef
.mpropdef
.mclassdef
404 var mmodule
= mclassdef
.mmodule
405 toolcontext
.modelbuilder
.resolve_mtype_unchecked
(mmodule
, mclassdef
, n_type
, true)
410 redef class AAsNotNullableExternCall
411 redef fun from_mtype
do return n_type
.mtype
.as_nullable
412 redef fun to_mtype
do
413 var mtype
= n_type
.mtype
.as(not null)
414 if mtype
isa MNullableType then return mtype
.mtype
418 redef fun verify_and_collect
(npropdef
, callback_set
, toolcontext
)
420 var mclassdef
= npropdef
.mpropdef
.mclassdef
421 var mmodule
= mclassdef
.mmodule
422 toolcontext
.modelbuilder
.resolve_mtype_unchecked
(mmodule
, mclassdef
, n_type
, true)