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"
62 types
["constid"] = "NSObject"
63 types
["SEL"] = "NSObject"
64 types
["void"] = "Pointer"
76 # Generate Nit code to wrap `classes`
79 var classes
= model
.classes
81 # Open specified path or stdin
83 var path
= opt_output
.value
85 if path
.file_extension
!= "nit" then
86 print_error
"Warning: output file path does not end with '.nit'"
89 file
= new FileWriter.open
(path
)
95 file
.write
"import cocoa::foundation\n\n"
96 for classe
in classes
do
97 write_class
(classe
, file
)
100 if path
!= null then file
.close
103 private fun write_class
(classe
: ObjcClass, file
: Writer)
108 extern class {{{classe.name}}} in "ObjC" `{ {{{classe.name}}} * `}
112 for super_name
in classe
.super_names
do file
.write
"""
113 super {{{super_name}}}
115 if classe
.super_names
.is_empty
then file
.write
"""
121 # Constructor or constructors
122 write_constructors
(classe
, file
)
125 for attribute
in classe
.attributes
do
126 write_attribute
(attribute
, file
)
130 for method
in classe
.methods
do
132 if not opt_init_as_methods
.value
and method
.is_init
then continue
134 write_method_signature
(method
, file
)
135 write_objc_method_call
(method
, file
)
143 private fun write_constructors
(classe
: ObjcClass, file
: Writer)
145 if opt_init_as_methods
.value
then
146 # A single constructor for `alloc`
149 return [{{{classe.name}}} alloc];
156 # A constructor per `init...` method
157 for method
in classe
.methods
do
158 if not method
.is_init
then continue
160 write_method_signature
(method
, file
)
162 write_objc_init_call
(classe
.name
, method
, file
)
166 private fun write_attribute
(attribute
: ObjcAttribute, file
: Writer)
168 write_attribute_getter
(attribute
, file
)
169 # TODO write_attribute_setter if there is no `readonly` annotation
172 private fun write_attribute_getter
(attribute
: ObjcAttribute, file
: Writer)
174 var nit_attr_name
= attribute
.name
.to_snake_case
175 var nit_attr_type
= attribute
.return_type
.to_nit_type
177 var c
= attribute
.comment_str
180 {{{c}}} fun {{{nit_attr_name}}}: {{{nit_attr_type}}} in "ObjC" `{
181 {{{c}}} return [self {{{attribute.name}}}];
187 private fun write_attribute_setter
(attribute
: ObjcAttribute, file
: Writer)
189 var nit_attr_name
= attribute
.name
.to_snake_case
190 var nit_attr_type
= attribute
.return_type
.to_nit_type
192 var c
= attribute
.comment_str
195 {{{c}}} fun {{{nit_attr_name}}}=(value: {{{nit_attr_type}}}) in "ObjC" `{
196 {{{c}}} return self.{{{attribute.name}}} = value;
202 private fun write_method_signature
(method
: ObjcMethod, file
: Writer)
204 var c
= method
.comment_str
206 # Build Nit method name
208 for param
in method
.params
do
209 name
+= param
.name
[0].to_upper
.to_s
+ param
.name
.substring_from
(1)
211 name
= name
.to_snake_case
213 if name
== "init" then name
= ""
216 var fun_keyword
= "fun"
217 if not opt_init_as_methods
.value
and method
.is_init
then
222 var params
= new Array[String]
223 for param
in method
.params
do
224 if param
.is_single
then break
225 params
.add
"{param.variable_name}: {param.return_type.to_nit_type}"
228 var params_with_par
= ""
229 if params
.not_empty
then params_with_par
= "({params.join(", ")})"
233 if method
.return_type
!= "void" and fun_keyword
!= "new" then
234 ret
= ": {method.return_type.to_nit_type}"
238 {{{c}}} {{{fun_keyword}}} {{{name}}}{{{params_with_par}}}{{{ret}}} in "ObjC" `{
242 # Write a combined call to alloc and to a constructor/method
243 private fun write_objc_init_call
(class_name
: String, method
: ObjcMethod, file
: Writer)
245 # Method name and other params
246 var params
= new Array[String]
247 for param
in method
.params
do
248 if not param
.is_single
then
249 params
.add
"{param.name}: {param.variable_name}"
250 else params
.add param
.name
253 var c
= method
.comment_str
256 {{{c}}} return [[{{{class_name}}} alloc] {{{params.join(" ")}}}];
262 private fun write_objc_method_call
(method
: ObjcMethod, file
: Writer)
264 # Is there a value to return?
266 if method
.return_type
!= "void" then ret
= "return "
268 # Method name and other params
269 var params
= new Array[String]
270 for param
in method
.params
do
271 if not param
.is_single
then
272 params
.add
"{param.name}: {param.variable_name}"
273 else params
.add param
.name
276 var c
= method
.comment_str
279 {{{c}}} {{{ret}}}[self {{{params.join(" ")}}}];
287 # Nit equivalent to this type
288 private fun to_nit_type
: String
290 var types
= sys
.nit_to_java_types
292 if types
.has_key
(self) then
301 private fun comment_str
: String do if is_commented
then