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 AMethPropdef then return
37 var mpropdef
= npropdef
.mpropdef
38 if mpropdef
== null then return
39 if not mpropdef
.is_extern
then return
41 npropdef
.verify_nitni_callbacks
(toolcontext
)
45 # Provides a better API but mainly the same content as AExternCalls
46 class ForeignCallbackSet
47 # set of imported functions, cached to avoid repetitions
48 var callbacks
: Set[ MExplicitCall ] = new HashSet[ MExplicitCall ]
50 # set of imported functions, cached to avoid repetitions
51 var supers
: Set[ MExplicitSuper ] = new HashSet[ MExplicitSuper ]
53 # set of relevant types, cached to avoid repetitions
54 var types
: Set[ MType ] = new HashSet[ MType ]
56 # set of imported casts and as, cached to avoid repetitions
57 var casts
: Set[ MExplicitCast ] = new HashSet[ MExplicitCast ]
59 # Utility function, must be called only when all other maps are filled
60 private var all_cached
: nullable Set[NitniCallback] = null
61 fun all
: Set[NitniCallback]
63 var cached
= all_cached
64 if cached
!= null then return cached
66 var set
= new HashSet[NitniCallback]
67 set
.add_all
(callbacks
)
76 # Integrate content from the `other` set into this one
77 fun join
(other
: ForeignCallbackSet)
79 callbacks
.add_all
( other
.callbacks
)
80 supers
.add_all
( other
.supers
)
81 types
.add_all
( other
.types
)
82 casts
.add_all
( other
.casts
)
86 redef class AMethPropdef
87 private var foreign_callbacks_cache
: nullable ForeignCallbackSet = null
89 # All foreign callbacks from this method
90 fun foreign_callbacks
: ForeignCallbackSet
92 var fcs
= foreign_callbacks_cache
93 assert fcs
!= null else print
"Error: attempting to access nitni callbacks before phase 'verify_nitni_callback_phase'."
97 # Verifiy the validity of the explicit callbacks to Nit
98 # also fills the set returned by foreign_callbacks
99 fun verify_nitni_callbacks
(toolcontext
: ToolContext)
101 if foreign_callbacks_cache
!= null then return
103 var fcs
= new ForeignCallbackSet
105 var mmodule
= mpropdef
.mclassdef
.mmodule
108 var recv_type
= mpropdef
.mclassdef
.bound_mtype
109 fcs
.types
.add
(recv_type
)
112 var rmt
= mpropdef
.msignature
.return_mtype
114 if rmt
isa MParameterType or rmt
isa MVirtualType then
115 var mclass_type
= mpropdef
.mclassdef
.bound_mtype
116 rmt
= rmt
.anchor_to
(mmodule
, mclass_type
)
118 var mtype
= rmt
.resolve_for
(recv_type
, recv_type
, mmodule
, true)
123 for p
in mpropdef
.msignature
.mparameters
do
124 var mtype
= p
.mtype
.resolve_for
(recv_type
, recv_type
, mmodule
, true)
125 if mtype
isa MParameterType or mtype
isa MVirtualType then
126 var mclass_type
= mpropdef
.mclassdef
.bound_mtype
127 mtype
= mtype
.anchor_to
(mmodule
, mclass_type
)
129 fcs
.types
.add
( mtype
)
133 if n_extern_calls
!= null then
134 for ec
in n_extern_calls
.n_extern_calls
do
135 ec
.verify_and_collect
(self, fcs
, toolcontext
)
140 foreign_callbacks_cache
= fcs
143 redef fun accept_rapid_type_visitor
(v
)
145 if foreign_callbacks_cache
== null then return
147 for cb
in foreign_callbacks
.callbacks
do v
.add_send
(cb
.recv_mtype
, cb
.mproperty
.as(MMethod))
148 for cast
in foreign_callbacks
.casts
do v
.add_cast_type
(cast
.to
)
149 for sup
in foreign_callbacks
.supers
do
150 v
.analysis
.add_super_send
(sup
.from
.mclassdef
.mclass
.mclass_type
, sup
.from
.as(MMethodDef))
152 for t
in foreign_callbacks
.types
do if t
isa MClassType then v
.add_type t
156 # Classification for all nitni callbacks
157 interface NitniCallback
164 # A prossible call from C, declared explictly after the `import` keyword
168 # Previously resolved mtype
169 var recv_mtype
: MClassType
170 var mproperty
: MProperty
171 var from_mmodule
: MModule
173 fun fill_type_for
( callback_set
: ForeignCallbackSet, from
: MModule )
175 var first
= mproperty
.lookup_first_definition
( from
, recv_mtype
)
176 var mclassdef
= first
.mclassdef
177 var bound_mtype
= mclassdef
.bound_mtype
179 # receiver / constructor return
180 recv_mtype
= recv_mtype
.resolve_for
(bound_mtype
, bound_mtype
, from
, true)
181 recv_mtype
= recv_mtype
.anchor_to
(from
, bound_mtype
)
182 callback_set
.types
.add
( recv_mtype
)
184 if first
isa MMethodDef then
185 var rmt
= first
.msignature
.return_mtype
187 rmt
= rmt
.resolve_for
(bound_mtype
, bound_mtype
, from
, true)
188 rmt
= rmt
.anchor_to
(from
, bound_mtype
)
189 callback_set
.types
.add
( rmt
)
192 for p
in first
.msignature
.mparameters
do
193 var param_mtype
= p
.mtype
.resolve_for
(recv_mtype
, recv_mtype
, from
, true)
194 param_mtype
= param_mtype
.resolve_for
(bound_mtype
, bound_mtype
, from
, true)
195 param_mtype
= param_mtype
.anchor_to
(from
, bound_mtype
)
196 callback_set
.types
.add
( param_mtype
)
201 # Signature of this call in C as seen by user
202 fun csignature
: String
204 var mproperty
= self.mproperty
205 if mproperty
isa MMethod then
206 var signature
= mproperty
.intro
.msignature
207 assert signature
!= null
210 if mproperty
.is_init
then
211 creturn_type
= recv_mtype
.cname
212 else if signature
.return_mtype
!= null then
213 var ret_mtype
= signature
.return_mtype
214 ret_mtype
= ret_mtype
.resolve_for
(recv_mtype
, recv_mtype
, from_mmodule
, true)
215 creturn_type
= ret_mtype
.cname
217 creturn_type
= "void"
221 if mproperty
.is_init
then
222 if mproperty
.name
== "init" or mproperty
.name
== "new" then
223 cname
= "new_{recv_mtype.mangled_cname}"
225 cname
= "new_{recv_mtype.mangled_cname}_{mproperty.short_cname}"
228 cname
= "{recv_mtype.mangled_cname}_{mproperty.short_cname}"
231 var cparams
= new List[String]
232 if not mproperty
.is_init
then
233 cparams
.add
( "{recv_mtype.cname} self" )
235 for p
in signature
.mparameters
do
236 var param_mtype
= p
.mtype
.resolve_for
(recv_mtype
, recv_mtype
, from_mmodule
, true)
237 cparams
.add
( "{param_mtype.cname} {p.name}" )
240 return "{creturn_type} {cname}( {cparams.join(", ")} )"
242 print
"Type of callback from foreign code not yet supported."
247 redef fun hash
do return recv_mtype
.hash
+ 1024 * mproperty
.hash
248 redef fun ==(o
) do return o
isa MExplicitCall and recv_mtype
== o
.recv_mtype
and mproperty
== o
.mproperty
256 redef fun hash
do return from
.hash
257 redef fun ==(o
) do return o
isa MExplicitSuper and from
== o
.from
266 fun check_cname
: String do return "{from.mangled_cname}_is_a_{to.mangled_cname}"
268 fun cast_cname
: String do return "{from.mangled_cname}_as_{to.mangled_cname}"
270 redef fun hash
do return from
.hash
+ 1024 * to
.hash
271 redef fun ==(o
) do return o
isa MExplicitCast and from
== o
.from
and to
== o
.to
274 redef class AExternCall
275 # Verify this explicit declaration of call from C and collect all relevant callbacks
276 fun verify_and_collect
(npropdef
: AMethPropdef, callback_set
: ForeignCallbackSet,
277 toolcontext
: ToolContext) is abstract
280 redef class ALocalPropExternCall
281 redef fun verify_and_collect
(npropdef
, callback_set
, toolcontext
)
283 var mmodule
= npropdef
.mpropdef
.mclassdef
.mmodule
284 var mclass_type
= npropdef
.mpropdef
.mclassdef
.bound_mtype
285 var m_name
= n_methid
.collect_text
286 var method
= toolcontext
.modelbuilder
.try_get_mproperty_by_name2
( self,
287 mmodule
, mclass_type
, m_name
)
289 if method
== null then
290 toolcontext
.error
(location
, "Local method {m_name} not found.")
294 var explicit_call
= new MExplicitCall(mclass_type
, method
, mmodule
)
295 callback_set
.callbacks
.add
(explicit_call
)
297 explicit_call
.fill_type_for
(callback_set
, mmodule
)
301 redef class AFullPropExternCall
302 redef fun verify_and_collect
(npropdef
, callback_set
, toolcontext
)
304 var mmodule
= npropdef
.mpropdef
.mclassdef
.mmodule
305 var mclassdef
= npropdef
.mpropdef
.mclassdef
306 var mclass_type
= mclassdef
.bound_mtype
307 var mtype
= toolcontext
.modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, n_type
)
309 if mtype
== null then return
311 if mtype
isa MParameterType or mtype
isa MVirtualType then
312 mtype
= mtype
.anchor_to
(mmodule
, mclass_type
)
315 if mtype
isa MNullableType then
316 toolcontext
.error
(location
, "Type {n_type.collect_text} is nullable and thus cannot be the receiver." )
320 var m_name
= n_methid
.collect_text
321 var method
= toolcontext
.modelbuilder
.try_get_mproperty_by_name2
( self,
322 mmodule
, mtype
, m_name
)
324 if method
== null then
325 toolcontext
.error
(location
, "Method {m_name} not found in {n_type.collect_text}." )
329 var explicit_call
= new MExplicitCall(mtype
.as(MClassType), method
, mmodule
)
330 callback_set
.callbacks
.add
(explicit_call
)
331 explicit_call
.fill_type_for
(callback_set
, mmodule
)
335 redef class AInitPropExternCall
336 redef fun verify_and_collect
(npropdef
, callback_set
, toolcontext
)
338 var mmodule
= npropdef
.mpropdef
.mclassdef
.mmodule
339 var mclassdef
= npropdef
.mpropdef
.mclassdef
340 var mtype
= toolcontext
.modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, n_type
)
341 if mtype
== null then return
343 if not mtype
isa MClassType then
344 toolcontext
.error
(location
, "Type {n_type.collect_text} is not a class and thus cannot be used to instanciate a new instance." )
348 var meth_name
= "new"
349 var meth
= toolcontext
.modelbuilder
.try_get_mproperty_by_name2
( self,
350 mmodule
, mtype
, meth_name
)
354 meth
= toolcontext
.modelbuilder
.try_get_mproperty_by_name2
( self,
355 mmodule
, mtype
, meth_name
)
359 toolcontext
.error
(location
, "Method {meth_name} not found in {n_type.collect_text}." )
363 var explicit_call
= new MExplicitCall(mtype
, meth
, mmodule
)
364 callback_set
.callbacks
.add
(explicit_call
)
365 explicit_call
.fill_type_for
(callback_set
, mmodule
)
369 redef class ASuperExternCall
370 redef fun verify_and_collect
(npropdef
, callback_set
, toolcontext
)
372 callback_set
.supers
.add
( new MExplicitSuper( npropdef
.mpropdef
.as(not null) ) )
373 callback_set
.types
.add
( npropdef
.mpropdef
.mclassdef
.mclass
.mclass_type
)
374 npropdef
.mpropdef
.has_supercall
= true
378 redef class ACastExternCall
379 fun from_mtype
: MType is abstract
380 fun to_mtype
: MType is abstract
382 redef fun verify_and_collect
(npropdef
, callback_set
, toolcontext
)
384 var from
= from_mtype
387 callback_set
.types
.add
(from
)
388 callback_set
.types
.add
(to
)
390 callback_set
.casts
.add
(new MExplicitCast(from
, to
))
394 redef class ACastAsExternCall
395 redef fun from_mtype
do return n_from_type
.mtype
.as(not null)
396 redef fun to_mtype
do return n_to_type
.mtype
.as(not null)
398 redef fun verify_and_collect
(npropdef
, callback_set
, toolcontext
)
400 var mclassdef
= npropdef
.mpropdef
.mclassdef
401 var mmodule
= mclassdef
.mmodule
402 toolcontext
.modelbuilder
.resolve_mtype_unchecked
(mmodule
, mclassdef
, n_from_type
, true)
403 toolcontext
.modelbuilder
.resolve_mtype_unchecked
(mmodule
, mclassdef
, n_to_type
, true)
408 redef class AAsNullableExternCall
409 redef fun from_mtype
do return n_type
.mtype
.as(not null)
410 redef fun to_mtype
do return n_type
.mtype
.as_nullable
412 redef fun verify_and_collect
(npropdef
, callback_set
, toolcontext
)
414 var mclassdef
= npropdef
.mpropdef
.mclassdef
415 var mmodule
= mclassdef
.mmodule
416 toolcontext
.modelbuilder
.resolve_mtype_unchecked
(mmodule
, mclassdef
, n_type
, true)
421 redef class AAsNotNullableExternCall
422 redef fun from_mtype
do return n_type
.mtype
.as_nullable
423 redef fun to_mtype
do
424 var mtype
= n_type
.mtype
.as(not null)
425 mtype
= mtype
.as_notnullable
429 redef fun verify_and_collect
(npropdef
, callback_set
, toolcontext
)
431 var mclassdef
= npropdef
.mpropdef
.mclassdef
432 var mmodule
= mclassdef
.mmodule
433 toolcontext
.modelbuilder
.resolve_mtype_unchecked
(mmodule
, mclassdef
, n_type
, true)