1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 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 # Manages all extern classes and their associated foreign type.
23 redef class ToolContext
24 var extern_classes_typing_phase_ast
: Phase = new ExternClassesTypingPhaseAst(self, [ffi_language_assignation_phase
, modelize_class_phase
])
26 var extern_classes_typing_phase_model
: Phase = new ExternClassesTypingPhaseModel(self,
27 [extern_classes_typing_phase_ast
, modelize_class_phase
, modelize_property_phase
])
30 # Assigns the `ftype` to class definitions, work on the AST only
31 private class ExternClassesTypingPhaseAst
34 redef fun process_nclassdef
(nclassdef
)
36 if not nclassdef
isa AStdClassdef then return
38 var code_block
= nclassdef
.n_extern_code_block
39 if code_block
== null then return
41 if nclassdef
.n_kwredef
!= null then
42 # A redef cannot specify a different extern type
43 toolcontext
.error
(nclassdef
.location
, "FFI Error: only the introduction of a class can declare an extern type.")
47 var ftype
= code_block
.language
.get_ftype
(code_block
, nclassdef
)
48 nclassdef
.mclassdef
.ftype_cache
= ftype
49 nclassdef
.mclassdef
.ftype_computed
= true
54 private var ftype_cache
: nullable ForeignType = null
55 private var ftype_computed
= false
57 # Associated extern type when defined on this classdef
58 fun ftype
: nullable ForeignType
64 private class ExternClassesTypingPhaseModel
67 redef fun process_nclassdef
(nclassdef
)
69 if not nclassdef
isa AStdClassdef then return
71 var mclassdef
= nclassdef
.mclassdef
72 if mclassdef
== null then return
73 var mclass
= mclassdef
.mclass
75 # We only need to do this once per class
76 if not mclassdef
.is_intro
then return
78 if mclass
.kind
!= extern_kind
then return
80 mclass
.compute_ftype
(self)
85 private var ftype_cache
: nullable ForeignType = null
86 private var ftype_computed
= false
88 # Extern type associated to this class according to specialisation
89 fun ftype
: nullable ForeignType do return ftype_cache
91 redef fun ctype
do return ftype_cache
.ctype
93 # Type in C of the extern class
94 # If not defined in the intro of this class will look in super-classes
95 # FIXME this only supports type definition at intro, extend to superclasses by redef
96 private fun compute_ftype
(v
: ExternClassesTypingPhaseModel): nullable ForeignType
98 if ftype_computed
then return ftype_cache
99 if kind
!= extern_kind
then return null
102 if name
== "Pointer" then
103 ftype_cache
= new ForeignType
104 ftype_computed
= true
108 var ftype
= intro
.ftype
109 if ftype
== null then
110 var ftype_b
: nullable ForeignType = null # FIXME hack to circumvent bug where ftype is typed null
112 # look in super classes
113 for s
in in_hierarchy
(intro_mmodule
).direct_greaters
do
114 var super_ftype
= s
.compute_ftype
(v
)
115 if super_ftype
!= null then
116 if ftype_b
== null then
117 ftype_b
= super_ftype
121 if super_ftype
!= ftype_b
then
122 v
.toolcontext
.error
(null, "FFI Error: extern type conflict in `{self}`.")
133 ftype_computed
= true