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
)
83 file_out
.write
"end\n\n"
86 if stub_for_unknown_types
then
87 for jtype
in model
.unknown_types
do
88 file_out
.write gen_unknown_class_header
(jtype
)
94 # License for the header of the generated Nit module
96 # This file is part of NIT (http://www.nitlanguage.org).
98 # Licensed under the Apache License, Version 2.0 (the "License");
99 # you may not use this file except in compliance with the License.
100 # You may obtain a copy of the License at
102 # http://www.apache.org/licenses/LICENSE-2.0
104 # Unless required by applicable law or agreed to in writing, software
105 # distributed under the License is distributed on an "AS IS" BASIS,
106 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
107 # See the License for the specific language governing permissions and
108 # limitations under the License.
110 # This code has been generated using `jwrapper`
113 fun gen_class_header
(jtype
: JavaType): String
115 var temp
= new Array[String]
116 var nit_type
= jtype
.to_nit_type
117 temp
.add
"# Java class: {jtype.to_package_name}\n"
118 temp
.add
"extern class {nit_type} in \"Java\
" `\{ {jtype.to_package_name} `\}\n"
119 temp
.add
"\tsuper JavaObject\n\n"
124 fun gen_unknown_class_header
(jtype
: JavaType): String
126 var nit_type
= jtype
.extern_name
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")
135 fun gen_method
(java_class
: JavaClass, jmethod_id
, nmethod_id
: String, jreturn_type
: JavaType, jparam_list
: Array[JavaType]): String
141 var nit_types
= new Array[NitType]
145 for i
in [0..jparam_list
.length
[ do
146 var jparam
= jparam_list
[i
]
147 var nit_type
= jparam
.to_nit_type
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)
153 model
.unknown_types
.add jparam
154 if comment_unknown_types
then
157 nit_type
= jparam
.extern_name
164 if not jparam
.is_collection
then cast
= jparam
.param_cast
166 nit_types
.add
(nit_type
)
168 if i
== jparam_list
.length
- 1 then
169 java_params
+= "{cast}{nit_id}{nit_id_no}"
170 nit_params
+= "{nit_id}{nit_id_no}: {nit_type}"
172 java_params
+= "{cast}{nit_id}{nit_id_no}" + ", "
173 nit_params
+= "{nit_id}{nit_id_no}: {nit_type}, "
179 # Method documentation
180 var doc
= "\t# Java implementation: {java_class}.{jmethod_id}\n"
183 var method_id
= nmethod_id
.to_nit_method_name
184 method_id
= java_class
.nit_name_for
(method_id
, jparam_list
, java_class
.methods
[jmethod_id
].length
> 1)
185 var nit_signature
= new Array[String]
187 nit_signature
.add
"\tfun {method_id}"
189 if not jparam_list
.is_empty
then
190 nit_signature
.add
"({nit_params})"
193 var return_type
= null
195 if not jreturn_type
.is_void
then
196 return_type
= jreturn_type
.to_nit_type
198 if not return_type
.is_complete
then
199 if jreturn_type
.is_wrapped
then
200 java_class
.imports
.add return_type
.mod
.as(not null)
202 model
.unknown_types
.add jreturn_type
203 if comment_unknown_types
then
206 return_type
= jreturn_type
.extern_name
211 nit_signature
.add
": {return_type} "
214 var temp
= new Array[String]
217 temp
.add
(comment
+ nit_signature
.join
)
219 if comment
== "#" then
220 temp
.add
(" in \"Java\
" `\{\n{comment}\t\tself.{jmethod_id}({java_params});\n{comment}\t`\}\n")
221 # Methods with return type
222 else if return_type
!= null then
223 temp
.add
(" in \"Java\
" `\{\n{comment}\t\treturn {jreturn_type.return_cast}self.{jmethod_id}({java_params});\n{comment}\t`\}\n")
224 # Methods without return type
225 else if jreturn_type
.is_void
then
226 temp
.add
(" in \"Java\
" `\{\n{comment}\t\tself.{jmethod_id}({java_params});\n{comment}\t`\}\n")
229 temp
.add
(" in \"Java\
" `\{\n{comment}\t\tself.{jmethod_id}({java_params});\n{comment}\t`\}\n")
237 # List of Nit keywords
239 # These may also be keywords in Java, but there they would be used capitalized.
240 private var nit_keywords
: Array[String] = ["abort", "abstract", "and", "assert",
241 "break", "class", "continue", "do", "else", "end", "enum", "extern", "false", "implies",
242 "import", "init", "interface", "intrude", "if", "in", "is", "isa", "isset", "for", "label",
243 "loop", "module", "new", "not", "null", "nullable", "or", "package", "private",
244 "protected", "public", "return", "self", "super", "then", "true", "type", "var", "while"]
249 # Convert the Java method name `self` to the Nit style
251 # * Converts to snake case
252 # * Strips `Get` and `Set`
253 # * Add suffix `=` to setters
254 fun to_nit_method_name
: String
256 var name
= self.to_snake_case
257 if name
.has_prefix
("get_") then
258 name
= name
.substring_from
(4)
259 else if name
.has_prefix
("set_") then
260 name
= name
.substring_from
(4)
261 if nit_keywords
.has
(name
) then name
+= "_"
265 # Strip the '_' prefix
266 while name
.has_prefix
("_") do name
= name
.substring
(1, name
.length-1
)
268 # Escape Nit keywords
269 if nit_keywords
.has
(name
) then name
+= "_"
271 # If the name starts by something other than a letter, prefix with `java_`
272 if not name
.chars
.first
.is_letter
then name
= "java_" + name
274 name
= name
.replace
("$", "_")
280 redef class JavaClass
281 # Property names used in this class
282 private var used_name
= new HashSet[String]
284 # Get an available property name for the Java property with `name` and parameters
286 # If `use_parameters_name` then expect that there will be conflicts,
287 # so use the types of `parameters` to build the name.
288 private fun nit_name_for
(name
: String, parameters
: Array[JavaType], use_parameters_name
: Bool): String
290 # Append the name of each parameter
291 if use_parameters_name
then
292 for param
in parameters
do
293 name
+= "_" + param
.id
297 # As a last resort, append numbers to the name
300 while used_name
.has
(name
) do
301 name
= base_name
+ count
.to_s