contrib/jwrapper: remove illegal attribute generation
[nit.git] / contrib / jwrapper / src / code_generator.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 # Services to generate extern class `in "Java"`
18 module code_generator
19
20 intrude import model
21
22 class CodeGenerator
23
24 var with_attributes: Bool
25 var comment_unknown_types: Bool
26 var file_out: FileWriter
27 var java_class: JavaClass
28 var nb_params: Int
29 var module_name: nullable String = null
30
31 init (file_name: String, jclass: JavaClass, with_attributes, comment: Bool)
32 do
33 file_out = new FileWriter.open(file_name)
34
35 var nit_ext = ".nit"
36 if file_name.has_suffix(nit_ext) then
37 # Output file ends with .nit, we expect it to be a valid name
38 module_name = file_name.strip_extension(nit_ext)
39
40 # Otherwise, it may be anything so do not declare a module
41 end
42
43 self.java_class = jclass
44 self.with_attributes = with_attributes
45 self.comment_unknown_types = comment
46 end
47
48 fun generate
49 do
50 var jclass = self.java_class
51
52 var class_content = new Array[String]
53 class_content.add(gen_class_header(jclass.class_type))
54
55 for id, methods_info in jclass.methods do
56 for method_info in methods_info do
57 var nid = id
58 if methods_info.length > 1 then nid += "{methods_info.index_of(method_info)}"
59 class_content.add gen_method(id, nid, method_info.return_type, method_info.params)
60 end
61 end
62 class_content.add("\nend\n")
63
64 var wrappers = new Array[String]
65 for jtype in jclass.unknown_types do
66 if jtype == jclass.class_type then continue
67 wrappers.add("\n")
68 wrappers.add(gen_unknown_class_header(jtype))
69 end
70
71 var imports = new Array[String]
72 imports.add("import mnit_android\n")
73 for import_ in jclass.imports do
74 imports.add("import android::{import_}\n")
75 end
76
77 file_out.write(gen_licence)
78
79 var module_name = module_name
80 if module_name != null then file_out.write "module {module_name}\n"
81
82 file_out.write("\n")
83 file_out.write(imports.join)
84 file_out.write("\n")
85 file_out.write(class_content.join)
86 file_out.write(wrappers.join)
87 end
88
89 fun gen_licence: String
90 do
91 return """
92 # This file is part of NIT (http://www.nitlanguage.org).
93 #
94 # Licensed under the Apache License, Version 2.0 (the "License");
95 # you may not use this file except in compliance with the License.
96 # You may obtain a copy of the License at
97 #
98 # http://www.apache.org/licenses/LICENSE-2.0
99 #
100 # Unless required by applicable law or agreed to in writing, software
101 # distributed under the License is distributed on an "AS IS" BASIS,
102 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
103 # See the License for the specific language governing permissions and
104 # limitations under the License.
105
106 # This code has been generated using `jwrapper`
107 """
108 end
109
110 fun gen_class_header(jtype: JavaType): String
111 do
112 var temp = new Array[String]
113 temp.add("extern class Native{jtype.id} in \"Java\" `\{ {jtype} `\}\n")
114 temp.add("\tsuper JavaObject\n\n")
115
116 return temp.join
117 end
118
119 fun gen_unknown_class_header(jtype: JavaType): String
120 do
121 var nit_type: NitType
122 if jtype.extern_name.has_generic_params then
123 nit_type = jtype.extern_name.generic_params.first
124 else
125 nit_type = jtype.extern_name
126 end
127
128 var temp = new Array[String]
129 temp.add("extern class {nit_type} in \"Java\" `\{ {jtype.to_package_name} `\}\n")
130 temp.add("\tsuper JavaObject\n\nend\n")
131
132 return temp.join
133 end
134
135 fun gen_method(jmethod_id: String, nmethod_id: String, jreturn_type: JavaType, jparam_list: Array[JavaType]): String
136 do
137 var java_params = ""
138 var nit_params = ""
139 var nit_id = "arg"
140 var nit_id_no = 0
141 var nit_types = new Array[NitType]
142 var comment = ""
143
144 # Parameters
145 for i in [0..jparam_list.length[ do
146 var jparam = jparam_list[i]
147 var nit_type = jparam.to_nit_type
148
149 if not nit_type.is_complete then
150 if jparam.is_wrapped then
151 java_class.imports.add nit_type.mod.as(not null)
152 else
153 if comment_unknown_types then
154 comment = "#"
155 else
156 nit_type = jparam.extern_name
157 java_class.unknown_types.add(jparam)
158 end
159 end
160 end
161
162 var cast = ""
163
164 if not jparam.is_collection then cast = jparam.param_cast
165
166 nit_types.add(nit_type)
167 nit_type.arg_id = "{nit_id}{nit_id_no}"
168
169 if i == jparam_list.length - 1 then
170 java_params += "{cast}{nit_id}{nit_id_no}"
171 nit_params += "{nit_id}{nit_id_no}: {nit_type}"
172 else
173 java_params += "{cast}{nit_id}{nit_id_no}" + ", "
174 nit_params += "{nit_id}{nit_id_no}: {nit_type}, "
175 end
176
177 nit_id_no += 1
178 end
179
180 # Method identifier
181 var method_id = nmethod_id.to_nit_method_name
182 var nit_signature = new Array[String]
183
184 nit_signature.add "\tfun {method_id}"
185
186 if not jparam_list.is_empty then
187 nit_signature.add "({nit_params})"
188 end
189
190 var return_type = null
191
192 if not jreturn_type.is_void then
193 return_type = jreturn_type.to_nit_type
194
195 if not return_type.is_complete then
196 if jreturn_type.is_wrapped then
197 java_class.imports.add return_type.mod.as(not null)
198 else
199 if comment_unknown_types then
200 comment = "#"
201 else
202 return_type = jreturn_type.extern_name
203 java_class.unknown_types.add(jreturn_type)
204 end
205 end
206 end
207
208 nit_signature.add ": {return_type} "
209 end
210
211 var temp = new Array[String]
212
213 temp.add(comment + nit_signature.join)
214
215 # FIXME : This huge `if` block is only necessary to copy primitive arrays as long as there's no better way to do it
216 if comment == "#" then
217 temp.add(" in \"Java\" `\{\n{comment}\t\tself.{jmethod_id}({java_params});\n{comment}\t`\}\n")
218 # Methods with return type
219 else if return_type != null then
220 temp.add(" in \"Java\" `\{\n{comment}\t\treturn {jreturn_type.return_cast}self.{jmethod_id}({java_params});\n{comment}\t`\}\n")
221 # Methods without return type
222 else if jreturn_type.is_void then
223 temp.add(" in \"Java\" `\{\n{comment}\t\tself.{jmethod_id}({java_params});\n{comment}\t`\}\n")
224 # No copy
225 else
226 temp.add(" in \"Java\" `\{\n{comment}\t\tself.{jmethod_id}({java_params});\n{comment}\t`\}\n")
227 end
228
229 return temp.join
230 end
231 end
232
233 redef class String
234 # Convert the Java method name `self` to the Nit style
235 #
236 # * Converts to snake case
237 # * Strips `Get` and `Set`
238 # * Add suffix `=` to setters
239 fun to_nit_method_name: String
240 do
241 var name = self.to_snake_case
242 if name.has_prefix("get_") then
243 name = name.substring_from(4)
244 else if name.has_prefix("set_") then
245 name = name.substring_from(4) + "="
246 end
247
248 return name
249 end
250 end