compile: clean CompilerVisitor constructor
[nit.git] / src / compiling / compiling_base.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2008 Jean Privat <jean@pryen.org>
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 # Common things for NIT compilation and C generation
18 package compiling_base
19
20 import syntax
21 private import utils
22
23 redef class ToolContext
24 readable writable attr _global: Bool = false
25 readable writable attr _compdir: String
26 readable writable attr _clibdir: String
27 readable writable attr _bindir: String
28 readable writable attr _output_file: String
29 readable writable attr _boost: Bool = false
30 readable writable attr _no_cc: Bool = false
31 readable writable attr _ext_prefix: String
32 end
33
34 # Class used to generate files.
35 # Note that in fact it is not a visitor.
36 # Note also that this class is unefficient and poorly designed thus requires love.
37 class CompilerVisitor
38 # Add a line in the current declaration block
39 meth add_decl(s: String)
40 do
41 if _indent_level >= 8 then
42 _ctx.decls.add("\t\t" + s)
43 else
44 _ctx.decls.add(" " * _indent_level + s)
45 end
46 end
47
48 # Add a line in the current instr block
49 meth add_instr(s: String)
50 do
51 if _indent_level >= 8 then
52 _ctx.instrs.add("\t\t" + s)
53 else
54 _ctx.instrs.add(" " * _indent_level + s)
55 end
56 end
57
58 # Return a unique new number for the instance
59 meth new_number: Int
60 do
61 var res = _number_cpt
62 _number_cpt = res + 1
63 return res
64 end
65 # next number for new_number
66 attr _number_cpt: Int = 0
67
68 # Add an indent level.
69 # New decl and instr will be indented.
70 meth indent do _indent_level += 1
71
72 # Remove an indent level.
73 meth unindent
74 do
75 _indent_level -= 1
76 if _indent_level < 0 then _indent_level = 0
77 end
78
79 # Return a big string containing all decl and instr
80 redef meth to_s
81 do
82 var out = new Array[String]
83 out.append(_ctx.decls)
84 out.append(_ctx.instrs)
85 out.add("")
86 return out.join("\n")
87 end
88
89 # The processed module
90 readable attr _module: MMSrcModule
91
92 # Where instr and decl are stored
93 readable writable attr _ctx: CContext = new CContext
94
95 # The current indent lever
96 readable writable attr _indent_level: Int = 0
97
98 # The ToolContext info
99 readable attr _tc: ToolContext
100
101 # Create a new CompilerVisitor based on a module
102 init(module: MMSrcModule, tc: ToolContext)
103 do
104 _module = module
105 _tc = tc
106 end
107 end
108
109 # Where instr and decl are stored for a module
110 # Note that this class is as badly designed as CompilerVisitor
111 class CContext
112 readable attr _decls: Array[String] = new Array[String]
113 readable attr _instrs: Array[String] = new Array[String]
114
115 meth append(c: CContext)
116 do
117 _instrs.append(c.decls)
118 _instrs.append(c.instrs)
119 end
120
121 meth merge(c: CContext)
122 do
123 _decls.append(c.decls)
124 _instrs.append(c.instrs)
125 end
126
127 init do end
128 end
129
130 redef class MMGlobalProperty
131 # C symbol refering a method inocation
132 meth meth_call: String
133 do
134 return "CALL_{intro.cname}"
135 end
136
137 # C symbol refering an attribure access
138 meth attr_access: String
139 do
140 return "ATTR_{intro.cname}"
141 end
142 end
143
144 redef class MMGlobalClass
145 # C symbol refering the identifier of the class
146 meth id_id: String
147 do
148 return "ID_{intro.name}"
149 end
150
151 # C symbol refering the color of the class (for subtype tests)
152 meth color_id: String
153 do
154 return "COLOR_{intro.name}"
155 end
156
157 # C symbol refering the init table position of the class (for constructor linearization)
158 meth init_table_pos_id: String
159 do
160 return "INIT_TABLE_POS_{intro.name}"
161 end
162 end
163
164 redef class MMLocalClass
165 # Cached primitive_info result
166 attr _primitive_info_cache: PrimitiveInfo
167
168 # If primitive_info result cached?
169 attr _primitive_info_b: Bool = false
170
171 # Return the primitive information of the class.
172 # Return null if the class is not primitive
173 # FIXME: Only here since there is no universal type yet
174 meth primitive_info: PrimitiveInfo
175 do
176 if _primitive_info_b == true then return _primitive_info_cache
177
178 var ctypes = once primitive_ctypes
179 if ctypes.has_key(name) then
180 _primitive_info_cache = ctypes[name]
181 _primitive_info_b = true
182 return _primitive_info_cache
183 end
184 var i = ctypes.iterator
185 while i.is_ok do
186 var n = i.key
187 if module.has_global_class_named(n) then
188 var c = module.class_by_name(n)
189 if cshe < c then
190 _primitive_info_cache = i.item
191 _primitive_info_b = true
192 return _primitive_info_cache
193 end
194 end
195 i.next
196 end
197 _primitive_info_b = true
198 return null
199 end
200
201 # Static information of primitive types
202 private meth primitive_ctypes: HashMap[Symbol, PrimitiveInfo]
203 do
204 var res = new HashMap[Symbol, PrimitiveInfo]
205 var pnames = ["Int", "Char", "Bool", "Float", "NativeString", "NativeArray", "Pointer"]
206 var tagged = [true, true, true, false, false, false, false]
207 var cnames = ["bigint", "char", "int", "float", "char *", "val_t *", "void *"]
208 for i in [0..pnames.length[ do
209 var n = pnames[i].to_symbol
210 var pi = new PrimitiveInfo
211 pi.name = n
212 pi.tagged = tagged[i]
213 pi.cname = cnames[i]
214 res[n] = pi
215 end
216 return res
217 end
218 end
219
220 # Information about a primitive class
221 class PrimitiveInfo
222 # The name of the class
223 readable writable attr _name: Symbol
224
225 # Is the class tagged (aka not boxed)
226 readable writable attr _tagged: Bool
227
228 # The corresponding c type for the primitive value
229 readable writable attr _cname: String
230
231 private init do end
232 end
233
234 redef class MMType
235 # The corresponding c type
236 meth cname: String
237 do
238 var pi = local_class.primitive_info
239 if pi == null then
240 return "val_t"
241 else
242 return pi.cname
243 end
244 end
245
246 # The default c value for uninitialized types.
247 # Return "null" for non primitive types and something more specific for primitive types
248 meth default_cvalue: String
249 do
250 var pi = local_class.primitive_info
251 if pi != null and pi.tagged then
252 return "TAG_{local_class.name}(({pi.cname})0)"
253 else
254 return "NIT_NULL"
255 end
256 end
257
258 # Box (or tag) a primitive value
259 # Is identity if not primitive
260 meth boxtype(s: String): String
261 do
262 var pi = local_class.primitive_info
263 if pi == null then
264 return s
265 else if pi.tagged then
266 return "TAG_{local_class.name}({s})"
267 else
268 return "BOX_{local_class.name}({s})"
269 end
270 end
271
272 # Unbox (or untag) a primitive value
273 # Is identity if not primitive
274 meth unboxtype(s: String): String
275 do
276 var pi = local_class.primitive_info
277 if pi == null then
278 return s
279 else if pi.tagged then
280 return "UNTAG_{local_class.name}({s})"
281 else
282 return "UNBOX_{local_class.name}({s})"
283 end
284 end
285 end
286
287 redef class MMLocalProperty
288 # Cacher result of cname
289 attr _cname_cache: String
290
291 # The mangled name of the method
292 meth cname: String
293 do
294 if _cname_cache == null then
295 _cname_cache = cmangle(module.name, local_class.name, name)
296 end
297 return _cname_cache
298 end
299
300 # C macro used to get the function for the call of a super property
301 meth super_meth_call: String
302 do
303 return "CALL_SUPER_{cname}"
304 end
305 end
306