contrib/jwrapper: do not try to generate generic extern classes
[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 # Copyright 2015 Alexis Laferrière <alexis.laf@xymus.net>
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17
18 # Contains the java and nit type representation used to convert java to nit code
19 module model
20
21 import more_collections
22
23 import jtype_converter
24
25 class JavaType
26 var identifier = new Array[String]
27 var generic_params: nullable Array[JavaType] = null
28 var is_void = false
29
30 # Has some generic type to be resolved (T extends foo => T is resolved to foo)
31 var has_unresolved_types = false
32
33 # Dimension of primitive array: `int[][]` is 2d
34 var array_dimension = 0
35
36 fun is_primitive_array: Bool do return array_dimension > 0
37
38 fun has_generic_params: Bool do return not generic_params == null
39 fun full_id: String do return identifier.join(".")
40 fun id: String do return identifier.last.replace("$", "")
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 return nit_type
70 end
71
72 fun is_collection: Bool do return is_primitive_array or collections_list.has(self.id)
73
74 fun is_wrapped: Bool do return find_extern_class != null
75
76 fun extern_name: NitType
77 do
78 if is_wrapped then return new NitType(find_extern_class.as(not null).first, find_extern_class.as(not null).second)
79
80 var name
81 if is_primitive_array then
82 # Primitive arrays have a special naming convention
83 name = "Java" + extern_class_name.join.capitalized + "Array"
84 else
85 name = "Java" + extern_class_name.join
86 end
87
88 name = name.replace("-", "_")
89
90 var nit_type = new NitType(name)
91 nit_type.is_complete = false
92 return nit_type
93 end
94
95 fun to_cast(jtype: String, is_param: Bool): String
96 do
97 if is_param then
98 return converter.cast_as_param(jtype)
99 end
100
101 return converter.cast_as_return(jtype)
102 end
103
104 redef fun to_s
105 do
106 var id = self.full_id
107
108 if self.is_primitive_array then
109 id += "[]" * array_dimension
110 else if self.has_generic_params then
111 var params = [for param in generic_params do param.to_s]
112 id += "<{params.join(", ")}>"
113 end
114
115 return id
116 end
117
118 # To fully qualified package name
119 # Cuts the primitive array `[]`
120 fun to_package_name: String
121 do
122 var str = self.to_s
123 var len = str.length
124
125 return str.substring(0, len - (2*array_dimension))
126 end
127
128 fun resolve_types(conversion_map: HashMap[String, Array[String]])
129 do
130 if identifier.length == 1 then
131 var resolved_id = conversion_map.get_or_null(self.id)
132 if resolved_id != null then self.identifier = new Array[String].from(resolved_id)
133 end
134
135 if self.has_generic_params then
136 for params in generic_params do params.resolve_types(conversion_map)
137 end
138 end
139
140 private fun extern_class_name: Array[String]
141 do
142 var class_name = new Array[String]
143 class_name.add(self.id)
144
145 if not self.has_generic_params then return class_name
146
147 class_name.add "Of"
148
149 for param in generic_params do class_name.add_all param.extern_class_name
150
151 return class_name
152 end
153
154 # Search inside `lib/android` directory for already wrapped classes
155 # If found, contains the class identifier and the Nit Module name
156 var find_extern_class: nullable Couple[String, NitModule] is lazy do
157
158 var regex = "extern class [a-zA-Z1-9]\\\+[ ]\\\+in[ ]\\\+\"Java\"[ ]*`\{[ ]*" + self.to_s + "\\\+[ ]*`\}"
159 var nit_dir = "NIT_DIR".environ
160 if nit_dir.is_empty then return null
161
162 var grep = new ProcessReader("grep", "-r", regex, nit_dir/"lib/android/", nit_dir/"lib/java/")
163 var to_eat = ["private", "extern", "class"]
164
165 var output = grep.read_line
166
167 var output_class = output.substring_from(output.index_of(':') + 1)
168 var tokens = output_class.split(" ")
169
170 var nclass_name = ""
171
172 for token in tokens do
173 if to_eat.has(token) then continue
174 nclass_name = token
175 break
176 end
177
178 if nclass_name == "" then return null
179
180 var str = output.substring(0, output.search(".nit").from)
181 str = str.substring_from(str.last_index_of('/') + 1)
182 var mod = new NitModule(str)
183
184 return new Couple[String, NitModule](nclass_name, mod)
185 end
186
187 # Comparison based on fully qualified named and generic params
188 # Ignores primitive array so `a.b.c[][] == a.b.c`
189 redef fun ==(other) do return other isa JavaType and self.full_id == other.full_id
190
191 redef fun hash do return self.full_id.hash
192
193 var collections_list: Array[String] is lazy do return ["List", "ArrayList", "LinkedList", "Vector", "Set", "SortedSet", "HashSet", "TreeSet", "LinkedHashSet", "Map", "SortedMap", "HashMap", "TreeMap", "Hashtable", "LinkedHashMap"]
194 var iterable: Array[String] is lazy do return ["ArrayList", "Set", "HashSet", "LinkedHashSet", "LinkedList", "Stack", "TreeSet", "Vector"]
195 var maps: Array[String] is lazy do return ["Map", "SortedMap", "HashMap", "TreeMap", "Hashtable", "LinkedHashMap"]
196 end
197
198 class NitType
199 # Nit class name
200 var identifier: String
201
202 # If this NitType was found in `lib/android`, contains the module name to import
203 var mod: nullable NitModule
204
205 # Returns `true` if all types have been successfully converted to Nit type
206 var is_complete: Bool = true
207
208 redef fun to_s do return identifier
209 end
210
211 # Model of a single Java class
212 class JavaClass
213 # Type of this class
214 var class_type = new JavaType
215
216 # Attributes of this class
217 var attributes = new HashMap[String, JavaType]
218
219 # Methods of this class organized by their name
220 var methods = new MultiHashMap[String, JavaMethod]
221
222 # Importations from this class
223 var imports = new HashSet[NitModule]
224
225 redef fun to_s do return class_type.to_s
226 end
227
228 # Model of all the Java class analyzed in one run
229 class JavaModel
230 # Unknown Java types used in `classes`
231 var unknown_types = new HashSet[JavaType]
232
233 # All analyzed classes
234 var classes = new Array[JavaClass]
235 end
236
237 # A Java method, with its signature
238 class JavaMethod
239 # Type returned by the method
240 var return_type: JavaType
241
242 # Type of the arguments of the method
243 var params: Array[JavaType]
244 end
245
246 # A Nit module, use to import the referenced extern classes
247 class NitModule
248 # Name of the module
249 var name: String
250
251 redef fun ==(other): Bool do return self.to_s == other.to_s
252 redef fun to_s: String do return self.name
253 redef fun hash: Int do return self.name.hash
254 end