various phases: more robust for keep-going
[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 if mclassdef == null then return
72 var mclass = mclassdef.mclass
73
74 # We only need to do this once per class
75 if not mclassdef.is_intro then return
76
77 if mclass.kind != extern_kind then return
78
79 mclass.compute_ftype(self)
80 end
81 end
82
83 redef class MClass
84 private var ftype_cache: nullable ForeignType = null
85 private var ftype_computed = false
86
87 # Extern type associated to this class according to specialisation
88 fun ftype: nullable ForeignType do return ftype_cache
89
90 redef fun ctype do return ftype_cache.ctype
91
92 # Type in C of the extern class
93 # If not defined in the intro of this class will look in super-classes
94 # FIXME this only supports type definition at intro, extend to superclasses by redef
95 private fun compute_ftype(v: ExternClassesTypingPhaseModel): nullable ForeignType
96 do
97 if ftype_computed then return ftype_cache
98 if kind != extern_kind then return null
99
100 # base case
101 if name == "Pointer" then
102 ftype_cache = new ForeignType
103 ftype_computed = true
104 return ftype_cache
105 end
106
107 var ftype = intro.ftype
108 if ftype == null then
109 var ftype_b: nullable ForeignType = null # FIXME hack to circumvent bug where ftype is typed null
110
111 # look in super classes
112 for s in in_hierarchy(intro.mmodule).direct_greaters do
113 var super_ftype = s.compute_ftype(v)
114 if super_ftype != null then
115 if ftype_b == null then
116 ftype_b = super_ftype
117 continue
118 else
119 # detect conflict
120 if super_ftype != ftype_b then
121 v.toolcontext.error(null, "Extern type conflict in {self}")
122 return null
123 end
124 end
125 end
126 end
127
128 ftype = ftype_b
129 end
130
131 ftype_cache = ftype
132 ftype_computed = true
133 return ftype
134 end
135 end