contrib/jwrapper: remove even more code related to collection hack
[nit.git] / contrib / jwrapper / src / model.nit
1 # This file is part of NIT (http://www.nitlanguage.org).
2 #
3 # Copyright 2014 Frédéric Vachon <fredvac@gmail.com>
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 # Contains the java and nit type representation used to convert java to nit code
18 module model
19
20 import jtype_converter
21
22 class JavaType
23 private var converter: JavaTypeConverter
24 var identifier = new Array[String]
25 var generic_params: nullable Array[JavaType] = null
26 var is_void = false
27
28 # Has some generic type to be resolved (T extends foo => T is resolved to foo)
29 var has_unresolved_types = false
30
31 # Dimension of primitive array: `int[][]` is 2d
32 var array_dimension = 0
33
34 fun is_primitive_array: Bool do return array_dimension > 0
35
36 fun has_generic_params: Bool do return not generic_params == null
37 fun full_id: String do return identifier.join(".")
38 fun id: String do return identifier.last.replace("$", "")
39
40 init(converter: JavaTypeConverter) do self.converter = converter
41
42 fun return_cast: String do return converter.cast_as_return(self.id)
43
44 fun param_cast: String
45 do
46 if self.has_generic_params then
47 return converter.cast_as_param(self.generic_params[0].id)
48 end
49
50 return converter.cast_as_param(self.id)
51 end
52
53 fun to_nit_type: NitType
54 do
55 var nit_type: NitType
56 var type_id = null
57
58 if not is_primitive_array then
59 type_id = converter.to_nit_type(self.id)
60 end
61
62 if type_id == null then
63 nit_type = self.extern_name
64 nit_type.is_complete = false
65 else
66 nit_type = new NitType(type_id)
67 end
68
69 if not self.has_generic_params then return nit_type
70
71 nit_type.generic_params = new Array[NitType]
72
73 for param in generic_params do
74 var nit_param = param.to_nit_type
75
76 nit_type.generic_params.add(nit_param)
77
78 if not nit_param.is_complete then nit_type.is_complete = false
79 end
80
81 return nit_type
82 end
83
84 fun is_iterable: Bool do return iterable.has(self.id)
85
86 fun is_collection: Bool do return is_primitive_array or collections_list.has(self.id)
87
88 fun is_wrapped: Bool do return find_extern_class != null
89
90 fun extern_name: NitType
91 do
92 if is_wrapped then return new NitType.with_module(find_extern_class.as(not null).first, find_extern_class.as(not null).second)
93
94 var name
95 if is_primitive_array then
96 # Primitive arrays have a special naming convention
97 name = "Native" + extern_class_name.join("").capitalized + "Array"
98 else
99 name = "Native" + extern_class_name.join("")
100 end
101
102 var nit_type = new NitType(name)
103 nit_type.is_complete = false
104 return nit_type
105 end
106
107 fun to_cast(jtype: String, is_param: Bool): String
108 do
109 if is_param then
110 return converter.cast_as_param(jtype)
111 end
112
113 return converter.cast_as_return(jtype)
114 end
115
116 redef fun to_s: String
117 do
118 var id = self.full_id
119
120 if self.is_primitive_array then
121 for i in [0..array_dimension[ do
122 id += "[]"
123 end
124 else if self.has_generic_params then
125 var gen_list = new Array[String]
126
127 for param in generic_params do
128 gen_list.add(param.to_s)
129 end
130
131 id += "<{gen_list.join(", ")}>"
132 end
133
134 return id
135 end
136
137 # To fully qualified package name
138 # Cuts the primitive array `[]`
139 fun to_package_name: String
140 do
141 var str = self.to_s
142 var len = str.length
143
144 return str.substring(0, len - (2*array_dimension))
145 end
146
147 fun resolve_types(conversion_map: HashMap[String, Array[String]])
148 do
149 if identifier.length == 1 then
150 var resolved_id = conversion_map.get_or_null(self.id)
151 if resolved_id != null then self.identifier = new Array[String].from(resolved_id)
152 end
153
154 if self.has_generic_params then
155 for params in generic_params do params.resolve_types(conversion_map)
156 end
157 end
158
159 private fun extern_class_name: Array[String]
160 do
161 var class_name = new Array[String]
162 class_name.add(self.id)
163
164 if not self.has_generic_params then return class_name
165
166 class_name.add "Of"
167
168 for param in generic_params do class_name.add_all param.extern_class_name
169
170 return class_name
171 end
172
173 # Search inside `lib/android` directory for already wrapped classes
174 # If found, contains the class identifier and the Nit Module name
175 var find_extern_class: nullable Couple[String, NitModule] is lazy do
176
177 var regex = "extern class [a-zA-Z1-9]\\\+[ ]\\\+in[ ]\\\+\"Java\"[ ]*`\{[ ]*" + self.to_s + "\\\+[ ]*`\}"
178 var nit_dir = "NIT_DIR".environ
179 var grep = new IProcess("grep", "-r", regex, nit_dir/"lib/android/", nit_dir/"lib/java/")
180 var to_eat = ["private", "extern", "class"]
181
182 var output = grep.read_line
183
184 var output_class = output.substring_from(output.index_of(':') + 1)
185 var tokens = output_class.split(" ")
186
187 var nclass_name = ""
188
189 for token in tokens do
190 if to_eat.has(token) then continue
191 nclass_name = token
192 break
193 end
194
195 if nclass_name == "" then return null
196
197 var str = output.substring(0, output.search(".nit").from)
198 str = str.substring_from(str.last_index_of('/') + 1)
199 var mod = new NitModule(str)
200
201 return new Couple[String, NitModule](nclass_name, mod)
202 end
203
204 # Comparison based on fully qualified named and generic params
205 # Ignores primitive array so `a.b.c[][] == a.b.c`
206 redef fun ==(other)
207 do
208 if other isa JavaType then
209 return self.repr == other.repr
210 end
211 return false
212 end
213
214 redef fun hash do return self.repr.hash
215
216 private fun repr: String
217 do
218 var id = self.full_id
219
220 if self.has_generic_params then
221 var gen_list = new Array[String]
222
223 for param in generic_params do
224 gen_list.add(param.to_s)
225 end
226
227 id += "<{gen_list.join(", ")}>"
228 end
229
230 return id
231 end
232
233 fun collections_list: Array[String] is cached do return ["List", "ArrayList", "LinkedList", "Vector", "Set", "SortedSet", "HashSet", "TreeSet", "LinkedHashSet", "Map", "SortedMap", "HashMap", "TreeMap", "Hashtable", "LinkedHashMap"]
234 fun iterable: Array[String] is cached do return ["ArrayList", "Set", "HashSet", "LinkedHashSet", "LinkedList", "Stack", "TreeSet", "Vector"]
235 fun maps: Array[String] is cached do return ["Map", "SortedMap", "HashMap", "TreeMap", "Hashtable", "LinkedHashMap"]
236 end
237
238 class NitType
239 var identifier: String
240 var arg_id: String
241 var generic_params: nullable Array[NitType] = null
242
243 # If this NitType was found in `lib/android`, contains the module name to import
244 var mod: nullable NitModule
245
246 # Returns `true` if all types have been successfully converted to Nit type
247 var is_complete: Bool = true
248
249 fun has_generic_params: Bool do return not generic_params == null
250
251 fun id: String do return identifier
252
253 init (id: String)
254 do
255 self.identifier = id
256 end
257
258 init with_generic_params(id: String, gen_params: String...)
259 do
260 self.init(id)
261 self.generic_params = new Array[NitType]
262 for param in gen_params do self.generic_params.add new NitType(param)
263 end
264
265 init with_module(id: String, mod: NitModule)
266 do
267 self.init(id)
268 self.mod = mod
269 end
270
271 redef fun to_s: String
272 do
273 var id = self.identifier
274
275 if self.has_generic_params then
276 var gen_list = new Array[String]
277
278 for param in generic_params do
279 gen_list.add(param.to_s)
280 end
281
282 id += "[{gen_list.join(", ")}]"
283 end
284
285 return id
286 end
287 end
288
289 class JavaClass
290 var class_type = new JavaType(new JavaTypeConverter)
291 var attributes = new HashMap[String, JavaType]
292
293 # Methods of this class organized by their name
294 var methods = new HashMap[String, Array[JavaMethod]]
295
296 var unknown_types = new HashSet[JavaType]
297 var imports = new HashSet[NitModule]
298
299 fun add_method(id: String, return_type: JavaType, params: Array[JavaType])
300 do
301 var signatures = methods.get_or_default(id, new Array[JavaMethod])
302 signatures.add(new JavaMethod(return_type, new Array[JavaType].from(params)))
303 methods[id] = signatures
304 end
305 end
306
307 # A Java method, with its signature
308 class JavaMethod
309 # Type returned by the method
310 var return_type: JavaType
311
312 # Type of the arguments of the method
313 var params: Array[JavaType]
314 end
315
316 # A Nit module, use to import the referenced extern classes
317 class NitModule
318 # Name of the module
319 var name: String
320
321 redef fun ==(other): Bool do return self.to_s == other.to_s
322 redef fun to_s: String do return self.name
323 redef fun hash: Int do return self.name.hash
324 end