1 # This file is part of NIT (http://www.nitlanguage.org).
3 # Copyright 2014 Frédéric Vachon <fredvac@gmail.com>
4 # Copyright 2015 Alexis Laferrière <alexis.laf@xymus.net>
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
10 # http://www.apache.org/licenses/LICENSE-2.0
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.
18 # Services to generate extern class `in "Java"`
25 # Path to the output file
28 # Model of Java class being wrapped
31 # Comment out methods with unknown (unwrapped) types
32 var comment_unknown_types
: Bool
34 # Generate stub classes for unknown types used in the generated module
35 var stub_for_unknown_types
: Bool
38 var file_out
: Writer = new FileWriter.open
(file_name
) is lazy
, writable
40 # Name of the Nit module to generate
41 var module_name
: nullable String is lazy
do
42 if file_name
.file_extension
== "nit" then
43 # Output file ends with .nit, we expect it to be a valid name
44 return file_name
.basename
(".nit")
48 # Generate the Nit module into `file_out`
52 file_out
.write license
55 var module_name
= module_name
56 if module_name
!= null then file_out
.write
"module {module_name}\n"
60 var imports
= new HashSet[String]
61 imports
.add
"import java\n"
62 for key
, jclass
in model
.classes
do
63 for import_
in jclass
.imports
do imports
.add
"import android::{import_}\n"
65 file_out
.write imports
.join
("\n")
68 for key
, jclass
in model
.classes
do
70 file_out
.write gen_class_header
(jclass
.class_type
)
72 for id
, signatures
in jclass
.methods
do
74 for signature
in signatures
do
76 if c
> 0 then nid
+= c
.to_s
79 file_out
.write gen_method
(jclass
, id
, nid
, signature
.return_type
, signature
.params
)
85 for constructor
in jclass
.constructors
do
86 var complex
= jclass
.constructors
.length
!= 1 and constructor
.params
.not_empty
87 var base_name
= if complex
then "from" else ""
88 var name
= jclass
.nit_name_for
(base_name
, constructor
.params
, complex
)
90 generate_constructor
(jclass
, constructor
, name
)
94 for id
, java_type
in jclass
.attributes
do
95 generate_getter_setter
(jclass
, id
, java_type
)
98 file_out
.write
"end\n\n"
101 if stub_for_unknown_types
then
102 for jtype
in model
.unknown_types
do
103 file_out
.write gen_unknown_class_header
(jtype
)
109 # License for the header of the generated Nit module
111 # This file is part of NIT (http://www.nitlanguage.org).
113 # Licensed under the Apache License, Version 2.0 (the "License");
114 # you may not use this file except in compliance with the License.
115 # You may obtain a copy of the License at
117 # http://www.apache.org/licenses/LICENSE-2.0
119 # Unless required by applicable law or agreed to in writing, software
120 # distributed under the License is distributed on an "AS IS" BASIS,
121 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
122 # See the License for the specific language governing permissions and
123 # limitations under the License.
125 # This code has been generated using `jwrapper`
128 fun gen_class_header
(jtype
: JavaType): String
130 var temp
= new Array[String]
131 var nit_type
= jtype
.to_nit_type
132 temp
.add
"# Java class: {jtype.to_package_name}\n"
133 temp
.add
"extern class {nit_type} in \"Java\
" `\{ {jtype.to_package_name} `\}\n"
134 temp
.add
"\tsuper JavaObject\n\n"
139 fun gen_unknown_class_header
(jtype
: JavaType): String
141 var nit_type
= jtype
.extern_name
143 var temp
= new Array[String]
144 temp
.add
("extern class {nit_type} in \"Java\
" `\{ {jtype.to_package_name} `\}\n")
145 temp
.add
("\tsuper JavaObject\n\nend\n")
150 fun gen_method
(java_class
: JavaClass, jmethod_id
, nmethod_id
: String, jreturn_type
: JavaType, jparam_list
: Array[JavaType]): String
156 var nit_types
= new Array[NitType]
160 for i
in [0..jparam_list
.length
[ do
161 var jparam
= jparam_list
[i
]
162 var nit_type
= jparam
.to_nit_type
164 if not nit_type
.is_complete
then
165 if jparam
.is_wrapped
then
166 java_class
.imports
.add nit_type
.mod
.as(not null)
168 model
.unknown_types
.add jparam
169 if comment_unknown_types
then
172 nit_type
= jparam
.extern_name
179 if not jparam
.is_collection
then cast
= jparam
.param_cast
181 nit_types
.add
(nit_type
)
183 if i
== jparam_list
.length
- 1 then
184 java_params
+= "{cast}{nit_id}{nit_id_no}"
185 nit_params
+= "{nit_id}{nit_id_no}: {nit_type}"
187 java_params
+= "{cast}{nit_id}{nit_id_no}" + ", "
188 nit_params
+= "{nit_id}{nit_id_no}: {nit_type}, "
194 # Method documentation
195 var doc
= "\t# Java implementation: {java_class}.{jmethod_id}\n"
198 var method_id
= nmethod_id
.to_nit_method_name
199 method_id
= java_class
.nit_name_for
(method_id
, jparam_list
, java_class
.methods
[jmethod_id
].length
> 1)
200 var nit_signature
= new Array[String]
202 nit_signature
.add
"\tfun {method_id}"
204 if not jparam_list
.is_empty
then
205 nit_signature
.add
"({nit_params})"
208 var return_type
= null
210 if not jreturn_type
.is_void
then
211 return_type
= jreturn_type
.to_nit_type
213 if not return_type
.is_complete
then
214 if jreturn_type
.is_wrapped
then
215 java_class
.imports
.add return_type
.mod
.as(not null)
217 model
.unknown_types
.add jreturn_type
218 if comment_unknown_types
then
221 return_type
= jreturn_type
.extern_name
226 nit_signature
.add
": {return_type} "
229 var temp
= new Array[String]
232 temp
.add
(comment
+ nit_signature
.join
)
234 if comment
== "#" then
235 temp
.add
(" in \"Java\
" `\{\n{comment}\t\tself.{jmethod_id}({java_params});\n{comment}\t`\}\n")
236 # Methods with return type
237 else if return_type
!= null then
238 temp
.add
(" in \"Java\
" `\{\n{comment}\t\treturn {jreturn_type.return_cast}self.{jmethod_id}({java_params});\n{comment}\t`\}\n")
239 # Methods without return type
240 else if jreturn_type
.is_void
then
241 temp
.add
(" in \"Java\
" `\{\n{comment}\t\tself.{jmethod_id}({java_params});\n{comment}\t`\}\n")
244 temp
.add
(" in \"Java\
" `\{\n{comment}\t\tself.{jmethod_id}({java_params});\n{comment}\t`\}\n")
250 # Generate getter and setter to access an attribute, of field
251 private fun generate_getter_setter
(java_class
: JavaClass, java_id
: String, java_type
: JavaType)
253 var nit_type
= model
.java_to_nit_type
(java_type
)
254 var nit_id
= java_id
.to_nit_method_name
255 nit_id
= java_class
.nit_name_for
(nit_id
, [java_type
], false)
258 if not nit_type
.is_known
then c
= "#"
261 # Java getter: {{{java_class}}}.{{{java_id}}}
262 {{{c}}} fun {{{nit_id}}}: {{{nit_type}}} in "Java" `{
263 {{{c}}} return self.{{{java_id}}};
266 # Java setter: {{{java_class}}}.{{{java_id}}}
267 {{{c}}} fun {{{nit_id}}}=(value: {{{nit_type}}}) in "Java" `{
268 {{{c}}} self.{{{java_id}}} = value;
274 # Generate getter and setter to access an attribute, of field
275 private fun generate_constructor
(java_class
: JavaClass, constructor
: JavaConstructor, name
: String)
278 var nit_params_s
= ""
279 var java_params_s
= ""
281 if constructor
.params
.not_empty
then
282 var nit_params
= new Array[String]
283 var java_params
= new Array[String]
285 for java_type
in constructor
.params
do
287 java_params
.add
"{java_type.param_cast}{param_id}"
289 var nit_type
= model
.java_to_nit_type
(java_type
)
290 nit_params
.add
"{param_id}: {nit_type}"
291 param_id
= param_id
.successor
(1)
293 if not nit_type
.is_known
then c
= "#"
296 nit_params_s
= "(" + nit_params
.join
(", ") + ")"
297 java_params_s
= java_params
.join
(", ")
301 # Java constructor: {{{java_class}}}
302 {{{c}}} new {{{name}}}{{{nit_params_s}}} in "Java" `{
303 {{{c}}} return new {{{java_class}}}({{{java_params_s}}});
311 # List of Nit keywords
313 # These may also be keywords in Java, but there they would be used capitalized.
314 private var nit_keywords
: Array[String] = ["abort", "abstract", "and", "assert",
315 "break", "class", "continue", "do", "else", "end", "enum", "extern", "false", "implies",
316 "import", "init", "interface", "intrude", "if", "in", "is", "isa", "isset", "for", "label",
317 "loop", "module", "new", "not", "null", "nullable", "or", "package", "private",
318 "protected", "public", "return", "self", "super", "then", "true", "type", "var", "while"]
323 # Convert the Java method name `self` to the Nit style
325 # * Converts to snake case
326 # * Strips `Get` and `Set`
327 # * Add suffix `=` to setters
328 fun to_nit_method_name
: String
330 var name
= self.to_snake_case
331 if name
.has_prefix
("get_") then
332 name
= name
.substring_from
(4)
333 else if name
.has_prefix
("set_") then
334 name
= name
.substring_from
(4)
335 if nit_keywords
.has
(name
) then name
+= "_"
339 # Strip the '_' prefix
340 while name
.has_prefix
("_") do name
= name
.substring
(1, name
.length-1
)
342 # Escape Nit keywords
343 if nit_keywords
.has
(name
) then name
+= "_"
345 # If the name starts by something other than a letter, prefix with `java_`
346 if not name
.chars
.first
.is_letter
then name
= "java_" + name
348 name
= name
.replace
("$", "_")
354 redef class JavaClass
355 # Property names used in this class
356 private var used_name
= new HashSet[String]
358 # Get an available property name for the Java property with `name` and parameters
360 # If `use_parameters_name` then expect that there will be conflicts,
361 # so use the types of `parameters` to build the name.
362 private fun nit_name_for
(name
: String, parameters
: Array[JavaType], use_parameters_name
: Bool): String
364 # Append the name of each parameter
365 if use_parameters_name
then
366 for param
in parameters
do
367 name
+= "_" + param
.id
371 # As a last resort, append numbers to the name
374 while used_name
.has
(name
) do
375 name
= base_name
+ count
.to_s