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 generate_class_header
(jclass
.class_type
)
72 for id
, signatures
in jclass
.methods
do
73 for signature
in signatures
do if not signature
.is_static
then
74 generate_method
(jclass
, id
, id
, signature
.return_type
, signature
.params
)
80 for constructor
in jclass
.constructors
do
81 var complex
= jclass
.constructors
.length
!= 1 and constructor
.params
.not_empty
82 var base_name
= if complex
then "from" else ""
83 var name
= jclass
.nit_name_for
(base_name
, constructor
.params
, complex
)
85 generate_constructor
(jclass
, constructor
, name
)
89 for id
, attribute
in jclass
.attributes
do if not attribute
.is_static
then
90 generate_getter_setter
(jclass
, id
, attribute
)
94 file_out
.write
"end\n\n"
96 # Static functions as top-level methods
97 var static_functions_prefix
= jclass
.class_type
.extern_name
.to_snake_case
98 for id
, signatures
in jclass
.methods
do
99 for signature
in signatures
do if signature
.is_static
then
100 var nit_id
= static_functions_prefix
+ "_" + id
101 generate_method
(jclass
, id
, nit_id
, signature
.return_type
, signature
.params
, is_static
=true)
106 # Static attributes as top-level getters and setters
107 for id
, attribute
in jclass
.attributes
do if attribute
.is_static
then
108 generate_getter_setter
(jclass
, id
, attribute
)
112 for d
in [1..opt_arrays
.value
] do
113 generate_primitive_array
(jclass
, d
)
117 if stub_for_unknown_types
then
118 for jtype
, nit_type
in model
.unknown_types
do
119 generate_unknown_class_header
(jtype
)
125 # License for the header of the generated Nit module
127 # This file is part of NIT (http://www.nitlanguage.org).
129 # Licensed under the Apache License, Version 2.0 (the "License");
130 # you may not use this file except in compliance with the License.
131 # You may obtain a copy of the License at
133 # http://www.apache.org/licenses/LICENSE-2.0
135 # Unless required by applicable law or agreed to in writing, software
136 # distributed under the License is distributed on an "AS IS" BASIS,
137 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138 # See the License for the specific language governing permissions and
139 # limitations under the License.
141 # This code has been generated using `jwrapper`
144 private fun generate_class_header
(jtype
: JavaType)
146 var nit_type
= model
.java_to_nit_type
(jtype
)
147 file_out
.write
"# Java class: {jtype.to_package_name}\n"
148 file_out
.write
"extern class {nit_type} in \"Java\
" `\{ {jtype.to_package_name} `\}\n"
149 file_out
.write
"\tsuper JavaObject\n\n"
152 private fun generate_unknown_class_header
(jtype
: JavaType)
154 var nit_type
= jtype
.extern_name
156 file_out
.write
"extern class {nit_type} in \"Java\
" `\{ {jtype.to_package_name} `\}\n"
157 file_out
.write
"\tsuper JavaObject\n\nend\n"
160 private fun generate_method
(java_class
: JavaClass, java_method_id
, method_id
: String,
161 java_return_type
: JavaType, java_params
: Array[JavaType], is_static
: nullable Bool)
163 var java_args
= new Array[String]
164 var nit_params
= new Array[String]
170 for jparam
in java_params
do
171 var nit_type
= model
.java_to_nit_type
(jparam
)
173 if not nit_type
.is_known
and comment_unknown_types
then c
= "#"
175 java_args
.add
"{jparam.param_cast}{nit_id}{nit_id_no}"
176 nit_params
.add
"{nit_id}{nit_id_no}: {nit_type}"
182 method_id
= method_id
.to_nit_method_name
183 method_id
= java_class
.nit_name_for
(method_id
, java_params
, java_class
.methods
[java_method_id
].length
> 1)
185 # Build the signature
186 var nit_signature
= new Array[String]
187 nit_signature
.add
"fun {method_id}"
188 if not java_params
.is_empty
then nit_signature
.add
"({nit_params.join(", ")})"
191 var return_type
= null
192 if not java_return_type
.is_void
then
193 return_type
= model
.java_to_nit_type
(java_return_type
)
195 if not return_type
.is_known
and comment_unknown_types
then c
= "#"
197 nit_signature
.add
": " + return_type
.to_s
200 # Build the call in Java
202 if is_static
== true then
203 java_call
= java_class
.class_type
.to_package_name
204 else java_call
= "self"
205 java_call
+= ".{java_method_id}({java_args.join(", ")})"
207 if return_type
!= null then java_call
= "return {java_return_type.return_cast}" + java_call
211 if is_static
== true then t
= ""
216 {{{t}}}# Java implementation: {{{java_return_type}}} {{{java_class}}}.{{{java_method_id}}}({{{java_params.join(", ")}}})
217 {{{ct}}}{{{nit_signature.join}}} in "Java" `{
218 {{{ct}}} {{{java_call}}};
223 # Generate getter and setter to access an attribute, of field
224 private fun generate_getter_setter
(java_class
: JavaClass, java_id
: String,
225 attribute
: JavaAttribute)
227 var java_type
= attribute
.java_type
228 var nit_type
= model
.java_to_nit_type
(java_type
)
231 if attribute
.is_static
then nit_id
= java_class
.class_type
.extern_name
.to_snake_case
+ "_" + nit_id
232 nit_id
= nit_id
.to_nit_method_name
233 nit_id
= java_class
.nit_name_for
(nit_id
, [java_type
], false)
236 if not nit_type
.is_known
and comment_unknown_types
then c
= "#"
239 if attribute
.is_static
== true then
240 recv
= java_class
.class_type
.to_package_name
245 if attribute
.is_static
then t
= ""
249 {{{t}}}# Java getter: {{{java_class}}}.{{{java_id}}}
250 {{{ct}}}fun {{{nit_id}}}: {{{nit_type}}} in "Java" `{
251 {{{ct}}} return {{{recv}}}.{{{java_id}}};
254 {{{t}}}# Java setter: {{{java_class}}}.{{{java_id}}}
255 {{{ct}}}fun {{{nit_id}}}=(value: {{{nit_type}}}) in "Java" `{
256 {{{ct}}} {{{recv}}}.{{{java_id}}} = value;
262 # Generate getter and setter to access an attribute, of field
263 private fun generate_constructor
(java_class
: JavaClass, constructor
: JavaConstructor, name
: String)
266 var nit_params_s
= ""
267 var java_params_s
= ""
269 if constructor
.params
.not_empty
then
270 var nit_params
= new Array[String]
271 var java_params
= new Array[String]
273 for java_type
in constructor
.params
do
275 java_params
.add
"{java_type.param_cast}{param_id}"
277 var nit_type
= model
.java_to_nit_type
(java_type
)
278 nit_params
.add
"{param_id}: {nit_type}"
279 param_id
= param_id
.successor
(1)
281 if not nit_type
.is_known
and comment_unknown_types
then c
= "#"
284 nit_params_s
= "(" + nit_params
.join
(", ") + ")"
285 java_params_s
= java_params
.join
(", ")
289 # Java constructor: {{{java_class}}}
290 {{{c}}} new {{{name}}}{{{nit_params_s}}} in "Java" `{
291 {{{c}}} return new {{{java_class}}}({{{java_params_s}}});
297 private fun generate_primitive_array
(java_class
: JavaClass, dimensions
: Int)
299 var base_java_type
= java_class
.class_type
300 var java_type
= base_java_type
.clone
301 java_type
.array_dimension
= dimensions
303 var base_nit_type
= model
.java_to_nit_type
(base_java_type
)
304 var nit_type
= model
.java_to_nit_type
(java_type
)
307 # Java primitive array: {{{java_type}}}
308 extern class {{{nit_type}}} in "Java" `{ {{{java_type.extern_equivalent}}} `}
309 super AbstractJavaArray[{{{base_nit_type}}}]
311 # Get a new array of the given `size`
312 new(size: Int) in "Java" `{ return new {{{base_java_type}}}[(int)size]; `}
314 redef fun [](i) in "Java" `{ return self[(int)i]; `}
316 redef fun []=(i, e) in "Java" `{ self[(int)i] = e; `}
318 redef fun length in "Java" `{ return self.length; `}
326 # List of Nit keywords
328 # These may also be keywords in Java, but there they would be used capitalized.
329 private var nit_keywords
= new HashSet[String].from
(["abort", "abstract", "and", "assert",
330 "break", "class", "continue", "do", "else", "end", "enum", "extern", "false", "implies",
331 "import", "init", "interface", "intrude", "if", "in", "is", "isa", "isset", "for", "label",
332 "loop", "module", "new", "not", "null", "nullable", "or", "package", "private",
333 "protected", "public", "return", "self", "super", "then", "true", "type", "var", "while",
336 "class_name", "get_time", "hash", "is_same_type", "is_same_instance", "output",
338 # Pointer or JavaObject methods
344 # Convert the Java method name `self` to the Nit style
346 # * Converts to snake case
347 # * Strips `Get` and `Set`
348 # * Add suffix `=` to setters
349 fun to_nit_method_name
: String
351 var name
= self.to_snake_case
353 # Strip the '_' prefix
354 while name
.has_prefix
("_") do name
= name
.substring
(1, name
.length-1
)
356 # Escape Nit keywords
357 if nit_keywords
.has
(name
) then name
+= "_"
359 # If the name starts by something other than a letter, prefix with `java_`
360 if not name
.chars
.first
.is_letter
then name
= "java_" + name
362 name
= name
.replace
("$", "_")
368 redef class JavaClass
369 # Property names used in this class
370 private var used_name
= new HashSet[String]
372 # Get an available property name for the Java property with `name` and parameters
374 # If `use_parameters_name` then expect that there will be conflicts,
375 # so use the types of `parameters` to build the name.
376 private fun nit_name_for
(name
: String, parameters
: Array[JavaType], use_parameters_name
: Bool): String
378 # Append the name of each parameter
379 if use_parameters_name
then
380 for param
in parameters
do
381 name
+= "_" + param
.id
385 # As a last resort, append numbers to the name
388 while used_name
.has
(name
) do
389 name
= base_name
+ count
.to_s