1 /* valaccodemethodmodule.vala
3 * Copyright (C) 2007-2010 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>
27 * The link between a method and generated code.
29 public abstract class Vala
.CCodeMethodModule
: CCodeStructModule
{
30 public override bool method_has_wrapper (Method method
) {
31 return (method
.get_attribute ("NoWrapper") == null);
34 public override string?
get_custom_creturn_type (Method m
) {
35 var attr
= m
.get_attribute ("CCode");
37 string type
= attr
.get_string ("type");
45 string get_creturn_type (Method m
, string default_value
) {
46 string type
= get_custom_creturn_type (m
);
53 bool is_gtypeinstance_creation_method (Method m
) {
56 var cl
= m
.parent_symbol as Class
;
57 if (m is CreationMethod
&& cl
!= null && !cl
.is_compact
) {
64 public virtual void generate_method_result_declaration (Method m
, CCodeFile decl_space
, CCodeFunction cfunc
, Map
<int,CCodeParameter
> cparam_map
, Map
<int,CCodeExpression
>? carg_map
) {
65 var creturn_type
= m
.return_type
;
66 if (m is CreationMethod
) {
67 var cl
= m
.parent_symbol as Class
;
69 // object creation methods return the new object in C
70 // in Vala they have no return type
71 creturn_type
= new
ObjectType (cl
);
73 } else if (m
.return_type
.is_real_non_null_struct_type ()) {
74 // structs are returned via out parameter
75 creturn_type
= new
VoidType ();
77 cfunc
.return_type
= get_creturn_type (m
, creturn_type
.get_cname ());
79 generate_type_declaration (m
.return_type
, decl_space
);
81 if (m
.return_type
.is_real_non_null_struct_type ()) {
82 // structs are returned via out parameter
83 var cparam
= new
CCodeParameter ("result", m
.return_type
.get_cname () + "*");
84 cparam_map
.set (get_param_pos (-3), cparam
);
85 if (carg_map
!= null) {
86 carg_map
.set (get_param_pos (-3), get_result_cexpression ());
88 } else if (!m
.no_array_length
&& m
.return_type is ArrayType
) {
89 // return array length if appropriate
90 var array_type
= (ArrayType
) m
.return_type
;
91 var array_length_type
= m
.array_length_type
!= null ? m
.array_length_type
: "int";
92 array_length_type
+= "*";
94 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
95 var cparam
= new
CCodeParameter (get_array_length_cname ("result", dim
), array_length_type
);
96 cparam_map
.set (get_param_pos (m
.carray_length_parameter_position
+ 0.01 * dim
), cparam
);
97 if (carg_map
!= null) {
98 carg_map
.set (get_param_pos (m
.carray_length_parameter_position
+ 0.01 * dim
), get_variable_cexpression (cparam
.name
));
101 } else if (m
.return_type is DelegateType
) {
102 // return delegate target if appropriate
103 var deleg_type
= (DelegateType
) m
.return_type
;
104 var d
= deleg_type
.delegate_symbol
;
106 var cparam
= new
CCodeParameter (get_delegate_target_cname ("result"), "void**");
107 cparam_map
.set (get_param_pos (m
.cdelegate_target_parameter_position
), cparam
);
108 if (carg_map
!= null) {
109 carg_map
.set (get_param_pos (m
.cdelegate_target_parameter_position
), get_variable_cexpression (cparam
.name
));
111 if (deleg_type
.value_owned
) {
112 cparam
= new
CCodeParameter (get_delegate_target_destroy_notify_cname ("result"), "GDestroyNotify*");
113 cparam_map
.set (get_param_pos (m
.cdelegate_target_parameter_position
+ 0.01), cparam
);
114 if (carg_map
!= null) {
115 carg_map
.set (get_param_pos (m
.cdelegate_target_parameter_position
+ 0.01), get_variable_cexpression (cparam
.name
));
121 if (m
.get_error_types ().size
> 0 || (m
.base_method
!= null && m
.base_method
.get_error_types ().size
> 0) || (m
.base_interface_method
!= null && m
.base_interface_method
.get_error_types ().size
> 0)) {
122 foreach (DataType error_type
in m
.get_error_types ()) {
123 generate_type_declaration (error_type
, decl_space
);
126 var cparam
= new
CCodeParameter ("error", "GError**");
127 cparam_map
.set (get_param_pos (-1), cparam
);
128 if (carg_map
!= null) {
129 carg_map
.set (get_param_pos (-1), new
CCodeIdentifier (cparam
.name
));
134 public void complete_async () {
135 var state
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "_state_");
136 var zero
= new
CCodeConstant ("0");
137 var state_is_zero
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, state
, zero
);
138 ccode
.open_if (state_is_zero
);
140 var async_result_expr
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "_async_result");
142 var idle_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_simple_async_result_complete_in_idle"));
143 idle_call
.add_argument (async_result_expr
);
144 ccode
.add_expression (idle_call
);
148 var direct_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_simple_async_result_complete"));
149 direct_call
.add_argument (async_result_expr
);
150 ccode
.add_expression (direct_call
);
154 var unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_unref"));
155 unref
.add_argument (async_result_expr
);
156 ccode
.add_expression (unref
);
158 ccode
.add_return (new
CCodeConstant ("FALSE"));
161 public override void generate_method_declaration (Method m
, CCodeFile decl_space
) {
162 if (m
.is_async_callback
) {
165 if (add_symbol_declaration (decl_space
, m
, m
.get_cname ())) {
169 var function
= new
CCodeFunction (m
.get_cname ());
171 if (m
.is_private_symbol () && !m
.external
) {
172 function
.modifiers
|= CCodeModifiers
.STATIC
;
174 function
.modifiers
|= CCodeModifiers
.INLINE
;
179 function
.modifiers
|= CCodeModifiers
.DEPRECATED
;
182 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
183 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
185 var cl
= m
.parent_symbol as Class
;
187 // do not generate _new functions for creation methods of abstract classes
188 if (!(m is CreationMethod
&& cl
!= null && cl
.is_abstract
)) {
189 generate_cparameters (m
, decl_space
, cparam_map
, function
, null, carg_map
, new
CCodeFunctionCall (new
CCodeIdentifier ("fake")));
191 decl_space
.add_function_declaration (function
);
194 if (m is CreationMethod
&& cl
!= null) {
195 // _construct function
196 function
= new
CCodeFunction (m
.get_real_cname ());
198 if (m
.is_private_symbol ()) {
199 function
.modifiers
|= CCodeModifiers
.STATIC
;
202 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
203 generate_cparameters (m
, decl_space
, cparam_map
, function
);
205 decl_space
.add_function_declaration (function
);
209 void register_plugin_types (Symbol sym
, Set
<Symbol
> registered_types
) {
210 var ns
= sym as Namespace
;
211 var cl
= sym as Class
;
212 var iface
= sym as Interface
;
214 foreach (var ns_ns
in ns
.get_namespaces ()) {
215 register_plugin_types (ns_ns
, registered_types
);
217 foreach (var ns_cl
in ns
.get_classes ()) {
218 register_plugin_types (ns_cl
, registered_types
);
220 foreach (var ns_iface
in ns
.get_interfaces ()) {
221 register_plugin_types (ns_iface
, registered_types
);
223 } else if (cl
!= null) {
224 register_plugin_type (cl
, registered_types
);
225 foreach (var cl_cl
in cl
.get_classes ()) {
226 register_plugin_types (cl_cl
, registered_types
);
228 } else if (iface
!= null) {
229 register_plugin_type (iface
, registered_types
);
230 foreach (var iface_cl
in iface
.get_classes ()) {
231 register_plugin_types (iface_cl
, registered_types
);
236 void register_plugin_type (ObjectTypeSymbol type_symbol
, Set
<Symbol
> registered_types
) {
237 if (type_symbol
.external_package
) {
241 if (!registered_types
.add (type_symbol
)) {
242 // already registered
246 var cl
= type_symbol as Class
;
252 // register base types first
253 foreach (var base_type
in cl
.get_base_types ()) {
254 register_plugin_type ((ObjectTypeSymbol
) base_type
.data_type
, registered_types
);
258 var register_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_register_type".printf (type_symbol
.get_lower_case_cname (null))));
259 register_call
.add_argument (new
CCodeIdentifier (module_init_param_name
));
260 ccode
.add_expression (register_call
);
263 public override void visit_method (Method m
) {
264 push_context (new
EmitContext (m
));
266 bool in_gobject_creation_method
= false;
267 bool in_fundamental_creation_method
= false;
269 check_type (m
.return_type
);
271 if (m is CreationMethod
) {
272 var cl
= current_type_symbol as Class
;
273 if (cl
!= null && !cl
.is_compact
) {
274 if (cl
.base_class
== null) {
275 in_fundamental_creation_method
= true;
276 } else if (gobject_type
!= null && cl
.is_subtype_of (gobject_type
)) {
277 in_gobject_creation_method
= true;
283 next_coroutine_state
= 1;
286 var creturn_type
= m
.return_type
;
287 if (m
.return_type
.is_real_non_null_struct_type ()) {
288 // structs are returned via out parameter
289 creturn_type
= new
VoidType ();
292 if (m
.binding
== MemberBinding
.CLASS
|| m
.binding
== MemberBinding
.STATIC
) {
293 in_static_or_class_context
= true;
297 foreach (Parameter param
in m
.get_parameters ()) {
301 // do not declare overriding methods and interface implementations
302 if (m
.is_abstract
|| m
.is_virtual
303 || (m
.base_method
== null && m
.base_interface_method
== null)) {
304 generate_method_declaration (m
, cfile
);
306 if (!m
.is_internal_symbol ()) {
307 generate_method_declaration (m
, header_file
);
309 if (!m
.is_private_symbol ()) {
310 generate_method_declaration (m
, internal_header_file
);
314 CCodeFunction function
;
315 function
= new
CCodeFunction (m
.get_real_cname ());
318 function
.modifiers
|= CCodeModifiers
.INLINE
;
321 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
323 generate_cparameters (m
, cfile
, cparam_map
, function
);
325 // generate *_real_* functions for virtual methods
326 // also generate them for abstract methods of classes to prevent faulty subclassing
327 if (!m
.is_abstract
|| (m
.is_abstract
&& current_type_symbol is Class
)) {
329 if (m
.base_method
!= null || m
.base_interface_method
!= null) {
330 // declare *_real_* function
331 function
.modifiers
|= CCodeModifiers
.STATIC
;
332 cfile
.add_function_declaration (function
);
333 } else if (m
.is_private_symbol ()) {
334 function
.modifiers
|= CCodeModifiers
.STATIC
;
337 if (m
.body
!= null) {
338 function
= new
CCodeFunction (m
.get_real_cname () + "_co", "gboolean");
340 // data struct to hold parameters, local variables, and the return value
341 function
.add_parameter (new
CCodeParameter ("data", Symbol
.lower_case_to_camel_case (m
.get_cname ()) + "Data*"));
343 function
.modifiers
|= CCodeModifiers
.STATIC
;
344 cfile
.add_function_declaration (function
);
349 if (m
.comment
!= null) {
350 cfile
.add_type_member_definition (new
CCodeComment (m
.comment
.content
));
353 push_function (function
);
355 // generate *_real_* functions for virtual methods
356 // also generate them for abstract methods of classes to prevent faulty subclassing
357 if (!m
.is_abstract
|| (m
.is_abstract
&& current_type_symbol is Class
)) {
358 if (m
.body
!= null) {
360 ccode
.open_switch (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "_state_"));
362 // initial coroutine state
363 ccode
.add_case (new
CCodeConstant ("0"));
364 ccode
.add_goto ("_state_0");
366 for (int state
= 1; state
<= m
.yield_count
; state
++) {
367 ccode
.add_case (new
CCodeConstant (state
.to_string ()));
368 ccode
.add_goto ("_state_%d".printf (state
));
372 // let gcc know that this can't happen
373 ccode
.add_default ();
374 ccode
.add_expression (new
CCodeFunctionCall (new
CCodeIdentifier ("g_assert_not_reached")));
379 ccode
.add_label ("_state_0");
383 // add variables for parent closure blocks
384 // as closures only have one parameter for the innermost closure block
385 var closure_block
= current_closure_block
;
386 int block_id
= get_block_id (closure_block
);
388 var parent_closure_block
= next_closure_block (closure_block
.parent_symbol
);
389 if (parent_closure_block
== null) {
392 int parent_block_id
= get_block_id (parent_closure_block
);
394 var parent_data
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_data%d_".printf (parent_block_id
));
395 ccode
.add_declaration ("Block%dData*".printf (parent_block_id
), new
CCodeVariableDeclarator ("_data%d_".printf (parent_block_id
)));
396 ccode
.add_assignment (new
CCodeIdentifier ("_data%d_".printf (parent_block_id
)), parent_data
);
398 closure_block
= parent_closure_block
;
399 block_id
= parent_block_id
;
402 // add self variable for closures
403 // as closures have block data parameter
404 if (m
.binding
== MemberBinding
.INSTANCE
) {
405 var cself
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "self");
406 ccode
.add_declaration ("%s *".printf (current_class
.get_cname ()), new
CCodeVariableDeclarator ("self"));
407 ccode
.add_assignment (new
CCodeIdentifier ("self"), cself
);
410 // allow capturing generic type parameters
411 foreach (var type_param
in m
.get_type_parameters ()) {
414 func_name
= "%s_type".printf (type_param
.name
.down ());
415 ccode
.add_declaration ("GType", new
CCodeVariableDeclarator (func_name
));
416 ccode
.add_assignment (new
CCodeIdentifier (func_name
), new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
));
418 func_name
= "%s_dup_func".printf (type_param
.name
.down ());
419 ccode
.add_declaration ("GBoxedCopyFunc", new
CCodeVariableDeclarator (func_name
));
420 ccode
.add_assignment (new
CCodeIdentifier (func_name
), new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
));
422 func_name
= "%s_destroy_func".printf (type_param
.name
.down ());
423 ccode
.add_declaration ("GDestroyNotify", new
CCodeVariableDeclarator (func_name
));
424 ccode
.add_assignment (new
CCodeIdentifier (func_name
), new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
));
426 } else if (m
.parent_symbol is Class
&& !m
.coroutine
) {
427 var cl
= (Class
) m
.parent_symbol
;
428 if (m
.overrides
|| (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
)) {
430 ReferenceType base_expression_type
;
432 base_method
= m
.base_method
;
433 base_expression_type
= new
ObjectType ((Class
) base_method
.parent_symbol
);
435 base_method
= m
.base_interface_method
;
436 base_expression_type
= new
ObjectType ((Interface
) base_method
.parent_symbol
);
438 var self_target_type
= new
ObjectType (cl
);
439 CCodeExpression cself
= transform_expression (new
CCodeIdentifier ("base"), base_expression_type
, self_target_type
);
441 ccode
.add_declaration ("%s *".printf (cl
.get_cname ()), new
CCodeVariableDeclarator ("self"));
442 ccode
.add_assignment (new
CCodeIdentifier ("self"), cself
);
443 } else if (m
.binding
== MemberBinding
.INSTANCE
444 && !(m is CreationMethod
)) {
445 create_method_type_check_statement (m
, creturn_type
, cl
, true, "self");
449 foreach (Parameter param
in m
.get_parameters ()) {
450 if (param
.ellipsis
) {
454 if (param
.direction
!= ParameterDirection
.OUT
) {
455 var t
= param
.variable_type
.data_type
;
456 if (t
!= null && t
.is_reference_type ()) {
457 create_method_type_check_statement (m
, creturn_type
, t
, !param
.variable_type
.nullable
, get_variable_cname (param
.name
));
459 } else if (!m
.coroutine
) {
460 // declare local variable for out parameter to allow assignment even when caller passes NULL
461 var vardecl
= new CCodeVariableDeclarator
.zero (get_variable_cname ("_" + param
.name
), default_value_for_type (param
.variable_type
, true));
462 ccode
.add_declaration (param
.variable_type
.get_cname (), vardecl
);
464 if (param
.variable_type is ArrayType
) {
465 // create variables to store array dimensions
466 var array_type
= (ArrayType
) param
.variable_type
;
468 if (!array_type
.fixed_length
) {
469 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
470 vardecl
= new CCodeVariableDeclarator
.zero (get_array_length_cname (get_variable_cname ("_" + param
.name
), dim
), new
CCodeConstant ("0"));
471 ccode
.add_declaration ("int", vardecl
);
474 } else if (param
.variable_type is DelegateType
) {
475 var deleg_type
= (DelegateType
) param
.variable_type
;
476 var d
= deleg_type
.delegate_symbol
;
478 // create variable to store delegate target
479 vardecl
= new CCodeVariableDeclarator
.zero (get_delegate_target_cname (get_variable_cname ("_" + param
.name
)), new
CCodeConstant ("NULL"));
480 ccode
.add_declaration ("void *", vardecl
);
482 if (deleg_type
.value_owned
) {
483 vardecl
= new CCodeVariableDeclarator
.zero (get_delegate_target_destroy_notify_cname (get_variable_cname ("_" + param
.name
)), new
CCodeConstant ("NULL"));
484 ccode
.add_declaration ("GDestroyNotify", vardecl
);
491 if (!(m
.return_type is VoidType
) && !m
.return_type
.is_real_non_null_struct_type () && !m
.coroutine
) {
492 var vardecl
= new
CCodeVariableDeclarator ("result", default_value_for_type (m
.return_type
, true));
493 vardecl
.init0
= true;
494 ccode
.add_declaration (m
.return_type
.get_cname (), vardecl
);
497 if (m is CreationMethod
) {
498 if (in_gobject_creation_method
) {
499 ccode
.add_declaration ("%s *".printf (((Class
) current_type_symbol
).get_cname ()), new CCodeVariableDeclarator
.zero ("self", new
CCodeConstant ("NULL")));
500 } else if (is_gtypeinstance_creation_method (m
)) {
501 var cl
= (Class
) m
.parent_symbol
;
502 ccode
.add_declaration (cl
.get_cname () + "*", new CCodeVariableDeclarator
.zero ("self", new
CCodeConstant ("NULL")));
504 if (cl
.is_fundamental ()) {
505 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_type_create_instance"));
506 ccall
.add_argument (new
CCodeIdentifier ("object_type"));
507 ccode
.add_assignment (new
CCodeIdentifier ("self"), new
CCodeCastExpression (ccall
, cl
.get_cname () + "*"));
509 /* type, dup func, and destroy func fields for generic types */
510 foreach (TypeParameter type_param
in current_class
.get_type_parameters ()) {
511 CCodeIdentifier param_name
;
512 CCodeAssignment assign
;
514 var priv_access
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv");
516 param_name
= new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ()));
517 assign
= new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
);
518 ccode
.add_expression (assign
);
520 param_name
= new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ()));
521 assign
= new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
);
522 ccode
.add_expression (assign
);
524 param_name
= new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ()));
525 assign
= new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
);
526 ccode
.add_expression (assign
);
529 } else if (current_type_symbol is Class
) {
530 var cl
= (Class
) m
.parent_symbol
;
531 ccode
.add_declaration (cl
.get_cname () + "*", new
CCodeVariableDeclarator ("self"));
533 if (!((CreationMethod
) m
).chain_up
) {
534 // TODO implicitly chain up to base class as in add_object_creation
535 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_new0"));
536 ccall
.add_argument (new
CCodeIdentifier (cl
.get_cname ()));
537 ccode
.add_assignment (new
CCodeIdentifier ("self"), ccall
);
540 if (cl
.base_class
== null) {
541 // derived compact classes do not have fields
542 var cinitcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_instance_init".printf (cl
.get_lower_case_cname (null))));
543 cinitcall
.add_argument (new
CCodeIdentifier ("self"));
544 ccode
.add_expression (cinitcall
);
547 var st
= (Struct
) m
.parent_symbol
;
549 // memset needs string.h
550 cfile
.add_include ("string.h");
551 var czero
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
552 czero
.add_argument (new
CCodeIdentifier ("self"));
553 czero
.add_argument (new
CCodeConstant ("0"));
554 czero
.add_argument (new
CCodeIdentifier ("sizeof (%s)".printf (st
.get_cname ())));
555 ccode
.add_expression (czero
);
559 if (context
.module_init_method
== m
&& in_plugin
) {
560 // GTypeModule-based plug-in, register types
561 register_plugin_types (context
.root
, new HashSet
<Symbol
> ());
564 foreach (Expression precondition
in m
.get_preconditions ()) {
565 create_precondition_statement (m
, creturn_type
, precondition
);
570 if (m
.body
!= null) {
574 // generate *_real_* functions for virtual methods
575 // also generate them for abstract methods of classes to prevent faulty subclassing
576 if (!m
.is_abstract
|| (m
.is_abstract
&& current_type_symbol is Class
)) {
577 /* Methods imported from a plain C file don't
578 * have a body, e.g. Vala.Parser.parse_file () */
579 if (m
.body
!= null) {
580 if (current_method_inner_error
) {
581 /* always separate error parameter and inner_error local variable
582 * as error may be set to NULL but we're always interested in inner errors
585 closure_struct
.add_field ("GError *", "_inner_error_");
587 // no initialization necessary, closure struct is zeroed
589 ccode
.add_declaration ("GError *", new CCodeVariableDeclarator
.zero ("_inner_error_", new
CCodeConstant ("NULL")));
598 if (!(m
.return_type is VoidType
) && !m
.return_type
.is_real_non_null_struct_type () && !m
.coroutine
) {
599 // add dummy return if exit block is known to be unreachable to silence C compiler
600 if (m
.return_block
!= null && m
.return_block
.get_predecessors ().size
== 0) {
601 ccode
.add_return (new
CCodeIdentifier ("result"));
605 if (m is CreationMethod
) {
606 if (current_type_symbol is Class
) {
607 creturn_type
= new
ObjectType (current_class
);
609 creturn_type
= new
VoidType ();
613 if (current_type_symbol is Class
&& gobject_type
!= null && current_class
.is_subtype_of (gobject_type
)
614 && current_class
.get_type_parameters ().size
> 0
615 && !((CreationMethod
) m
).chain_up
) {
616 var ccond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.GREATER_THAN
, new
CCodeIdentifier ("__params_it"), new
CCodeIdentifier ("__params"));
617 var cdofreeparam
= new
CCodeBlock ();
618 cdofreeparam
.add_statement (new
CCodeExpressionStatement (new
CCodeUnaryExpression (CCodeUnaryOperator
.PREFIX_DECREMENT
, new
CCodeIdentifier ("__params_it"))));
619 var cunsetcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_unset"));
620 cunsetcall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("__params_it"), "value")));
621 cdofreeparam
.add_statement (new
CCodeExpressionStatement (cunsetcall
));
622 ccode
.add_statement (new
CCodeWhileStatement (ccond
, cdofreeparam
));
624 var cfreeparams
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_free"));
625 cfreeparams
.add_argument (new
CCodeIdentifier ("__params"));
626 ccode
.add_expression (cfreeparams
);
629 if (current_type_symbol is Class
) {
630 CCodeExpression cresult
= new
CCodeIdentifier ("self");
631 if (get_custom_creturn_type (m
) != null) {
632 cresult
= new
CCodeCastExpression (cresult
, get_custom_creturn_type (m
));
635 ccode
.add_return (cresult
);
639 cfile
.add_function (ccode
);
643 if (m
.is_abstract
&& current_type_symbol is Class
) {
644 // generate helpful error message if a sublcass does not implement an abstract method.
645 // This is only meaningful for subclasses implemented in C since the vala compiler would
646 // complain during compile time of such en error.
648 // add a typecheck statement for "self"
649 create_method_type_check_statement (m
, creturn_type
, current_type_symbol
, true, "self");
651 // add critical warning that this method should not have been called
652 var type_from_instance_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_TYPE_FROM_INSTANCE"));
653 type_from_instance_call
.add_argument (new
CCodeIdentifier ("self"));
655 var type_name_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_type_name"));
656 type_name_call
.add_argument (type_from_instance_call
);
658 var error_string
= "\"Type `%%s' does not implement abstract method `%s'\"".printf (m
.get_cname ());
660 var cerrorcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_critical"));
661 cerrorcall
.add_argument (new
CCodeConstant (error_string
));
662 cerrorcall
.add_argument (type_name_call
);
664 ccode
.add_expression (cerrorcall
);
666 // add return statement
667 return_default_value (creturn_type
);
669 cfile
.add_function (ccode
);
673 in_static_or_class_context
= false;
677 if ((m
.is_abstract
|| m
.is_virtual
) && !m
.coroutine
&&
678 /* If the method is a signal handler, the declaration
679 * is not needed. -- the name should be reserved for the
681 m
.signal_reference
== null) {
683 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
684 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
686 generate_vfunc (m
, creturn_type
, cparam_map
, carg_map
);
690 // m is possible entry point, add appropriate startup code
691 var cmain
= new
CCodeFunction ("main", "int");
692 cmain
.line
= function
.line
;
693 cmain
.add_parameter (new
CCodeParameter ("argc", "int"));
694 cmain
.add_parameter (new
CCodeParameter ("argv", "char **"));
695 var main_block
= new
CCodeBlock ();
697 if (context
.profile
== Profile
.GOBJECT
) {
698 if (context
.mem_profiler
) {
699 var mem_profiler_init_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_mem_set_vtable"));
700 mem_profiler_init_call
.line
= cmain
.line
;
701 mem_profiler_init_call
.add_argument (new
CCodeConstant ("glib_mem_profiler_table"));
702 main_block
.add_statement (new
CCodeExpressionStatement (mem_profiler_init_call
));
705 if (context
.thread
) {
706 var thread_init_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_thread_init"));
707 thread_init_call
.line
= cmain
.line
;
708 thread_init_call
.add_argument (new
CCodeConstant ("NULL"));
709 main_block
.add_statement (new
CCodeExpressionStatement (thread_init_call
));
712 var type_init_call
= new
CCodeExpressionStatement (new
CCodeFunctionCall (new
CCodeIdentifier ("g_type_init")));
713 type_init_call
.line
= cmain
.line
;
714 main_block
.add_statement (type_init_call
);
717 var main_call
= new
CCodeFunctionCall (new
CCodeIdentifier (function
.name
));
718 if (m
.get_parameters ().size
== 1) {
719 main_call
.add_argument (new
CCodeIdentifier ("argv"));
720 main_call
.add_argument (new
CCodeIdentifier ("argc"));
722 if (m
.return_type is VoidType
) {
723 // method returns void, always use 0 as exit code
724 var main_stmt
= new
CCodeExpressionStatement (main_call
);
725 main_stmt
.line
= cmain
.line
;
726 main_block
.add_statement (main_stmt
);
727 var ret_stmt
= new
CCodeReturnStatement (new
CCodeConstant ("0"));
728 ret_stmt
.line
= cmain
.line
;
729 main_block
.add_statement (ret_stmt
);
731 var main_stmt
= new
CCodeReturnStatement (main_call
);
732 main_stmt
.line
= cmain
.line
;
733 main_block
.add_statement (main_stmt
);
735 cmain
.block
= main_block
;
736 cfile
.add_function (cmain
);
740 public virtual CCodeParameter
generate_parameter (Parameter param
, CCodeFile decl_space
, Map
<int,CCodeParameter
> cparam_map
, Map
<int,CCodeExpression
>? carg_map
) {
741 CCodeParameter cparam
;
742 if (!param
.ellipsis
) {
743 string ctypename
= param
.variable_type
.get_cname ();
745 generate_type_declaration (param
.variable_type
, decl_space
);
747 // pass non-simple structs always by reference
748 if (param
.variable_type
.data_type is Struct
) {
749 var st
= (Struct
) param
.variable_type
.data_type
;
750 if (!st
.is_simple_type () && param
.direction
== ParameterDirection
.IN
) {
751 if (st
.is_immutable
&& !param
.variable_type
.value_owned
) {
752 ctypename
= "const " + ctypename
;
755 if (!param
.variable_type
.nullable
) {
761 if (param
.direction
!= ParameterDirection
.IN
) {
765 cparam
= new
CCodeParameter (get_variable_cname (param
.name
), ctypename
);
767 cparam
= new CCodeParameter
.with_ellipsis ();
770 cparam_map
.set (get_param_pos (param
.cparameter_position
, param
.ellipsis
), cparam
);
771 if (carg_map
!= null && !param
.ellipsis
) {
772 carg_map
.set (get_param_pos (param
.cparameter_position
, param
.ellipsis
), get_variable_cexpression (param
.name
));
778 public override void generate_cparameters (Method m
, CCodeFile decl_space
, Map
<int,CCodeParameter
> cparam_map
, CCodeFunction func
, CCodeFunctionDeclarator? vdeclarator
= null, Map
<int,CCodeExpression
>? carg_map
= null, CCodeFunctionCall? vcall
= null, int direction
= 3) {
780 var closure_block
= current_closure_block
;
781 int block_id
= get_block_id (closure_block
);
782 var instance_param
= new
CCodeParameter ("_data%d_".printf (block_id
), "Block%dData*".printf (block_id
));
783 cparam_map
.set (get_param_pos (m
.cinstance_parameter_position
), instance_param
);
784 } else if (m
.parent_symbol is Class
&& m is CreationMethod
) {
785 var cl
= (Class
) m
.parent_symbol
;
786 if (!cl
.is_compact
&& vcall
== null) {
787 cparam_map
.set (get_param_pos (m
.cinstance_parameter_position
), new
CCodeParameter ("object_type", "GType"));
789 } else if (m
.binding
== MemberBinding
.INSTANCE
|| (m
.parent_symbol is Struct
&& m is CreationMethod
)) {
790 TypeSymbol parent_type
= find_parent_type (m
);
792 if (parent_type is Class
) {
793 this_type
= new
ObjectType ((Class
) parent_type
);
794 } else if (parent_type is Interface
) {
795 this_type
= new
ObjectType ((Interface
) parent_type
);
796 } else if (parent_type is Struct
) {
797 this_type
= new
StructValueType ((Struct
) parent_type
);
798 } else if (parent_type is Enum
) {
799 this_type
= new
EnumValueType ((Enum
) parent_type
);
801 assert_not_reached ();
804 generate_type_declaration (this_type
, decl_space
);
806 CCodeParameter instance_param
= null;
807 if (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
) {
808 var base_type
= new
ObjectType ((Interface
) m
.base_interface_method
.parent_symbol
);
809 instance_param
= new
CCodeParameter ("base", base_type
.get_cname ());
810 } else if (m
.overrides
) {
811 var base_type
= new
ObjectType ((Class
) m
.base_method
.parent_symbol
);
812 instance_param
= new
CCodeParameter ("base", base_type
.get_cname ());
814 if (m
.parent_symbol is Struct
&& !((Struct
) m
.parent_symbol
).is_simple_type ()) {
815 instance_param
= new
CCodeParameter ("*self", this_type
.get_cname ());
817 instance_param
= new
CCodeParameter ("self", this_type
.get_cname ());
820 cparam_map
.set (get_param_pos (m
.cinstance_parameter_position
), instance_param
);
821 } else if (m
.binding
== MemberBinding
.CLASS
) {
822 TypeSymbol parent_type
= find_parent_type (m
);
824 this_type
= new
ClassType ((Class
) parent_type
);
825 var class_param
= new
CCodeParameter ("klass", this_type
.get_cname ());
826 cparam_map
.set (get_param_pos (m
.cinstance_parameter_position
), class_param
);
829 if (is_gtypeinstance_creation_method (m
)) {
830 // memory management for generic types
831 int type_param_index
= 0;
832 var cl
= (Class
) m
.parent_symbol
;
833 foreach (TypeParameter type_param
in cl
.get_type_parameters ()) {
834 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeParameter ("%s_type".printf (type_param
.name
.down ()), "GType"));
835 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeParameter ("%s_dup_func".printf (type_param
.name
.down ()), "GBoxedCopyFunc"));
836 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeParameter ("%s_destroy_func".printf (type_param
.name
.down ()), "GDestroyNotify"));
837 if (carg_map
!= null) {
838 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ())));
839 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ())));
840 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ())));
844 } else if (!m
.closure
) {
845 int type_param_index
= 0;
846 foreach (var type_param
in m
.get_type_parameters ()) {
847 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeParameter ("%s_type".printf (type_param
.name
.down ()), "GType"));
848 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeParameter ("%s_dup_func".printf (type_param
.name
.down ()), "GBoxedCopyFunc"));
849 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeParameter ("%s_destroy_func".printf (type_param
.name
.down ()), "GDestroyNotify"));
850 if (carg_map
!= null) {
851 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ())));
852 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ())));
853 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ())));
859 foreach (Parameter param
in m
.get_parameters ()) {
860 if (param
.direction
!= ParameterDirection
.OUT
) {
861 if ((direction
& 1) == 0) {
866 if ((direction
& 2) == 0) {
872 generate_parameter (param
, decl_space
, cparam_map
, carg_map
);
875 if ((direction
& 2) != 0) {
876 generate_method_result_declaration (m
, decl_space
, func
, cparam_map
, carg_map
);
879 // append C parameters in the right order
884 foreach (int pos
in cparam_map
.get_keys ()) {
885 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
892 func
.add_parameter (cparam_map
.get (min_pos
));
893 if (vdeclarator
!= null) {
894 vdeclarator
.add_parameter (cparam_map
.get (min_pos
));
897 var arg
= carg_map
.get (min_pos
);
899 vcall
.add_argument (arg
);
906 public void generate_vfunc (Method m
, DataType return_type
, Map
<int,CCodeParameter
> cparam_map
, Map
<int,CCodeExpression
> carg_map
, string suffix
= "", int direction
= 3) {
907 push_context (new
EmitContext ());
909 string cname
= m
.get_cname ();
910 if (suffix
== "_finish" && cname
.has_suffix ("_async")) {
911 cname
= cname
.substring (0, cname
.length
- "_async".length
);
913 var vfunc
= new
CCodeFunction (cname
+ suffix
);
915 CCodeFunctionCall vcast
= null;
916 if (m
.parent_symbol is Interface
) {
917 var iface
= (Interface
) m
.parent_symbol
;
919 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_INTERFACE".printf (iface
.get_upper_case_cname (null))));
921 var cl
= (Class
) m
.parent_symbol
;
923 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS".printf (cl
.get_upper_case_cname (null))));
925 vcast
.add_argument (new
CCodeIdentifier ("self"));
927 cname
= m
.vfunc_name
;
928 if (suffix
== "_finish" && cname
.has_suffix ("_async")) {
929 cname
= cname
.substring (0, cname
.length
- "_async".length
);
931 var vcall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, cname
+ suffix
));
932 carg_map
.set (get_param_pos (m
.cinstance_parameter_position
), new
CCodeIdentifier ("self"));
934 generate_cparameters (m
, cfile
, cparam_map
, vfunc
, null, carg_map
, vcall
, direction
);
936 push_function (vfunc
);
938 foreach (Expression precondition
in m
.get_preconditions ()) {
939 create_precondition_statement (m
, return_type
, precondition
);
942 if (return_type is VoidType
|| return_type
.is_real_non_null_struct_type ()) {
943 ccode
.add_expression (vcall
);
944 } else if (m
.get_postconditions ().size
== 0) {
945 /* pass method return value */
946 ccode
.add_return (vcall
);
948 /* store method return value for postconditions */
949 ccode
.add_declaration (get_creturn_type (m
, return_type
.get_cname ()), new
CCodeVariableDeclarator ("result"));
950 ccode
.add_assignment (new
CCodeIdentifier ("result"), vcall
);
953 if (m
.get_postconditions ().size
> 0) {
954 foreach (Expression postcondition
in m
.get_postconditions ()) {
955 create_postcondition_statement (postcondition
);
958 if (!(return_type is VoidType
)) {
959 ccode
.add_return (new
CCodeIdentifier ("result"));
963 cfile
.add_function (vfunc
);
968 private void create_method_type_check_statement (Method m
, DataType return_type
, TypeSymbol t
, bool non_null
, string var_name
) {
970 create_type_check_statement (m
, return_type
, t
, non_null
, var_name
);
974 private void create_precondition_statement (CodeNode method_node
, DataType ret_type
, Expression precondition
) {
975 var ccheck
= new
CCodeFunctionCall ();
977 precondition
.emit (this
);
979 ccheck
.add_argument (get_cvalue (precondition
));
981 if (method_node is CreationMethod
) {
982 ccheck
.call
= new
CCodeIdentifier ("g_return_val_if_fail");
983 ccheck
.add_argument (new
CCodeConstant ("NULL"));
984 } else if (method_node is Method
&& ((Method
) method_node
).coroutine
) {
986 ccheck
.call
= new
CCodeIdentifier ("g_return_val_if_fail");
987 ccheck
.add_argument (new
CCodeConstant ("FALSE"));
988 } else if (ret_type is VoidType
) {
990 ccheck
.call
= new
CCodeIdentifier ("g_return_if_fail");
992 ccheck
.call
= new
CCodeIdentifier ("g_return_val_if_fail");
994 var cdefault
= default_value_for_type (ret_type
, false);
995 if (cdefault
!= null) {
996 ccheck
.add_argument (cdefault
);
1002 ccode
.add_expression (ccheck
);
1005 private TypeSymbol?
find_parent_type (Symbol sym
) {
1006 while (sym
!= null) {
1007 if (sym is TypeSymbol
) {
1008 return (TypeSymbol
) sym
;
1010 sym
= sym
.parent_symbol
;
1015 public override void visit_creation_method (CreationMethod m
) {
1016 bool visible
= !m
.is_private_symbol ();
1020 if (m
.source_type
== SourceFileType
.FAST
) {
1024 // do not generate _new functions for creation methods of abstract classes
1025 if (current_type_symbol is Class
&& !current_class
.is_compact
&& !current_class
.is_abstract
) {
1026 var vfunc
= new
CCodeFunction (m
.get_cname ());
1028 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
1029 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
1031 var vblock
= new
CCodeBlock ();
1033 var vcall
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_real_cname ()));
1034 vcall
.add_argument (new
CCodeIdentifier (current_class
.get_type_id ()));
1036 generate_cparameters (m
, cfile
, cparam_map
, vfunc
, null, carg_map
, vcall
);
1037 CCodeStatement cstmt
= new
CCodeReturnStatement (vcall
);
1038 cstmt
.line
= vfunc
.line
;
1039 vblock
.add_statement (cstmt
);
1042 vfunc
.modifiers
|= CCodeModifiers
.STATIC
;
1045 vfunc
.block
= vblock
;
1047 cfile
.add_function (vfunc
);