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