ni_nitdoc: added fast copy past utility to signatures.
[nit.git] / src / primitive_info.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 primitive_info
19
20 #FIXME Split this module into 2: one in metamodel and one in compiling
21
22 import metamodel
23
24 redef class MMLocalClass
25 # extern type of extern classes
26 fun extern_c_type : String is abstract
27
28 # Cached primitive_info result
29 var _primitive_info_cache: nullable PrimitiveInfo = null
30
31 # If primitive_info result cached?
32 var _primitive_info_b: Bool = false
33
34 # Return the primitive information of the class.
35 # Return null if the class is not primitive
36 fun primitive_info: nullable PrimitiveInfo
37 do
38 if _primitive_info_b == true then return _primitive_info_cache
39
40 var ctypes = once primitive_ctypes
41 if ctypes.has_key(name) then
42 _primitive_info_cache = ctypes[name]
43 _primitive_info_b = true
44 return _primitive_info_cache
45 end
46 if global.is_extern then
47 var pi = new PrimitiveInfo( name, false, extern_c_type )
48 _primitive_info_cache = pi
49 _primitive_info_b = true
50 return _primitive_info_cache
51 end
52 var i = ctypes.iterator
53 while i.is_ok do
54 var n = i.key
55 if mmmodule.has_global_class_named(n) then
56 var c = mmmodule.class_by_name(n)
57 if cshe < c then
58 _primitive_info_cache = i.item
59 _primitive_info_b = true
60 return _primitive_info_cache
61 end
62 end
63 i.next
64 end
65 _primitive_info_b = true
66 return null
67 end
68
69 # Static information of primitive types
70 private fun primitive_ctypes: HashMap[Symbol, PrimitiveInfo]
71 do
72 var res = new HashMap[Symbol, PrimitiveInfo]
73 var pnames = ["Int", "Char", "Bool", "Float", "NativeString", "Pointer"]
74 var tagged = [true, true, true, false, false, false]
75 var cnames = ["bigint", "char", "int", "float", "char *", "void *"]
76 for i in [0..pnames.length[ do
77 var n = pnames[i].to_symbol
78 var pi = new PrimitiveInfo(n, tagged[i], cnames[i])
79 res[n] = pi
80 end
81 return res
82 end
83 end
84
85 # Information about a primitive class
86 class PrimitiveInfo
87 # The name of the class
88 readable var _name: Symbol
89
90 # Is the class tagged (aka not boxed)
91 readable var _tagged: Bool
92
93 # The corresponding c type for the primitive value
94 readable var _cname: String
95
96 private init(n: Symbol, t: Bool, c: String)
97 do
98 _name = n
99 _tagged = t
100 _cname = c
101 end
102 end
103
104 redef class MMType
105 # The corresponding c type
106 fun cname: String
107 do
108 var pi = local_class.primitive_info
109 if pi == null then
110 return "val_t"
111 else
112 return pi.cname
113 end
114 end
115
116 # Is the type tagged?
117 fun is_tagged: Bool
118 do
119 if is_nullable then return false
120 var pi = local_class.primitive_info
121 return pi != null and pi.tagged
122 end
123
124 # The default c value for uninitialized types.
125 # Return "null" for non primitive types and something more specific for primitive types
126 fun default_cvalue: String
127 do
128 var pi = local_class.primitive_info
129 if pi != null and pi.tagged then
130 return "TAG_{local_class.name}(({pi.cname})0)"
131 else
132 return "NIT_NULL"
133 end
134 end
135
136 # Box (or tag) a primitive value
137 # Is identity if not primitive
138 fun boxtype(s: String): String
139 do
140 var pi = local_class.primitive_info
141 if pi == null or is_nullable then
142 return s
143 else if pi.tagged then
144 return "TAG_{local_class.name}({s})"
145 else
146 return "BOX_{local_class.name}({s})"
147 end
148 end
149
150 # Unbox (or untag) a primitive value
151 # Is identity if not primitive
152 fun unboxtype(s: String): String
153 do
154 var pi = local_class.primitive_info
155 if pi == null or is_nullable then
156 return s
157 else if pi.tagged then
158 return "UNTAG_{local_class.name}({s})"
159 else
160 return "UNBOX_{local_class.name}({s})"
161 end
162 end
163 end
164
165 redef class MMMethod
166 fun default_extern_name : String
167 do
168 return "{friendly_extern_name(local_class)}___impl"
169 end
170
171 # Friendly name for this method. Is mainly the class name followed by the
172 # function name. It is prefixed with "new" for a constructor.
173 fun friendly_extern_name( local_class : MMLocalClass ) : String
174 do
175 if not global.is_init then
176 var native_fun_name : String
177 var method_name = name.to_s
178 if method_name == "+" then
179 native_fun_name = "_plus" # add
180 else if method_name == "-" then
181 native_fun_name = "_minus" # sub
182 else if method_name == "*" then
183 native_fun_name = "_star" # multi
184 else if method_name == "/" then
185 native_fun_name = "_slash" # div
186 else if method_name == "%" then
187 native_fun_name = "_percent" # mod
188 else if method_name == "[]" then
189 native_fun_name = "_index" # brackets
190 else if method_name == "[]=" then
191 native_fun_name = "_index_assign" # brackets
192 else if method_name == "==" then
193 native_fun_name = "_equal" # eq
194 else if method_name == "<" then
195 native_fun_name = "_less" # lt
196 else if method_name == ">" then
197 native_fun_name = "_greater" # gt
198 else if method_name == "<=" then
199 native_fun_name = "_less_or_equal" # greater_or_equal
200 else if method_name == ">=" then
201 native_fun_name = "_ge" # smaller_or_equal
202 else if method_name == "!=" then
203 native_fun_name = "_not_equal" # bang
204 else if method_name == ">>" then
205 native_fun_name = "_right"
206 else if method_name == "<<" then
207 native_fun_name = "_left"
208 else if method_name == "<=>" then
209 native_fun_name = "_starship"
210 else if method_name[ method_name.length-1 ] == '=' then
211 native_fun_name = "{method_name.substring(0,method_name.length-1)}__assign"
212 else
213 native_fun_name = method_name
214 end
215
216 return "{local_class.name}_{native_fun_name}"
217 else
218 if name == once "init".to_symbol then
219 return "new_{local_class.name}"
220 else
221 return "new_{local_class.name}_{name}"
222 end
223 end
224 end
225 end
226