1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
24 # Path to the output file
25 var opt_output
= new OptionString("Output file", "-o")
27 # Shall `init` methods/constructors be wrapped as methods?
29 # By default, these methods/constructors are wrapped as extern constructors.
30 # So initializing an extern Objective-C object looks like:
32 # var o = new NSArray.init_with_array(some_other_array)
35 # If this option is set, the object must first be allocated and then initialized.
36 # This is closer to the Objective-C behavior:
39 # o.init_with_array(some_other_array)
41 var opt_init_as_methods
= new OptionBool(
42 "Wrap `init...` constructors as Nit methods instead of Nit constructors",
45 private var nit_to_java_types
: Map[String, String] is lazy
do
46 var types
= new HashMap[String, String]
47 types
["char"] = "Byte"
48 types
["short"] = "Int"
49 types
["short int"] = "Int"
52 types
["long int"] = "Int"
53 types
["long long"] = "Int"
54 types
["long long int"] = "Int"
55 types
["float"] = "Float"
56 types
["double"] = "Float"
57 types
["long double"] = "Float"
59 types
["NSUInteger"] = "Int"
60 types
["BOOL"] = "Bool"
61 types
["id"] = "NSObject"
67 # Generate Nit code to wrap `classes`
68 fun generate
(classes
: Array[ObjcClass])
70 # Open specified path or stdin
72 var path
= opt_output
.value
74 if path
.file_extension
!= "nit" then
75 print_error
"Warning: output file path does not end with '.nit'"
78 file
= new FileWriter.open
(path
)
84 file
.write
"import cocoa::foundation\n\n"
85 for classe
in classes
do
86 write_class
(classe
, file
)
89 if path
!= null then file
.close
92 private fun write_class
(classe
: ObjcClass, file
: Writer)
94 var commented_methods
= new Array[ObjcMethod]
95 file
.write
"extern class " + classe
.name
+ """ in "ObjC" `{ """ + classe.name + """ * `}\n"""
96 for super_name
in classe
.super_names
do
97 file
.write
""" super """ + super_name
+ "\n"
99 if classe
.super_names
.is_empty
then file
.write
""" super NSObject\n"""
100 write_constructor
(classe
, file
)
102 for attribute
in classe
.attributes
do
103 write_attribute
(attribute
, file
)
105 for method
in classe
.methods
do
106 if method
.is_commented
then
107 commented_methods
.add
(method
)
109 if not opt_init_as_methods
.value
and method
.params
.first
.name
.has
("init") then continue
111 write_method
(method
, file
)
112 file
.write
""" in "ObjC" `{\n """
113 write_objc_method_call
(method
, file
)
115 if method
!= classe
.methods
.last
then file
.write
"\n\n"
118 for commented_method
in commented_methods
do
119 if commented_method
== commented_methods
.first
then file
.write
"\n"
121 write_method
(commented_method
, file
)
122 if commented_method
!= commented_methods
.last
then file
.write
"\n"
127 private fun write_constructor
(classe
: ObjcClass, file
: Writer)
129 if not opt_init_as_methods
.value
then
130 for method
in classe
.methods
do
131 if method
.params
.first
.name
.has
("init") and not method
.is_commented
then
133 if method
.params
.first
.name
== "init" then
136 write_method
(method
, file
)
138 file
.write
""" in "ObjC" `{\n"""
139 write_objc_init_call
(classe
.name
, method
, file
)
140 file
.write
""" `}\n"""
144 file
.write
"""\n new in "ObjC"`{\n"""
145 file
.write
""" return [""" + classe
.name
+ " alloc];\n"
146 file
.write
""" `}\n"""
150 private fun write_attribute
(attribute
: ObjcAttribute, file
: Writer)
152 write_attribute_getter
(attribute
, file
)
153 # TODO write_attribute_setter if there is no `readonly` annotation
157 private fun write_attribute_getter
(attribute
: ObjcAttribute, file
: Writer)
159 file
.write
""" fun """ + attribute
.name
.to_snake_case
+ ": " + attribute
.return_type
.to_nit_type
160 file
.write
""" in "ObjC" `{\n"""
161 file
.write
""" return [self """ + attribute
.name
+ "];\n"
162 file
.write
""" `}\n"""
165 private fun write_attribute_setter
(attribute
: ObjcAttribute, file
: Writer)
167 file
.write
""" fun """ + attribute
.name
.to_snake_case
+ "=(value: " + attribute
.return_type
.to_nit_type
+ ")"
168 file
.write
" in \"ObjC\
" `\{\n"
169 file
.write
""" self.""" + attribute
.name
+ " = value;\n"
170 file
.write
""" `}\n"""
173 private fun write_method
(method
: ObjcMethod, file
: Writer)
176 for param
in method
.params
do
177 name
+= param
.name
[0].to_upper
.to_s
+ param
.name
.substring_from
(1)
178 name
= name
.to_snake_case
180 if name
.has
("init") and not opt_init_as_methods
.value
then
183 if opt_init_as_methods
.value
and name
== "init" then name
= "init_0"
187 for param
in method
.params
do
188 if param
== method
.params
.first
and not param
.is_single
then
189 file
.write
"(" + param
.variable_name
+ ": " + param
.return_type
.to_nit_type
191 if param
!= method
.params
.first
and not param
.is_single
then
192 file
.write
", " + param
.variable_name
+ ": " + param
.return_type
.to_nit_type
194 if param
== method
.params
.last
and not param
.is_single
then
198 if method
.return_type
!= "void" and not method
.params
.first
.name
.has
("init") then
199 file
.write
": " + method
.return_type
.to_nit_type
203 private fun write_objc_init_call
(classe_name
: String, method
: ObjcMethod, file
: Writer)
205 file
.write
""" return [[""" + classe_name
+ " alloc] "
206 for param
in method
.params
do
207 if not param
.is_single
then
208 file
.write param
.name
+ ":" + param
.variable_name
209 if not param
== method
.params
.last
then file
.write
" "
211 file
.write param
.name
217 private fun write_objc_method_call
(method
: ObjcMethod, file
: Writer)
219 if method
.return_type
!= "void" then file
.write
"return "
221 for param
in method
.params
do
222 if not param
.is_single
then
223 file
.write param
.name
+ ":" + param
.variable_name
224 if not param
== method
.params
.last
then file
.write
" "
226 file
.write param
.name
234 # Nit equivalent to this type
235 private fun to_nit_type
: String
237 var types
= sys
.nit_to_java_types
239 if types
.has_key
(self) then