bc4f0c46771a708e0b6fc5d22a64f1f9ab6cd222
[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 ffi_base
21
22 redef class ToolContext
23 var extern_classes_typing_phase_ast: Phase = new ExternClassesTypingPhaseAst(self, [ffi_language_assignation_phase, modelize_class_phase])
24
25 var extern_classes_typing_phase_model: Phase = new ExternClassesTypingPhaseModel(self,
26 [extern_classes_typing_phase_ast, modelize_class_phase, modelize_property_phase])
27 end
28
29 # Assigns the `ftype` to class definitions, work on the AST only
30 private class ExternClassesTypingPhaseAst
31 super Phase
32
33 redef fun process_nclassdef(nclassdef)
34 do
35 if not nclassdef isa AStdClassdef then return
36
37 var code_block = nclassdef.n_extern_code_block
38 if code_block == null then return
39
40 if nclassdef.n_kwredef != null then
41 # A redef cannot specifiy a different extern type
42 toolcontext.error(nclassdef.location, "Only the introduction of a class can specify an extern type.")
43 return
44 end
45
46 var ftype = code_block.language.get_ftype(code_block, nclassdef)
47 nclassdef.mclassdef.ftype_cache = ftype
48 nclassdef.mclassdef.ftype_computed = true
49 end
50 end
51
52 redef class MClassDef
53 private var ftype_cache: nullable ForeignType = null
54 private var ftype_computed = false
55
56 # Associated extern type when defined on this classdef
57 fun ftype: nullable ForeignType
58 do
59 return ftype_cache
60 end
61 end
62
63 private class ExternClassesTypingPhaseModel
64 super Phase
65
66 redef fun process_nclassdef(nclassdef)
67 do
68 if not nclassdef isa AStdClassdef then return
69
70 var mclassdef = nclassdef.mclassdef
71 var mclass = nclassdef.mclass
72
73 # We only need to do this once per class
74 if mclass.intro != mclassdef then return
75
76 if mclass.kind != extern_kind then return
77
78 mclass.compute_ftype(self)
79 end
80 end
81
82 redef class MClass
83 private var ftype_cache: nullable ForeignType = null
84 private var ftype_computed = false
85
86 # Extern type associated to this class according to specialisation
87 fun ftype: nullable ForeignType do return ftype_cache
88
89 redef fun ctype do return ftype_cache.ctype
90
91 # Type in C of the extern class
92 # If not defined in the intro of this class will look in super-classes
93 # FIXME this only supports type definition at intro, extend to superclasses by redef
94 private fun compute_ftype(v: ExternClassesTypingPhaseModel): nullable ForeignType
95 do
96 if ftype_computed then return ftype_cache
97 if kind != extern_kind then return null
98
99 # base case
100 if name == "Pointer" then
101 ftype_cache = new ForeignType
102 ftype_computed = true
103 return ftype_cache
104 end
105
106 var ftype = intro.ftype
107 if ftype == null then
108 var ftype_b: nullable ForeignType = null # FIXME hack to circumvent bug where ftype is typed null
109
110 # look in super classes
111 for s in in_hierarchy(intro.mmodule).direct_greaters do
112 var super_ftype = s.compute_ftype(v)
113 if super_ftype != null then
114 if ftype_b == null then
115 ftype_b = super_ftype
116 continue
117 else
118 # detect conflict
119 if super_ftype != ftype_b then
120 v.toolcontext.error(null, "Extern type conflict in {self}")
121 return null
122 end
123 end
124 end
125 end
126
127 ftype = ftype_b
128 end
129
130 ftype_cache = ftype
131 ftype_computed = true
132 return ftype
133 end
134 end