model: use the robust `intro_mmodule` instead of `intro.mmodule`.
[nit.git] / src / ffi / extern_classes.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 # Manages all extern classes and their associated foreign type.
18 module extern_classes
19
20 import light_ffi_base
21 import modelize
22
23 redef class ToolContext
24 var extern_classes_typing_phase_ast: Phase = new ExternClassesTypingPhaseAst(self, [ffi_language_assignation_phase, modelize_class_phase])
25
26 var extern_classes_typing_phase_model: Phase = new ExternClassesTypingPhaseModel(self,
27 [extern_classes_typing_phase_ast, modelize_class_phase, modelize_property_phase])
28 end
29
30 # Assigns the `ftype` to class definitions, work on the AST only
31 private class ExternClassesTypingPhaseAst
32 super Phase
33
34 redef fun process_nclassdef(nclassdef)
35 do
36 if not nclassdef isa AStdClassdef then return
37
38 var code_block = nclassdef.n_extern_code_block
39 if code_block == null then return
40
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.")
44 return
45 end
46
47 var ftype = code_block.language.get_ftype(code_block, nclassdef)
48 nclassdef.mclassdef.ftype_cache = ftype
49 nclassdef.mclassdef.ftype_computed = true
50 end
51 end
52
53 redef class MClassDef
54 private var ftype_cache: nullable ForeignType = null
55 private var ftype_computed = false
56
57 # Associated extern type when defined on this classdef
58 fun ftype: nullable ForeignType
59 do
60 return ftype_cache
61 end
62 end
63
64 private class ExternClassesTypingPhaseModel
65 super Phase
66
67 redef fun process_nclassdef(nclassdef)
68 do
69 if not nclassdef isa AStdClassdef then return
70
71 var mclassdef = nclassdef.mclassdef
72 if mclassdef == null then return
73 var mclass = mclassdef.mclass
74
75 # We only need to do this once per class
76 if not mclassdef.is_intro then return
77
78 if mclass.kind != extern_kind then return
79
80 mclass.compute_ftype(self)
81 end
82 end
83
84 redef class MClass
85 private var ftype_cache: nullable ForeignType = null
86 private var ftype_computed = false
87
88 # Extern type associated to this class according to specialisation
89 fun ftype: nullable ForeignType do return ftype_cache
90
91 redef fun ctype do return ftype_cache.ctype
92
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
97 do
98 if ftype_computed then return ftype_cache
99 if kind != extern_kind then return null
100
101 # base case
102 if name == "Pointer" then
103 ftype_cache = new ForeignType
104 ftype_computed = true
105 return ftype_cache
106 end
107
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
111
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
118 continue
119 else
120 # detect conflict
121 if super_ftype != ftype_b then
122 v.toolcontext.error(null, "FFI Error: extern type conflict in `{self}`.")
123 return null
124 end
125 end
126 end
127 end
128
129 ftype = ftype_b
130 end
131
132 ftype_cache = ftype
133 ftype_computed = true
134 return ftype
135 end
136 end