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
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
, java_type
in jclass
.attributes
do
90 generate_getter_setter
(jclass
, id
, java_type
)
93 file_out
.write
"end\n\n"
96 if stub_for_unknown_types
then
97 for jtype
, nit_type
in model
.unknown_types
do
98 generate_unknown_class_header
(jtype
)
104 # License for the header of the generated Nit module
106 # This file is part of NIT (http://www.nitlanguage.org).
108 # Licensed under the Apache License, Version 2.0 (the "License");
109 # you may not use this file except in compliance with the License.
110 # You may obtain a copy of the License at
112 # http://www.apache.org/licenses/LICENSE-2.0
114 # Unless required by applicable law or agreed to in writing, software
115 # distributed under the License is distributed on an "AS IS" BASIS,
116 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
117 # See the License for the specific language governing permissions and
118 # limitations under the License.
120 # This code has been generated using `jwrapper`
123 private fun generate_class_header
(jtype
: JavaType)
125 var nit_type
= model
.java_to_nit_type
(jtype
)
126 file_out
.write
"# Java class: {jtype.to_package_name}\n"
127 file_out
.write
"extern class {nit_type} in \"Java\
" `\{ {jtype.to_package_name} `\}\n"
128 file_out
.write
"\tsuper JavaObject\n\n"
131 private fun generate_unknown_class_header
(jtype
: JavaType)
133 var nit_type
= jtype
.extern_name
135 file_out
.write
"extern class {nit_type} in \"Java\
" `\{ {jtype.to_package_name} `\}\n"
136 file_out
.write
"\tsuper JavaObject\n\nend\n"
139 private fun generate_method
(java_class
: JavaClass, jmethod_id
, method_id
: String,
140 jreturn_type
: JavaType, jparam_list
: Array[JavaType])
146 var nit_types
= new Array[NitType]
150 for i
in [0..jparam_list
.length
[ do
151 var jparam
= jparam_list
[i
]
152 var nit_type
= model
.java_to_nit_type
(jparam
)
154 if not nit_type
.is_known
and comment_unknown_types
then comment
= "#"
155 if jparam
.is_primitive_array
then comment
= "#"
157 var cast
= jparam
.param_cast
159 nit_types
.add
(nit_type
)
161 if i
== jparam_list
.length
- 1 then
162 java_params
+= "{cast}{nit_id}{nit_id_no}"
163 nit_params
+= "{nit_id}{nit_id_no}: {nit_type}"
165 java_params
+= "{cast}{nit_id}{nit_id_no}" + ", "
166 nit_params
+= "{nit_id}{nit_id_no}: {nit_type}, "
172 # Method documentation
173 var doc
= "\t# Java implementation: {java_class}.{jmethod_id}\n"
176 method_id
= method_id
.to_nit_method_name
177 method_id
= java_class
.nit_name_for
(method_id
, jparam_list
, java_class
.methods
[jmethod_id
].length
> 1)
178 var nit_signature
= new Array[String]
180 nit_signature
.add
"\tfun {method_id}"
182 if not jparam_list
.is_empty
then
183 nit_signature
.add
"({nit_params})"
186 var return_type
= null
187 if not jreturn_type
.is_void
then
188 return_type
= model
.java_to_nit_type
(jreturn_type
)
190 if not return_type
.is_known
and comment_unknown_types
then comment
= "#"
191 if jreturn_type
.is_primitive_array
then comment
= "#"
193 nit_signature
.add
": {return_type} "
197 file_out
.write comment
+ nit_signature
.join
199 if comment
== "#" then
200 file_out
.write
" in \"Java\
" `\{\n{comment}\t\tself.{jmethod_id}({java_params});\n{comment}\t`\}\n"
201 # Methods with return type
202 else if return_type
!= null then
203 file_out
.write
" in \"Java\
" `\{\n{comment}\t\treturn {jreturn_type.return_cast}self.{jmethod_id}({java_params});\n{comment}\t`\}\n"
204 # Methods without return type
205 else if jreturn_type
.is_void
then
206 file_out
.write
" in \"Java\
" `\{\n{comment}\t\tself.{jmethod_id}({java_params});\n{comment}\t`\}\n"
209 file_out
.write
" in \"Java\
" `\{\n{comment}\t\tself.{jmethod_id}({java_params});\n{comment}\t`\}\n"
213 # Generate getter and setter to access an attribute, of field
214 private fun generate_getter_setter
(java_class
: JavaClass, java_id
: String, java_type
: JavaType)
216 var nit_type
= model
.java_to_nit_type
(java_type
)
217 var nit_id
= java_id
.to_nit_method_name
218 nit_id
= java_class
.nit_name_for
(nit_id
, [java_type
], false)
221 if not nit_type
.is_known
and comment_unknown_types
then c
= "#"
222 if java_type
.is_primitive_array
then c
= "#"
225 # Java getter: {{{java_class}}}.{{{java_id}}}
226 {{{c}}} fun {{{nit_id}}}: {{{nit_type}}} in "Java" `{
227 {{{c}}} return self.{{{java_id}}};
230 # Java setter: {{{java_class}}}.{{{java_id}}}
231 {{{c}}} fun {{{nit_id}}}=(value: {{{nit_type}}}) in "Java" `{
232 {{{c}}} self.{{{java_id}}} = value;
238 # Generate getter and setter to access an attribute, of field
239 private fun generate_constructor
(java_class
: JavaClass, constructor
: JavaConstructor, name
: String)
242 var nit_params_s
= ""
243 var java_params_s
= ""
245 if constructor
.params
.not_empty
then
246 var nit_params
= new Array[String]
247 var java_params
= new Array[String]
249 for java_type
in constructor
.params
do
251 java_params
.add
"{java_type.param_cast}{param_id}"
253 var nit_type
= model
.java_to_nit_type
(java_type
)
254 nit_params
.add
"{param_id}: {nit_type}"
255 param_id
= param_id
.successor
(1)
257 if not nit_type
.is_known
and comment_unknown_types
then c
= "#"
258 if java_type
.is_primitive_array
then c
= "#"
261 nit_params_s
= "(" + nit_params
.join
(", ") + ")"
262 java_params_s
= java_params
.join
(", ")
266 # Java constructor: {{{java_class}}}
267 {{{c}}} new {{{name}}}{{{nit_params_s}}} in "Java" `{
268 {{{c}}} return new {{{java_class}}}({{{java_params_s}}});
276 # List of Nit keywords
278 # These may also be keywords in Java, but there they would be used capitalized.
279 private var nit_keywords
= new HashSet[String].from
(["abort", "abstract", "and", "assert",
280 "break", "class", "continue", "do", "else", "end", "enum", "extern", "false", "implies",
281 "import", "init", "interface", "intrude", "if", "in", "is", "isa", "isset", "for", "label",
282 "loop", "module", "new", "not", "null", "nullable", "or", "package", "private",
283 "protected", "public", "return", "self", "super", "then", "true", "type", "var", "while",
286 "class_name", "get_time", "hash", "is_same_type", "is_same_instance", "output",
288 # Pointer or JavaObject methods
294 # Convert the Java method name `self` to the Nit style
296 # * Converts to snake case
297 # * Strips `Get` and `Set`
298 # * Add suffix `=` to setters
299 fun to_nit_method_name
: String
301 var name
= self.to_snake_case
303 # Strip the '_' prefix
304 while name
.has_prefix
("_") do name
= name
.substring
(1, name
.length-1
)
306 # Escape Nit keywords
307 if nit_keywords
.has
(name
) then name
+= "_"
309 # If the name starts by something other than a letter, prefix with `java_`
310 if not name
.chars
.first
.is_letter
then name
= "java_" + name
312 name
= name
.replace
("$", "_")
318 redef class JavaClass
319 # Property names used in this class
320 private var used_name
= new HashSet[String]
322 # Get an available property name for the Java property with `name` and parameters
324 # If `use_parameters_name` then expect that there will be conflicts,
325 # so use the types of `parameters` to build the name.
326 private fun nit_name_for
(name
: String, parameters
: Array[JavaType], use_parameters_name
: Bool): String
328 # Append the name of each parameter
329 if use_parameters_name
then
330 for param
in parameters
do
331 name
+= "_" + param
.id
335 # As a last resort, append numbers to the name
338 while used_name
.has
(name
) do
339 name
= base_name
+ count
.to_s