1 /* valaccodemethodmodule.vala
3 * Copyright (C) 2007-2009 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Jürg Billeter <j@bitron.ch>
21 * Raffaele Sandrini <raffaele@sandrini.ch>
28 * The link between a method and generated code.
30 public class Vala
.CCodeMethodModule
: CCodeStructModule
{
31 public CCodeMethodModule (CCodeGenerator codegen
, CCodeModule? next
) {
35 public override bool method_has_wrapper (Method method
) {
36 return (method
.get_attribute ("NoWrapper") == null);
39 public override string?
get_custom_creturn_type (Method m
) {
40 var attr
= m
.get_attribute ("CCode");
42 string type
= attr
.get_string ("type");
50 string get_creturn_type (Method m
, string default_value
) {
51 string type
= get_custom_creturn_type (m
);
58 public override void visit_method (Method m
) {
59 var old_type_symbol
= current_type_symbol
;
60 var old_symbol
= current_symbol
;
61 Method old_method
= current_method
;
62 DataType old_return_type
= current_return_type
;
63 bool old_method_inner_error
= current_method_inner_error
;
64 int old_next_temp_var_id
= next_temp_var_id
;
65 var old_variable_name_map
= variable_name_map
;
66 var old_try
= current_try
;
67 if (m
.parent_symbol is TypeSymbol
) {
68 current_type_symbol
= (TypeSymbol
) m
.parent_symbol
;
72 current_return_type
= m
.return_type
;
73 current_method_inner_error
= false;
75 variable_name_map
= new HashMap
<string,string> (str_hash
, str_equal
);
78 bool in_gtypeinstance_creation_method
= false;
79 bool in_gobject_creation_method
= false;
80 bool in_fundamental_creation_method
= false;
82 check_type (m
.return_type
);
84 if (m is CreationMethod
) {
85 in_creation_method
= true;
86 var cl
= current_type_symbol as Class
;
87 if (cl
!= null && !cl
.is_compact
) {
88 in_gtypeinstance_creation_method
= true;
89 if (cl
.base_class
== null) {
90 in_fundamental_creation_method
= true;
91 } else if (cl
.is_subtype_of (gobject_type
)) {
92 in_gobject_creation_method
= true;
97 current_return_type
= new
ObjectType (cl
);
101 var creturn_type
= current_return_type
;
103 m
.accept_children (codegen
);
105 if (m is CreationMethod
) {
106 if (in_gobject_creation_method
&& m
.body
!= null) {
107 var cblock
= new
CCodeBlock ();
109 if (!((CreationMethod
) m
).chain_up
) {
110 // set construct properties
111 foreach (CodeNode stmt
in m
.body
.get_statements ()) {
112 var expr_stmt
= stmt as ExpressionStatement
;
113 if (expr_stmt
!= null) {
114 var prop
= expr_stmt
.assigned_property ();
115 if (prop
!= null && prop
.set_accessor
.construction
) {
116 if (stmt
.ccodenode is CCodeFragment
) {
117 foreach (CCodeNode cstmt
in ((CCodeFragment
) stmt
.ccodenode
).get_children ()) {
118 cblock
.add_statement (cstmt
);
121 cblock
.add_statement (stmt
.ccodenode
);
127 add_object_creation (cblock
, ((CreationMethod
) m
).n_construction_params
> 0 || current_class
.get_type_parameters ().size
> 0);
129 var cdeclaration
= new
CCodeDeclaration ("%s *".printf (((Class
) current_type_symbol
).get_cname ()));
130 cdeclaration
.add_declarator (new
CCodeVariableDeclarator ("self"));
132 cblock
.add_statement (cdeclaration
);
135 // other initialization code
136 foreach (CodeNode stmt
in m
.body
.get_statements ()) {
137 var expr_stmt
= stmt as ExpressionStatement
;
138 if (expr_stmt
!= null) {
139 var prop
= expr_stmt
.assigned_property ();
140 if (prop
!= null && prop
.set_accessor
.construction
) {
144 if (stmt
.ccodenode is CCodeFragment
) {
145 foreach (CCodeNode cstmt
in ((CCodeFragment
) stmt
.ccodenode
).get_children ()) {
146 cblock
.add_statement (cstmt
);
149 cblock
.add_statement (stmt
.ccodenode
);
153 m
.body
.ccodenode
= cblock
;
156 in_creation_method
= false;
159 bool inner_error
= current_method_inner_error
;
161 current_type_symbol
= old_type_symbol
;
162 current_symbol
= old_symbol
;
163 current_method
= old_method
;
164 current_return_type
= old_return_type
;
165 current_method_inner_error
= old_method_inner_error
;
166 next_temp_var_id
= old_next_temp_var_id
;
167 variable_name_map
= old_variable_name_map
;
168 current_try
= old_try
;
170 function
= new
CCodeFunction (m
.get_real_cname (), get_creturn_type (m
, creturn_type
.get_cname ()));
171 m
.ccodenode
= function
;
174 function
.modifiers
|= CCodeModifiers
.INLINE
;
177 var cparam_map
= new HashMap
<int,CCodeFormalParameter
> (direct_hash
, direct_equal
);
179 CCodeFunctionDeclarator vdeclarator
= null;
180 if (m
.is_abstract
|| m
.is_virtual
) {
181 var vdecl
= new
CCodeDeclaration (get_creturn_type (m
, creturn_type
.get_cname ()));
182 vdeclarator
= new
CCodeFunctionDeclarator (m
.vfunc_name
);
183 vdecl
.add_declarator (vdeclarator
);
184 type_struct
.add_declaration (vdecl
);
187 generate_cparameters (m
, creturn_type
, in_gtypeinstance_creation_method
, cparam_map
, function
, vdeclarator
);
189 bool visible
= !m
.is_internal_symbol ();
191 // generate *_real_* functions for virtual methods
192 // also generate them for abstract methods of classes to prevent faulty subclassing
193 if (!m
.is_abstract
|| (m
.is_abstract
&& current_type_symbol is Class
)) {
194 if (visible
&& m
.base_method
== null && m
.base_interface_method
== null) {
195 /* public methods need function declaration in
196 * header file except virtual/overridden methods */
197 header_type_member_declaration
.append (function
.copy ());
199 /* declare all other functions in source file to
200 * avoid dependency on order within source file */
201 function
.modifiers
|= CCodeModifiers
.STATIC
;
202 source_type_member_declaration
.append (function
.copy ());
205 /* Methods imported from a plain C file don't
206 * have a body, e.g. Vala.Parser.parse_file () */
207 if (m
.body
!= null) {
208 function
.block
= (CCodeBlock
) m
.body
.ccodenode
;
209 function
.block
.line
= function
.line
;
211 var cinit
= new
CCodeFragment ();
212 function
.block
.prepend_statement (cinit
);
215 var co_function
= new
CCodeFunction (m
.get_real_cname () + "_co", "gboolean");
217 // data struct to hold parameters, local variables, and the return value
218 co_function
.add_parameter (new
CCodeFormalParameter ("data", Symbol
.lower_case_to_camel_case (m
.get_cname ()) + "Data*"));
220 co_function
.modifiers
|= CCodeModifiers
.STATIC
;
221 source_type_member_declaration
.append (co_function
.copy ());
223 var cswitch
= new
CCodeSwitchStatement (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "state"));
225 // initial coroutine state
226 cswitch
.add_statement (new
CCodeCaseStatement (new
CCodeConstant ("0")));
229 cswitch
.add_statement (function
.block
);
231 // complete async call by invoking callback
232 var object_creation
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_newv"));
233 object_creation
.add_argument (new
CCodeConstant ("G_TYPE_OBJECT"));
234 object_creation
.add_argument (new
CCodeConstant ("0"));
235 object_creation
.add_argument (new
CCodeConstant ("NULL"));
237 var async_result_creation
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_simple_async_result_new"));
238 async_result_creation
.add_argument (object_creation
);
239 async_result_creation
.add_argument (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "callback"));
240 async_result_creation
.add_argument (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "user_data"));
241 async_result_creation
.add_argument (new
CCodeIdentifier ("data"));
243 var completecall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_simple_async_result_complete"));
244 completecall
.add_argument (async_result_creation
);
245 cswitch
.add_statement (new
CCodeExpressionStatement (completecall
));
247 cswitch
.add_statement (new
CCodeReturnStatement (new
CCodeConstant ("FALSE")));
249 co_function
.block
= new
CCodeBlock ();
250 co_function
.block
.add_statement (cswitch
);
252 source_type_member_definition
.append (co_function
);
255 if (m
.parent_symbol is Class
) {
256 var cl
= (Class
) m
.parent_symbol
;
257 if (m
.overrides
|| (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
)) {
259 ReferenceType base_expression_type
;
261 base_method
= m
.base_method
;
262 base_expression_type
= new
ObjectType ((Class
) base_method
.parent_symbol
);
264 base_method
= m
.base_interface_method
;
265 base_expression_type
= new
ObjectType ((Interface
) base_method
.parent_symbol
);
267 var self_target_type
= new
ObjectType (cl
);
268 CCodeExpression cself
= transform_expression (new
CCodeIdentifier ("base"), base_expression_type
, self_target_type
);
270 var cdecl
= new
CCodeDeclaration ("%s *".printf (cl
.get_cname ()));
271 cdecl
.add_declarator (new
CCodeVariableDeclarator ("self", cself
));
273 cinit
.append (cdecl
);
274 } else if (m
.binding
== MemberBinding
.INSTANCE
275 && !(m is CreationMethod
)) {
276 var ccheckstmt
= create_method_type_check_statement (m
, creturn_type
, cl
, true, "self");
277 if (ccheckstmt
!= null) {
278 ccheckstmt
.line
= function
.line
;
279 cinit
.append (ccheckstmt
);
283 foreach (FormalParameter param
in m
.get_parameters ()) {
284 if (param
.ellipsis
) {
288 var t
= param
.parameter_type
.data_type
;
289 if (t
!= null && t
.is_reference_type ()) {
290 if (param
.direction
!= ParameterDirection
.OUT
) {
291 var type_check
= create_method_type_check_statement (m
, creturn_type
, t
, (context
.non_null
&& !param
.parameter_type
.nullable
), param
.name
);
292 if (type_check
!= null) {
293 type_check
.line
= function
.line
;
294 cinit
.append (type_check
);
297 // ensure that the passed reference for output parameter is cleared
298 var a
= new
CCodeAssignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier (param
.name
)), new
CCodeConstant ("NULL"));
299 cinit
.append (new
CCodeExpressionStatement (a
));
305 /* always separate error parameter and inner_error local variable
306 * as error may be set to NULL but we're always interested in inner errors
309 closure_struct
.add_field ("GError *", "inner_error");
311 // no initialization necessary, closure struct is zeroed
313 var cdecl
= new
CCodeDeclaration ("GError *");
314 cdecl
.add_declarator (new
CCodeVariableDeclarator ("inner_error", new
CCodeConstant ("NULL")));
315 cinit
.append (cdecl
);
320 if (m
.source_reference
!= null && m
.source_reference
.comment
!= null) {
321 source_type_member_definition
.append (new
CCodeComment (m
.source_reference
.comment
));
323 source_type_member_definition
.append (function
);
326 if (m is CreationMethod
) {
327 if (in_gobject_creation_method
) {
328 int n_params
= ((CreationMethod
) m
).n_construction_params
;
330 if (n_params
> 0 || current_class
.get_type_parameters ().size
> 0) {
331 // declare construction parameter array
332 var cparamsinit
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
333 cparamsinit
.add_argument (new
CCodeIdentifier ("GParameter"));
334 cparamsinit
.add_argument (new
CCodeConstant ((n_params
+ 3 * current_class
.get_type_parameters ().size
).to_string ()));
336 var cdecl
= new
CCodeDeclaration ("GParameter *");
337 cdecl
.add_declarator (new
CCodeVariableDeclarator ("__params", cparamsinit
));
338 cinit
.append (cdecl
);
340 cdecl
= new
CCodeDeclaration ("GParameter *");
341 cdecl
.add_declarator (new
CCodeVariableDeclarator ("__params_it", new
CCodeIdentifier ("__params")));
342 cinit
.append (cdecl
);
345 /* type, dup func, and destroy func properties for generic types */
346 foreach (TypeParameter type_param
in current_class
.get_type_parameters ()) {
347 CCodeConstant prop_name
;
348 CCodeIdentifier param_name
;
350 prop_name
= new
CCodeConstant ("\"%s-type\"".printf (type_param
.name
.down ()));
351 param_name
= new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ()));
352 cinit
.append (new
CCodeExpressionStatement (get_construct_property_assignment (prop_name
, new
IntegerType ((Struct
) gtype_type
), param_name
)));
354 prop_name
= new
CCodeConstant ("\"%s-dup-func\"".printf (type_param
.name
.down ()));
355 param_name
= new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ()));
356 cinit
.append (new
CCodeExpressionStatement (get_construct_property_assignment (prop_name
, new
PointerType (new
VoidType ()), param_name
)));
358 prop_name
= new
CCodeConstant ("\"%s-destroy-func\"".printf (type_param
.name
.down ()));
359 param_name
= new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ()));
360 cinit
.append (new
CCodeExpressionStatement (get_construct_property_assignment (prop_name
, new
PointerType (new
VoidType ()), param_name
)));
362 } else if (in_gtypeinstance_creation_method
) {
363 var cl
= (Class
) m
.parent_symbol
;
364 var cdeclaration
= new
CCodeDeclaration (cl
.get_cname () + "*");
365 var cdecl
= new
CCodeVariableDeclarator ("self");
366 cdeclaration
.add_declarator (cdecl
);
367 cinit
.append (cdeclaration
);
369 if (!((CreationMethod
) m
).chain_up
) {
370 // TODO implicitly chain up to base class as in add_object_creation
371 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_type_create_instance"));
372 ccall
.add_argument (new
CCodeIdentifier ("object_type"));
373 cdecl
.initializer
= new
CCodeCastExpression (ccall
, cl
.get_cname () + "*");
376 /* type, dup func, and destroy func fields for generic types */
377 foreach (TypeParameter type_param
in current_class
.get_type_parameters ()) {
378 CCodeIdentifier param_name
;
379 CCodeAssignment assign
;
381 var priv_access
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv");
383 param_name
= new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ()));
384 assign
= new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
);
385 cinit
.append (new
CCodeExpressionStatement (assign
));
387 param_name
= new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ()));
388 assign
= new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
);
389 cinit
.append (new
CCodeExpressionStatement (assign
));
391 param_name
= new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ()));
392 assign
= new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
);
393 cinit
.append (new
CCodeExpressionStatement (assign
));
395 } else if (current_type_symbol is Class
) {
396 var cl
= (Class
) m
.parent_symbol
;
397 var cdecl
= new
CCodeDeclaration (cl
.get_cname () + "*");
398 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_new0"));
399 ccall
.add_argument (new
CCodeIdentifier (cl
.get_cname ()));
400 cdecl
.add_declarator (new
CCodeVariableDeclarator ("self", ccall
));
401 cinit
.append (cdecl
);
403 var cinitcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_instance_init".printf (cl
.get_lower_case_cname (null))));
404 cinitcall
.add_argument (new
CCodeIdentifier ("self"));
405 cinit
.append (new
CCodeExpressionStatement (cinitcall
));
407 var st
= (Struct
) m
.parent_symbol
;
409 // memset needs string.h
410 string_h_needed
= true;
411 var czero
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
412 czero
.add_argument (new
CCodeIdentifier ("self"));
413 czero
.add_argument (new
CCodeConstant ("0"));
414 czero
.add_argument (new
CCodeIdentifier ("sizeof (%s)".printf (st
.get_cname ())));
415 cinit
.append (new
CCodeExpressionStatement (czero
));
419 if (context
.module_init_method
== m
&& in_plugin
) {
420 // GTypeModule-based plug-in, register types
421 cinit
.append (module_init_fragment
);
424 foreach (Expression precondition
in m
.get_preconditions ()) {
425 var check_stmt
= create_precondition_statement (m
, creturn_type
, precondition
);
426 if (check_stmt
!= null) {
427 cinit
.append (check_stmt
);
430 } else if (m
.is_abstract
) {
431 // generate helpful error message if a sublcass does not implement an abstract method.
432 // This is only meaningful for subclasses implemented in C since the vala compiler would
433 // complain during compile time of such en error.
435 var cblock
= new
CCodeBlock ();
437 // add a typecheck statement for "self"
438 var check_stmt
= create_method_type_check_statement (m
, creturn_type
, current_type_symbol
, true, "self");
439 if (check_stmt
!= null) {
440 cblock
.add_statement (check_stmt
);
443 // add critical warning that this method should not have been called
444 var type_from_instance_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_TYPE_FROM_INSTANCE"));
445 type_from_instance_call
.add_argument (new
CCodeIdentifier ("self"));
447 var type_name_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_type_name"));
448 type_name_call
.add_argument (type_from_instance_call
);
450 var error_string
= "\"Type `%%s' does not implement abstract method `%s'\"".printf (m
.get_cname ());
452 var cerrorcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_critical"));
453 cerrorcall
.add_argument (new
CCodeConstant (error_string
));
454 cerrorcall
.add_argument (type_name_call
);
456 cblock
.add_statement (new
CCodeExpressionStatement (cerrorcall
));
458 // add return statement
459 cblock
.add_statement (new
CCodeReturnStatement (default_value_for_type (creturn_type
, false)));
461 function
.block
= cblock
;
462 source_type_member_definition
.append (function
);
466 if (m
.is_abstract
|| m
.is_virtual
) {
467 cparam_map
= new HashMap
<int,CCodeFormalParameter
> (direct_hash
, direct_equal
);
468 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
470 generate_vfunc (m
, creturn_type
, cparam_map
, carg_map
);
474 // m is possible entry point, add appropriate startup code
475 var cmain
= new
CCodeFunction ("main", "int");
476 cmain
.line
= function
.line
;
477 cmain
.add_parameter (new
CCodeFormalParameter ("argc", "int"));
478 cmain
.add_parameter (new
CCodeFormalParameter ("argv", "char **"));
479 var main_block
= new
CCodeBlock ();
481 if (context
.thread
) {
482 var thread_init_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_thread_init"));
483 thread_init_call
.line
= cmain
.line
;
484 thread_init_call
.add_argument (new
CCodeConstant ("NULL"));
485 main_block
.add_statement (new
CCodeExpressionStatement (thread_init_call
));
488 var type_init_call
= new
CCodeExpressionStatement (new
CCodeFunctionCall (new
CCodeIdentifier ("g_type_init")));
489 type_init_call
.line
= cmain
.line
;
490 main_block
.add_statement (type_init_call
);
492 var main_call
= new
CCodeFunctionCall (new
CCodeIdentifier (function
.name
));
493 if (m
.get_parameters ().size
== 1) {
494 main_call
.add_argument (new
CCodeIdentifier ("argv"));
495 main_call
.add_argument (new
CCodeIdentifier ("argc"));
497 if (m
.return_type is VoidType
) {
498 // method returns void, always use 0 as exit code
499 var main_stmt
= new
CCodeExpressionStatement (main_call
);
500 main_stmt
.line
= cmain
.line
;
501 main_block
.add_statement (main_stmt
);
502 var ret_stmt
= new
CCodeReturnStatement (new
CCodeConstant ("0"));
503 ret_stmt
.line
= cmain
.line
;
504 main_block
.add_statement (ret_stmt
);
506 var main_stmt
= new
CCodeReturnStatement (main_call
);
507 main_stmt
.line
= cmain
.line
;
508 main_block
.add_statement (main_stmt
);
510 cmain
.block
= main_block
;
511 source_type_member_definition
.append (cmain
);
515 public override void generate_cparameters (Method m
, DataType creturn_type
, bool in_gtypeinstance_creation_method
, Map
<int,CCodeFormalParameter
> cparam_map
, CCodeFunction func
, CCodeFunctionDeclarator? vdeclarator
= null, Map
<int,CCodeExpression
>? carg_map
= null, CCodeFunctionCall? vcall
= null, int direction
= 3) {
516 if (m
.parent_symbol is Class
&& m is CreationMethod
) {
517 var cl
= (Class
) m
.parent_symbol
;
518 if (!cl
.is_compact
&& vcall
== null) {
519 cparam_map
.set (get_param_pos (m
.cinstance_parameter_position
), new
CCodeFormalParameter ("object_type", "GType"));
521 } else if (m
.binding
== MemberBinding
.INSTANCE
|| (m
.parent_symbol is Struct
&& m is CreationMethod
)) {
522 TypeSymbol parent_type
= find_parent_type (m
);
524 if (parent_type is Class
) {
525 this_type
= new
ObjectType ((Class
) parent_type
);
526 } else if (parent_type is Interface
) {
527 this_type
= new
ObjectType ((Interface
) parent_type
);
528 } else if (parent_type is Struct
) {
529 this_type
= new
StructValueType ((Struct
) parent_type
);
530 } else if (parent_type is Enum
) {
531 this_type
= new
EnumValueType ((Enum
) parent_type
);
533 assert_not_reached ();
536 CCodeFormalParameter instance_param
= null;
537 if (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
) {
538 var base_type
= new
ObjectType ((Interface
) m
.base_interface_method
.parent_symbol
);
539 instance_param
= new
CCodeFormalParameter ("base", base_type
.get_cname ());
540 } else if (m
.overrides
) {
541 var base_type
= new
ObjectType ((Class
) m
.base_method
.parent_symbol
);
542 instance_param
= new
CCodeFormalParameter ("base", base_type
.get_cname ());
544 if (m
.parent_symbol is Struct
&& !((Struct
) m
.parent_symbol
).is_simple_type ()) {
545 instance_param
= new
CCodeFormalParameter ("*self", this_type
.get_cname ());
547 instance_param
= new
CCodeFormalParameter ("self", this_type
.get_cname ());
550 cparam_map
.set (get_param_pos (m
.cinstance_parameter_position
), instance_param
);
551 } else if (m
.binding
== MemberBinding
.CLASS
) {
552 TypeSymbol parent_type
= find_parent_type (m
);
554 this_type
= new
ClassType ((Class
) parent_type
);
555 var class_param
= new
CCodeFormalParameter ("klass", this_type
.get_cname ());
556 cparam_map
.set (get_param_pos (m
.cinstance_parameter_position
), class_param
);
559 if (in_gtypeinstance_creation_method
) {
560 // memory management for generic types
561 int type_param_index
= 0;
562 foreach (TypeParameter type_param
in current_class
.get_type_parameters ()) {
563 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeFormalParameter ("%s_type".printf (type_param
.name
.down ()), "GType"));
564 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeFormalParameter ("%s_dup_func".printf (type_param
.name
.down ()), "GBoxedCopyFunc"));
565 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeFormalParameter ("%s_destroy_func".printf (type_param
.name
.down ()), "GDestroyNotify"));
566 if (carg_map
!= null) {
567 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ())));
568 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ())));
569 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ())));
575 foreach (FormalParameter param
in m
.get_parameters ()) {
576 if (param
.direction
!= ParameterDirection
.OUT
) {
577 if ((direction
& 1) == 0) {
582 if ((direction
& 2) == 0) {
588 if (!param
.no_array_length
&& param
.parameter_type is ArrayType
) {
589 var array_type
= (ArrayType
) param
.parameter_type
;
591 var length_ctype
= "int";
592 if (param
.direction
!= ParameterDirection
.IN
) {
593 length_ctype
= "int*";
596 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
597 var cparam
= new
CCodeFormalParameter (head
.get_array_length_cname (param
.name
, dim
), length_ctype
);
598 cparam_map
.set (get_param_pos (param
.carray_length_parameter_position
+ 0.01 * dim
), cparam
);
599 if (carg_map
!= null) {
600 carg_map
.set (get_param_pos (param
.carray_length_parameter_position
+ 0.01 * dim
), new
CCodeIdentifier (cparam
.name
));
605 cparam_map
.set (get_param_pos (param
.cparameter_position
), (CCodeFormalParameter
) param
.ccodenode
);
606 if (carg_map
!= null) {
607 carg_map
.set (get_param_pos (param
.cparameter_position
), new
CCodeIdentifier (param
.name
));
610 if (param
.parameter_type is DelegateType
) {
611 var deleg_type
= (DelegateType
) param
.parameter_type
;
612 var d
= deleg_type
.delegate_symbol
;
614 var cparam
= new
CCodeFormalParameter (get_delegate_target_cname (param
.name
), "void*");
615 cparam_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
), cparam
);
616 if (carg_map
!= null) {
617 carg_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
), new
CCodeIdentifier (cparam
.name
));
619 if (deleg_type
.value_owned
) {
620 cparam
= new
CCodeFormalParameter (get_delegate_target_destroy_notify_cname (param
.name
), "GDestroyNotify");
621 cparam_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
+ 0.01), cparam
);
622 if (carg_map
!= null) {
623 carg_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
+ 0.01), new
CCodeIdentifier (cparam
.name
));
627 } else if (param
.parameter_type is MethodType
) {
628 var cparam
= new
CCodeFormalParameter (get_delegate_target_cname (param
.name
), "void*");
629 cparam_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
), cparam
);
630 if (carg_map
!= null) {
631 carg_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
), new
CCodeIdentifier (cparam
.name
));
636 if ((direction
& 2) != 0) {
637 if (!m
.no_array_length
&& creturn_type is ArrayType
) {
638 // return array length if appropriate
639 var array_type
= (ArrayType
) creturn_type
;
641 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
642 var cparam
= new
CCodeFormalParameter (head
.get_array_length_cname ("result", dim
), "int*");
643 cparam_map
.set (get_param_pos (m
.carray_length_parameter_position
+ 0.01 * dim
), cparam
);
644 if (carg_map
!= null) {
645 carg_map
.set (get_param_pos (m
.carray_length_parameter_position
+ 0.01 * dim
), new
CCodeIdentifier (cparam
.name
));
648 } else if (creturn_type is DelegateType
) {
649 // return delegate target if appropriate
650 var deleg_type
= (DelegateType
) creturn_type
;
651 var d
= deleg_type
.delegate_symbol
;
653 var cparam
= new
CCodeFormalParameter (get_delegate_target_cname ("result"), "void*");
654 cparam_map
.set (get_param_pos (m
.cdelegate_target_parameter_position
), cparam
);
655 if (carg_map
!= null) {
656 carg_map
.set (get_param_pos (m
.cdelegate_target_parameter_position
), new
CCodeIdentifier (cparam
.name
));
661 if (m
.get_error_types ().size
> 0) {
662 var cparam
= new
CCodeFormalParameter ("error", "GError**");
663 cparam_map
.set (get_param_pos (-1), cparam
);
664 if (carg_map
!= null) {
665 carg_map
.set (get_param_pos (-1), new
CCodeIdentifier (cparam
.name
));
670 // append C parameters in the right order
675 foreach (int pos
in cparam_map
.get_keys ()) {
676 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
683 func
.add_parameter (cparam_map
.get (min_pos
));
684 if (vdeclarator
!= null) {
685 vdeclarator
.add_parameter (cparam_map
.get (min_pos
));
688 vcall
.add_argument (carg_map
.get (min_pos
));
694 public void generate_vfunc (Method m
, DataType return_type
, Map
<int,CCodeFormalParameter
> cparam_map
, Map
<int,CCodeExpression
> carg_map
, string suffix
= "", int direction
= 3) {
695 bool visible
= !m
.is_internal_symbol ();
697 var vfunc
= new
CCodeFunction (m
.get_cname () + suffix
, return_type
.get_cname ());
698 vfunc
.line
= function
.line
;
700 var vblock
= new
CCodeBlock ();
702 foreach (Expression precondition
in m
.get_preconditions ()) {
703 var check_stmt
= create_precondition_statement (m
, return_type
, precondition
);
704 if (check_stmt
!= null) {
705 vblock
.add_statement (check_stmt
);
709 CCodeFunctionCall vcast
= null;
710 if (m
.parent_symbol is Interface
) {
711 var iface
= (Interface
) m
.parent_symbol
;
713 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_INTERFACE".printf (iface
.get_upper_case_cname (null))));
715 var cl
= (Class
) m
.parent_symbol
;
717 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS".printf (cl
.get_upper_case_cname (null))));
719 vcast
.add_argument (new
CCodeIdentifier ("self"));
721 var vcall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, m
.vfunc_name
+ suffix
));
722 carg_map
.set (get_param_pos (m
.cinstance_parameter_position
), new
CCodeIdentifier ("self"));
724 generate_cparameters (m
, return_type
, false, cparam_map
, vfunc
, null, carg_map
, vcall
, direction
);
726 CCodeStatement cstmt
;
727 if (return_type is VoidType
) {
728 cstmt
= new
CCodeExpressionStatement (vcall
);
729 } else if (m
.get_postconditions ().size
== 0) {
730 /* pass method return value */
731 cstmt
= new
CCodeReturnStatement (vcall
);
733 /* store method return value for postconditions */
734 var cdecl
= new
CCodeDeclaration (get_creturn_type (m
, return_type
.get_cname ()));
735 cdecl
.add_declarator (new
CCodeVariableDeclarator ("result", vcall
));
738 cstmt
.line
= vfunc
.line
;
739 vblock
.add_statement (cstmt
);
741 if (m
.get_postconditions ().size
> 0) {
742 foreach (Expression postcondition
in m
.get_postconditions ()) {
743 vblock
.add_statement (create_postcondition_statement (postcondition
));
746 if (!(return_type is VoidType
)) {
747 var cret_stmt
= new
CCodeReturnStatement (new
CCodeIdentifier ("result"));
748 cret_stmt
.line
= vfunc
.line
;
749 vblock
.add_statement (cret_stmt
);
754 header_type_member_declaration
.append (vfunc
.copy ());
756 vfunc
.modifiers
|= CCodeModifiers
.STATIC
;
757 source_type_member_declaration
.append (vfunc
.copy ());
760 vfunc
.block
= vblock
;
762 if (m
.is_abstract
&& m
.source_reference
!= null && m
.source_reference
.comment
!= null) {
763 source_type_member_definition
.append (new
CCodeComment (m
.source_reference
.comment
));
765 source_type_member_definition
.append (vfunc
);
768 private CCodeStatement?
create_method_type_check_statement (Method m
, DataType return_type
, TypeSymbol t
, bool non_null
, string var_name
) {
772 return create_type_check_statement (m
, return_type
, t
, non_null
, var_name
);
776 private CCodeStatement?
create_precondition_statement (CodeNode method_node
, DataType ret_type
, Expression precondition
) {
777 var ccheck
= new
CCodeFunctionCall ();
779 ccheck
.add_argument ((CCodeExpression
) precondition
.ccodenode
);
781 if (ret_type is VoidType
) {
783 ccheck
.call
= new
CCodeIdentifier ("g_return_if_fail");
785 ccheck
.call
= new
CCodeIdentifier ("g_return_val_if_fail");
787 var cdefault
= default_value_for_type (ret_type
, false);
788 if (cdefault
!= null) {
789 ccheck
.add_argument (cdefault
);
795 return new
CCodeExpressionStatement (ccheck
);
798 private CCodeStatement
create_postcondition_statement (Expression postcondition
) {
799 var cassert
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_assert"));
801 cassert
.add_argument ((CCodeExpression
) postcondition
.ccodenode
);
803 return new
CCodeExpressionStatement (cassert
);
806 private TypeSymbol?
find_parent_type (Symbol sym
) {
807 while (sym
!= null) {
808 if (sym is TypeSymbol
) {
809 return (TypeSymbol
) sym
;
811 sym
= sym
.parent_symbol
;
816 private void add_object_creation (CCodeBlock b
, bool has_params
) {
817 var cl
= (Class
) current_type_symbol
;
819 bool chain_up
= false;
820 CreationMethod cm
= null;
821 if (cl
.base_class
!= null) {
822 cm
= cl
.base_class
.default_construction_method as CreationMethod
;
823 if (cm
!= null && cm
.get_parameters ().size
== 0
824 && cm
.has_construct_function
) {
831 if (!has_params
&& !chain_up
832 && cl
.base_class
!= gobject_type
) {
833 // possibly report warning or error about missing base call
836 var cdecl
= new
CCodeVariableDeclarator ("self");
838 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (cm
.get_real_cname ()));
839 ccall
.add_argument (new
CCodeIdentifier ("object_type"));
840 cdecl
.initializer
= new
CCodeCastExpression (ccall
, "%s*".printf (cl
.get_cname ()));
842 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_newv"));
843 ccall
.add_argument (new
CCodeIdentifier ("object_type"));
845 ccall
.add_argument (new
CCodeConstant ("__params_it - __params"));
846 ccall
.add_argument (new
CCodeConstant ("__params"));
848 ccall
.add_argument (new
CCodeConstant ("0"));
849 ccall
.add_argument (new
CCodeConstant ("NULL"));
851 cdecl
.initializer
= ccall
;
854 var cdeclaration
= new
CCodeDeclaration ("%s *".printf (cl
.get_cname ()));
855 cdeclaration
.add_declarator (cdecl
);
857 b
.add_statement (cdeclaration
);
860 public override void visit_creation_method (CreationMethod m
) {
861 bool visible
= !m
.is_internal_symbol ();
863 if (m
.body
!= null && current_type_symbol is Class
&& current_class
.is_subtype_of (gobject_type
)) {
865 foreach (Statement stmt
in m
.body
.get_statements ()) {
866 var expr_stmt
= stmt as ExpressionStatement
;
867 if (expr_stmt
!= null) {
868 Property prop
= expr_stmt
.assigned_property ();
869 if (prop
!= null && prop
.set_accessor
.construction
) {
874 m
.n_construction_params
= n_params
;
877 head
.visit_method (m
);
879 DataType creturn_type
;
880 if (current_type_symbol is Class
) {
881 creturn_type
= new
ObjectType (current_class
);
883 creturn_type
= new
VoidType ();
886 if (current_type_symbol is Class
&& !current_class
.is_compact
) {
887 var vfunc
= new
CCodeFunction (m
.get_cname (), creturn_type
.get_cname ());
888 vfunc
.line
= function
.line
;
890 var cparam_map
= new HashMap
<int,CCodeFormalParameter
> (direct_hash
, direct_equal
);
891 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
893 var vblock
= new
CCodeBlock ();
895 var vcall
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_real_cname ()));
896 vcall
.add_argument (new
CCodeIdentifier (current_class
.get_type_id ()));
898 generate_cparameters (m
, creturn_type
, true, cparam_map
, vfunc
, null, carg_map
, vcall
);
899 CCodeStatement cstmt
= new
CCodeReturnStatement (vcall
);
900 cstmt
.line
= vfunc
.line
;
901 vblock
.add_statement (cstmt
);
904 header_type_member_declaration
.append (vfunc
.copy ());
906 vfunc
.modifiers
|= CCodeModifiers
.STATIC
;
907 source_type_member_declaration
.append (vfunc
.copy ());
910 vfunc
.block
= vblock
;
912 source_type_member_definition
.append (vfunc
);
915 if (current_type_symbol is Class
&& current_class
.is_subtype_of (gobject_type
)
916 && (((CreationMethod
) m
).n_construction_params
> 0 || current_class
.get_type_parameters ().size
> 0)) {
917 var ccond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.GREATER_THAN
, new
CCodeIdentifier ("__params_it"), new
CCodeIdentifier ("__params"));
918 var cdofreeparam
= new
CCodeBlock ();
919 cdofreeparam
.add_statement (new
CCodeExpressionStatement (new
CCodeUnaryExpression (CCodeUnaryOperator
.PREFIX_DECREMENT
, new
CCodeIdentifier ("__params_it"))));
920 var cunsetcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_unset"));
921 cunsetcall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("__params_it"), "value")));
922 cdofreeparam
.add_statement (new
CCodeExpressionStatement (cunsetcall
));
923 function
.block
.add_statement (new
CCodeWhileStatement (ccond
, cdofreeparam
));
925 var cfreeparams
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_free"));
926 cfreeparams
.add_argument (new
CCodeIdentifier ("__params"));
927 function
.block
.add_statement (new
CCodeExpressionStatement (cfreeparams
));
930 if (current_type_symbol is Class
) {
931 CCodeExpression cresult
= new
CCodeIdentifier ("self");
932 if (get_custom_creturn_type (m
) != null) {
933 cresult
= new
CCodeCastExpression (cresult
, get_custom_creturn_type (m
));
936 var creturn
= new
CCodeReturnStatement ();
937 creturn
.return_expression
= cresult
;
938 function
.block
.add_statement (creturn
);