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
{
31 private bool ellipses_to_valist
= false;
33 public override bool method_has_wrapper (Method method
) {
34 return (method
.get_attribute ("NoWrapper") == null);
37 string get_creturn_type (Method m
, string default_value
) {
38 string type
= get_ccode_type (m
);
45 bool is_gtypeinstance_creation_method (Method m
) {
48 var cl
= m
.parent_symbol as Class
;
49 if (m is CreationMethod
&& cl
!= null && !cl
.is_compact
) {
56 public virtual void generate_method_result_declaration (Method m
, CCodeFile decl_space
, CCodeFunction cfunc
, Map
<int,CCodeParameter
> cparam_map
, Map
<int,CCodeExpression
>? carg_map
) {
57 var creturn_type
= m
.return_type
;
58 if (m is CreationMethod
) {
59 var cl
= m
.parent_symbol as Class
;
61 // object creation methods return the new object in C
62 // in Vala they have no return type
63 creturn_type
= new
ObjectType (cl
);
65 } else if (m
.return_type
.is_real_non_null_struct_type ()) {
66 // structs are returned via out parameter
67 creturn_type
= new
VoidType ();
69 cfunc
.return_type
= get_creturn_type (m
, get_ccode_name (creturn_type
));
71 generate_type_declaration (m
.return_type
, decl_space
);
73 if (m
.return_type
.is_real_non_null_struct_type ()) {
74 // structs are returned via out parameter
75 var cparam
= new
CCodeParameter ("result", get_ccode_name (m
.return_type
) + "*");
76 cparam_map
.set (get_param_pos (-3), cparam
);
77 if (carg_map
!= null) {
78 carg_map
.set (get_param_pos (-3), get_result_cexpression ());
80 } else if (get_ccode_array_length (m
) && m
.return_type is ArrayType
) {
81 // return array length if appropriate
82 var array_type
= (ArrayType
) m
.return_type
;
83 var array_length_type
= get_ccode_array_length_type (m
) != null ?
get_ccode_array_length_type (m
) : "int";
84 array_length_type
+= "*";
86 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
87 var cparam
= new
CCodeParameter (get_array_length_cname ("result", dim
), array_length_type
);
88 cparam_map
.set (get_param_pos (get_ccode_array_length_pos (m
) + 0.01 * dim
), cparam
);
89 if (carg_map
!= null) {
90 carg_map
.set (get_param_pos (get_ccode_array_length_pos (m
) + 0.01 * dim
), get_variable_cexpression (cparam
.name
));
93 } else if (m
.return_type is DelegateType
) {
94 // return delegate target if appropriate
95 var deleg_type
= (DelegateType
) m
.return_type
;
96 if (deleg_type
.delegate_symbol
.has_target
) {
97 var cparam
= new
CCodeParameter (get_delegate_target_cname ("result"), "gpointer*");
98 cparam_map
.set (get_param_pos (get_ccode_delegate_target_pos (m
)), cparam
);
99 if (carg_map
!= null) {
100 carg_map
.set (get_param_pos (get_ccode_delegate_target_pos (m
)), get_variable_cexpression (cparam
.name
));
102 if (deleg_type
.is_disposable ()) {
103 cparam
= new
CCodeParameter (get_delegate_target_destroy_notify_cname ("result"), "GDestroyNotify*");
104 cparam_map
.set (get_param_pos (get_ccode_delegate_target_pos (m
) + 0.01), cparam
);
105 if (carg_map
!= null) {
106 carg_map
.set (get_param_pos (get_ccode_delegate_target_pos (m
) + 0.01), get_variable_cexpression (cparam
.name
));
112 if (m
.has_error_type_parameter ()) {
113 foreach (DataType error_type
in m
.get_error_types ()) {
114 generate_type_declaration (error_type
, decl_space
);
117 var cparam
= new
CCodeParameter ("error", "GError**");
118 cparam_map
.set (get_param_pos (-1), cparam
);
119 if (carg_map
!= null) {
120 carg_map
.set (get_param_pos (-1), new
CCodeIdentifier (cparam
.name
));
125 public void complete_async () {
126 var data_var
= new
CCodeIdentifier ("_data_");
127 var async_result_expr
= new CCodeMemberAccess
.pointer (data_var
, "_async_result");
129 var finish_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_task_return_pointer"));
130 finish_call
.add_argument (async_result_expr
);
131 finish_call
.add_argument (data_var
);
132 finish_call
.add_argument (new
CCodeConstant ("NULL"));
133 ccode
.add_expression (finish_call
);
135 // Preserve the "complete now" behavior if state != 0, do so by
136 // iterating the GTask's main context till the task is complete.
137 var state
= new CCodeMemberAccess
.pointer (data_var
, "_state_");
138 var zero
= new
CCodeConstant ("0");
139 var state_is_not_zero
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, state
, zero
);
140 ccode
.open_if (state_is_not_zero
);
142 CCodeBinaryExpression task_is_complete
;
144 if (context
.require_glib_version (2, 44)) {
145 var task_complete
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_task_get_completed"));
146 task_complete
.add_argument (async_result_expr
);
147 task_is_complete
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, task_complete
, new
CCodeConstant ("TRUE"));
149 var task_complete
= new CCodeMemberAccess
.pointer (data_var
, "_task_complete_");
150 task_is_complete
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, task_complete
, new
CCodeConstant ("TRUE"));
153 ccode
.open_while (task_is_complete
);
154 var task_context
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_task_get_context"));
155 task_context
.add_argument (async_result_expr
);
156 var iterate_context
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_main_context_iteration"));
157 iterate_context
.add_argument (task_context
);
158 iterate_context
.add_argument (new
CCodeConstant ("TRUE"));
159 ccode
.add_expression (iterate_context
);
164 var unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_unref"));
165 unref
.add_argument (async_result_expr
);
166 ccode
.add_expression (unref
);
168 ccode
.add_return (new
CCodeConstant ("FALSE"));
171 public override void generate_method_declaration (Method m
, CCodeFile decl_space
) {
172 if (m
.is_async_callback
) {
175 if (add_symbol_declaration (decl_space
, m
, get_ccode_name (m
))) {
179 var function
= new
CCodeFunction (get_ccode_name (m
));
181 if (m
.is_private_symbol () && !m
.external
) {
182 function
.modifiers
|= CCodeModifiers
.STATIC
;
184 function
.modifiers
|= CCodeModifiers
.INLINE
;
186 } else if (context
.hide_internal
&& m
.is_internal_symbol () && !m
.external
) {
187 function
.modifiers
|= CCodeModifiers
.INTERNAL
;
190 if (m
.version
.deprecated
) {
191 function
.modifiers
|= CCodeModifiers
.DEPRECATED
;
194 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
195 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
197 var cl
= m
.parent_symbol as Class
;
199 // do not generate _new functions for creation methods of abstract classes
200 if (!(m is CreationMethod
&& cl
!= null && cl
.is_abstract
)) {
201 bool etv_tmp
= ellipses_to_valist
;
202 ellipses_to_valist
= false;
203 generate_cparameters (m
, decl_space
, cparam_map
, function
, null, carg_map
, new
CCodeFunctionCall (new
CCodeIdentifier ("fake")));
204 ellipses_to_valist
= etv_tmp
;
206 decl_space
.add_function_declaration (function
);
209 if (is_gtypeinstance_creation_method (m
)) {
210 // _construct function
211 function
= new
CCodeFunction (get_ccode_real_name (m
));
213 if (m
.is_private_symbol ()) {
214 function
.modifiers
|= CCodeModifiers
.STATIC
;
215 } else if (context
.hide_internal
&& m
.is_internal_symbol ()) {
216 function
.modifiers
|= CCodeModifiers
.INTERNAL
;
219 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
220 bool etv_tmp
= ellipses_to_valist
;
221 ellipses_to_valist
= false;
222 generate_cparameters (m
, decl_space
, cparam_map
, function
);
223 ellipses_to_valist
= etv_tmp
;
225 decl_space
.add_function_declaration (function
);
227 if (m
.is_variadic ()) {
228 // _constructv function
229 function
= new
CCodeFunction (get_ccode_constructv_name ((CreationMethod
) m
));
231 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
232 generate_cparameters (m
, decl_space
, cparam_map
, function
);
234 decl_space
.add_function_declaration (function
);
239 void register_plugin_types (Symbol sym
, Set
<Symbol
> registered_types
) {
240 var ns
= sym as Namespace
;
241 var cl
= sym as Class
;
242 var iface
= sym as Interface
;
244 foreach (var ns_ns
in ns
.get_namespaces ()) {
245 register_plugin_types (ns_ns
, registered_types
);
247 foreach (var ns_cl
in ns
.get_classes ()) {
248 register_plugin_types (ns_cl
, registered_types
);
250 foreach (var ns_iface
in ns
.get_interfaces ()) {
251 register_plugin_types (ns_iface
, registered_types
);
253 } else if (cl
!= null) {
254 register_plugin_type (cl
, registered_types
);
255 foreach (var cl_cl
in cl
.get_classes ()) {
256 register_plugin_types (cl_cl
, registered_types
);
258 } else if (iface
!= null) {
259 register_plugin_type (iface
, registered_types
);
260 foreach (var iface_cl
in iface
.get_classes ()) {
261 register_plugin_types (iface_cl
, registered_types
);
266 void register_plugin_type (ObjectTypeSymbol type_symbol
, Set
<Symbol
> registered_types
) {
267 if (type_symbol
.external_package
) {
271 if (!registered_types
.add (type_symbol
)) {
272 // already registered
276 var cl
= type_symbol as Class
;
282 // register base types first
283 foreach (var base_type
in cl
.get_base_types ()) {
284 register_plugin_type ((ObjectTypeSymbol
) base_type
.data_type
, registered_types
);
288 // Add function prototypes for required register-type-calls which are likely external
289 var register_func
= new
CCodeFunction ("%s_register_type".printf (get_ccode_lower_case_name (type_symbol
, null)), "GType");
290 register_func
.add_parameter (new
CCodeParameter ("module", "GTypeModule *"));
291 register_func
.is_declaration
= true;
292 cfile
.add_function_declaration (register_func
);
294 var register_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_register_type".printf (get_ccode_lower_case_name (type_symbol
, null))));
295 register_call
.add_argument (new
CCodeIdentifier (module_init_param_name
));
296 ccode
.add_expression (register_call
);
298 var iface
= type_symbol as Interface
;
300 string? dbus_name
= GDBusModule
.get_dbus_name(type_symbol
);
302 if (dbus_name
!= null) {
303 string proxy_cname
= get_ccode_lower_case_prefix (type_symbol
) + "proxy";
304 var register_proxy
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_register_dynamic_type".printf (proxy_cname
)));
305 register_proxy
.add_argument (new
CCodeIdentifier (module_init_param_name
));
306 ccode
.add_expression (register_proxy
);
312 * This function generates the code the given method. If the method is
313 * a constructor, _construct is generated, unless it's variadic, in which
314 * case _constructv is generated (and _construct is generated together
315 * with _new in visit_creation_method).
317 public override void visit_method (Method m
) {
318 string real_name
= get_ccode_real_name (m
);
319 if (m is CreationMethod
&& m
.is_variadic ()) {
320 real_name
= get_ccode_constructv_name ((CreationMethod
) m
);
323 push_context (new
EmitContext (m
));
324 push_line (m
.source_reference
);
326 bool in_gobject_creation_method
= false;
327 bool in_fundamental_creation_method
= false;
329 check_type (m
.return_type
);
331 bool profile
= m
.get_attribute ("Profile") != null;
333 if (m is CreationMethod
) {
334 var cl
= current_type_symbol as Class
;
335 if (cl
!= null && !cl
.is_compact
) {
336 if (cl
.base_class
== null) {
337 in_fundamental_creation_method
= true;
338 } else if (gobject_type
!= null && cl
.is_subtype_of (gobject_type
)) {
339 in_gobject_creation_method
= true;
344 var creturn_type
= m
.return_type
;
345 if (m
.return_type
.is_real_non_null_struct_type ()) {
346 // structs are returned via out parameter
347 creturn_type
= new
VoidType ();
350 foreach (Parameter param
in m
.get_parameters ()) {
354 // do not declare overriding methods and interface implementations
355 if ((m
.is_abstract
|| m
.is_virtual
356 || (m
.base_method
== null && m
.base_interface_method
== null)) && m
.signal_reference
== null) {
357 generate_method_declaration (m
, cfile
);
359 if (!m
.is_internal_symbol ()) {
360 generate_method_declaration (m
, header_file
);
362 if (!m
.is_private_symbol ()) {
363 generate_method_declaration (m
, internal_header_file
);
368 string prefix
= "_vala_prof_%s".printf (real_name
);
370 cfile
.add_include ("stdio.h");
372 var counter
= new
CCodeIdentifier (prefix
+ "_counter");
373 var counter_decl
= new
CCodeDeclaration ("gint");
374 counter_decl
.add_declarator (new
CCodeVariableDeclarator (counter
.name
));
375 counter_decl
.modifiers
= CCodeModifiers
.STATIC
;
376 cfile
.add_type_member_declaration (counter_decl
);
378 // nesting level for recursive functions
379 var level
= new
CCodeIdentifier (prefix
+ "_level");
380 var level_decl
= new
CCodeDeclaration ("gint");
381 level_decl
.add_declarator (new
CCodeVariableDeclarator (level
.name
));
382 level_decl
.modifiers
= CCodeModifiers
.STATIC
;
383 cfile
.add_type_member_declaration (level_decl
);
385 var timer
= new
CCodeIdentifier (prefix
+ "_timer");
386 var timer_decl
= new
CCodeDeclaration ("GTimer *");
387 timer_decl
.add_declarator (new
CCodeVariableDeclarator (timer
.name
));
388 timer_decl
.modifiers
= CCodeModifiers
.STATIC
;
389 cfile
.add_type_member_declaration (timer_decl
);
391 var constructor
= new
CCodeFunction (prefix
+ "_init");
392 constructor
.modifiers
= CCodeModifiers
.STATIC
| CCodeModifiers
.CONSTRUCTOR
;
393 cfile
.add_function_declaration (constructor
);
394 push_function (constructor
);
396 ccode
.add_assignment (timer
, new
CCodeFunctionCall (new
CCodeIdentifier ("g_timer_new")));
398 var stop_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_timer_stop"));
399 stop_call
.add_argument (timer
);
400 ccode
.add_expression (stop_call
);
403 cfile
.add_function (constructor
);
406 var destructor
= new
CCodeFunction (prefix
+ "_exit");
407 destructor
.modifiers
= CCodeModifiers
.STATIC
| CCodeModifiers
.DESTRUCTOR
;
408 cfile
.add_function_declaration (destructor
);
409 push_function (destructor
);
411 var elapsed_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_timer_elapsed"));
412 elapsed_call
.add_argument (timer
);
413 elapsed_call
.add_argument (new
CCodeConstant ("NULL"));
415 var print_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("fprintf"));
416 print_call
.add_argument (new
CCodeIdentifier ("stderr"));
417 print_call
.add_argument (new
CCodeConstant ("\"%s: %%gs (%%d calls)\\n\"".printf (m
.get_full_name ())));
418 print_call
.add_argument (elapsed_call
);
419 print_call
.add_argument (counter
);
420 ccode
.add_expression (print_call
);
423 cfile
.add_function (destructor
);
426 CCodeFunction function
;
427 function
= new
CCodeFunction (real_name
);
430 function
.modifiers
|= CCodeModifiers
.INLINE
;
433 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
435 generate_cparameters (m
, cfile
, cparam_map
, function
);
437 // generate *_real_* functions for virtual methods
438 // also generate them for abstract methods of classes to prevent faulty subclassing
439 if (!m
.is_abstract
|| (m
.is_abstract
&& current_type_symbol is Class
)) {
441 if (m
.base_method
!= null || m
.base_interface_method
!= null) {
442 // declare *_real_* function
443 function
.modifiers
|= CCodeModifiers
.STATIC
;
444 cfile
.add_function_declaration (function
);
445 } else if (m
.is_private_symbol ()) {
446 function
.modifiers
|= CCodeModifiers
.STATIC
;
447 } else if (context
.hide_internal
&& m
.is_internal_symbol ()) {
448 function
.modifiers
|= CCodeModifiers
.INTERNAL
;
451 if (m
.body
!= null) {
452 function
= new
CCodeFunction (real_name
+ "_co", "gboolean");
454 // data struct to hold parameters, local variables, and the return value
455 function
.add_parameter (new
CCodeParameter ("_data_", Symbol
.lower_case_to_camel_case (get_ccode_const_name (m
)) + "Data*"));
456 function
.modifiers
|= CCodeModifiers
.STATIC
;
457 cfile
.add_function_declaration (function
);
462 if (m
.comment
!= null) {
463 cfile
.add_type_member_definition (new
CCodeComment (m
.comment
.content
));
466 push_function (function
);
468 unowned CCodeBlock? co_switch_block
= null;
470 // generate *_real_* functions for virtual methods
471 // also generate them for abstract methods of classes to prevent faulty subclassing
472 if (!m
.is_abstract
|| (m
.is_abstract
&& current_type_symbol is Class
)) {
473 if (m
.body
!= null) {
475 ccode
.open_switch (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), "_state_"));
477 // initial coroutine state
478 ccode
.add_case (new
CCodeConstant ("0"));
479 ccode
.add_goto ("_state_0");
481 co_switch_block
= ccode
.current_block
;
486 ccode
.add_label ("_state_0");
490 // add variables for parent closure blocks
491 // as closures only have one parameter for the innermost closure block
492 var closure_block
= current_closure_block
;
493 int block_id
= get_block_id (closure_block
);
495 var parent_closure_block
= next_closure_block (closure_block
.parent_symbol
);
496 if (parent_closure_block
== null) {
499 int parent_block_id
= get_block_id (parent_closure_block
);
501 var parent_data
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_data%d_".printf (parent_block_id
));
502 ccode
.add_declaration ("Block%dData*".printf (parent_block_id
), new
CCodeVariableDeclarator ("_data%d_".printf (parent_block_id
)));
503 ccode
.add_assignment (new
CCodeIdentifier ("_data%d_".printf (parent_block_id
)), parent_data
);
505 closure_block
= parent_closure_block
;
506 block_id
= parent_block_id
;
509 // add self variable for closures
510 // as closures have block data parameter
511 if (m
.binding
== MemberBinding
.INSTANCE
) {
512 var cself
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "self");
513 ccode
.add_declaration (get_ccode_name (get_data_type_for_symbol (current_type_symbol
)), new
CCodeVariableDeclarator ("self"));
514 ccode
.add_assignment (new
CCodeIdentifier ("self"), cself
);
517 // allow capturing generic type parameters
518 foreach (var type_param
in m
.get_type_parameters ()) {
521 func_name
= "%s_type".printf (type_param
.name
.down ());
522 ccode
.add_declaration ("GType", new
CCodeVariableDeclarator (func_name
));
523 ccode
.add_assignment (new
CCodeIdentifier (func_name
), new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
));
525 func_name
= "%s_dup_func".printf (type_param
.name
.down ());
526 ccode
.add_declaration ("GBoxedCopyFunc", new
CCodeVariableDeclarator (func_name
));
527 ccode
.add_assignment (new
CCodeIdentifier (func_name
), new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
));
529 func_name
= "%s_destroy_func".printf (type_param
.name
.down ());
530 ccode
.add_declaration ("GDestroyNotify", new
CCodeVariableDeclarator (func_name
));
531 ccode
.add_assignment (new
CCodeIdentifier (func_name
), new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
));
533 } else if (m
.parent_symbol is Class
&& !m
.coroutine
) {
534 var cl
= (Class
) m
.parent_symbol
;
535 if (m
.overrides
|| (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
)) {
537 ReferenceType base_expression_type
;
539 base_method
= m
.base_method
;
540 base_expression_type
= new
ObjectType ((Class
) base_method
.parent_symbol
);
542 base_method
= m
.base_interface_method
;
543 base_expression_type
= new
ObjectType ((Interface
) base_method
.parent_symbol
);
545 var self_target_type
= new
ObjectType (cl
);
546 CCodeExpression cself
= get_cvalue_ (transform_value (new
GLibValue (base_expression_type
, new
CCodeIdentifier ("base"), true), self_target_type
, m
));
548 ccode
.add_declaration ("%s *".printf (get_ccode_name (cl
)), new
CCodeVariableDeclarator ("self"));
549 ccode
.add_assignment (new
CCodeIdentifier ("self"), cself
);
550 } else if (m
.binding
== MemberBinding
.INSTANCE
551 && !(m is CreationMethod
)
552 && m
.base_method
== null && m
.base_interface_method
== null) {
553 create_method_type_check_statement (m
, creturn_type
, cl
, true, "self");
557 foreach (Parameter param
in m
.get_parameters ()) {
558 if (param
.ellipsis
) {
562 if (param
.direction
!= ParameterDirection
.OUT
) {
563 var t
= param
.variable_type
.data_type
;
564 if (t
!= null && (t
.is_reference_type () || param
.variable_type
.is_real_struct_type ())) {
565 var cname
= get_variable_cname (param
.name
);
566 if (param
.direction
== ParameterDirection
.REF
&& !param
.variable_type
.is_real_struct_type ()) {
569 create_method_type_check_statement (m
, creturn_type
, t
, !param
.variable_type
.nullable
, cname
);
571 } else if (!m
.coroutine
) {
572 // declare local variable for out parameter to allow assignment even when caller passes NULL
573 var vardecl
= new CCodeVariableDeclarator
.zero (get_variable_cname ("_vala_%s".printf (param
.name
)), default_value_for_type (param
.variable_type
, true));
574 ccode
.add_declaration (get_ccode_name (param
.variable_type
), vardecl
);
576 if (param
.variable_type is ArrayType
) {
577 // create variables to store array dimensions
578 var array_type
= (ArrayType
) param
.variable_type
;
580 if (!array_type
.fixed_length
) {
581 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
582 vardecl
= new CCodeVariableDeclarator
.zero (get_array_length_cname (get_variable_cname ("_vala_%s".printf (param
.name
)), dim
), new
CCodeConstant ("0"));
583 ccode
.add_declaration ("int", vardecl
);
586 } else if (param
.variable_type is DelegateType
) {
587 var deleg_type
= (DelegateType
) param
.variable_type
;
588 if (deleg_type
.delegate_symbol
.has_target
) {
589 // create variable to store delegate target
590 vardecl
= new CCodeVariableDeclarator
.zero ("_vala_%s".printf (get_ccode_delegate_target_name (param
)), new
CCodeConstant ("NULL"));
591 ccode
.add_declaration ("void *", vardecl
);
593 if (deleg_type
.is_disposable ()) {
594 vardecl
= new CCodeVariableDeclarator
.zero (get_delegate_target_destroy_notify_cname (get_variable_cname ("_vala_%s".printf (param
.name
))), new
CCodeConstant ("NULL"));
595 ccode
.add_declaration ("GDestroyNotify", vardecl
);
602 if (!(m
.return_type is VoidType
) && !m
.return_type
.is_real_non_null_struct_type () && !m
.coroutine
) {
603 var vardecl
= new
CCodeVariableDeclarator ("result", default_value_for_type (m
.return_type
, true));
604 vardecl
.init0
= true;
605 ccode
.add_declaration (get_ccode_name (m
.return_type
), vardecl
);
608 if (m is CreationMethod
) {
609 if (in_gobject_creation_method
) {
611 ccode
.add_declaration ("%s *".printf (get_ccode_name (current_type_symbol
)), new CCodeVariableDeclarator
.zero ("self", new
CCodeConstant ("NULL")));
613 } else if (is_gtypeinstance_creation_method (m
)) {
614 var cl
= (Class
) m
.parent_symbol
;
615 ccode
.add_declaration (get_ccode_name (cl
) + "*", new CCodeVariableDeclarator
.zero ("self", new
CCodeConstant ("NULL")));
617 if (cl
.is_fundamental () && !((CreationMethod
) m
).chain_up
) {
618 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_type_create_instance"));
619 ccall
.add_argument (get_variable_cexpression ("object_type"));
620 ccode
.add_assignment (get_this_cexpression (), new
CCodeCastExpression (ccall
, get_ccode_name (cl
) + "*"));
622 /* type, dup func, and destroy func fields for generic types */
623 foreach (TypeParameter type_param
in current_class
.get_type_parameters ()) {
624 CCodeIdentifier param_name
;
625 CCodeAssignment assign
;
627 var priv_access
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv");
629 param_name
= new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ()));
630 assign
= new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
);
631 ccode
.add_expression (assign
);
633 param_name
= new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ()));
634 assign
= new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
);
635 ccode
.add_expression (assign
);
637 param_name
= new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ()));
638 assign
= new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
);
639 ccode
.add_expression (assign
);
642 } else if (current_type_symbol is Class
) {
643 var cl
= (Class
) m
.parent_symbol
;
645 ccode
.add_declaration (get_ccode_name (cl
) + "*", new
CCodeVariableDeclarator ("self"));
648 if (!((CreationMethod
) m
).chain_up
) {
649 // TODO implicitly chain up to base class as in add_object_creation
650 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_new0"));
651 ccall
.add_argument (new
CCodeIdentifier (get_ccode_name (cl
)));
652 ccode
.add_assignment (get_this_cexpression (), ccall
);
655 if (cl
.base_class
== null) {
656 var cinitcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_instance_init".printf (get_ccode_lower_case_name (cl
, null))));
657 cinitcall
.add_argument (get_this_cexpression ());
658 ccode
.add_expression (cinitcall
);
661 var st
= (Struct
) m
.parent_symbol
;
663 // memset needs string.h
664 cfile
.add_include ("string.h");
665 var czero
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
666 czero
.add_argument (new
CCodeIdentifier ("self"));
667 czero
.add_argument (new
CCodeConstant ("0"));
668 czero
.add_argument (new
CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (st
))));
669 ccode
.add_expression (czero
);
673 if (context
.module_init_method
== m
&& in_plugin
) {
674 // GTypeModule-based plug-in, register types
675 register_plugin_types (context
.root
, new HashSet
<Symbol
> ());
678 foreach (Expression precondition
in m
.get_preconditions ()) {
679 create_precondition_statement (m
, creturn_type
, precondition
);
685 string prefix
= "_vala_prof_%s".printf (real_name
);
687 var level
= new
CCodeIdentifier (prefix
+ "_level");
688 ccode
.open_if (new
CCodeUnaryExpression (CCodeUnaryOperator
.LOGICAL_NEGATION
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, level
)));
690 var counter
= new
CCodeIdentifier (prefix
+ "_counter");
691 ccode
.add_expression (new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, counter
));
693 var timer
= new
CCodeIdentifier (prefix
+ "_timer");
694 var cont_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_timer_continue"));
695 cont_call
.add_argument (timer
);
696 ccode
.add_expression (cont_call
);
701 if (m
.body
!= null) {
704 if (co_switch_block
!= null) {
705 // after counting the number of yields for coroutines, append the case statements to the switch
706 var old_block
= ccode
.current_block
;
707 ccode
.current_block
= co_switch_block
;
709 for (int state
= 1; state
< emit_context
.next_coroutine_state
; state
++) {
710 ccode
.add_case (new
CCodeConstant (state
.to_string ()));
711 ccode
.add_goto ("_state_%d".printf (state
));
714 // let gcc know that this can't happen
715 ccode
.add_default ();
716 ccode
.add_expression (new
CCodeFunctionCall (new
CCodeIdentifier ("g_assert_not_reached")));
718 ccode
.current_block
= old_block
;
719 co_switch_block
= null;
723 // we generate the same code if we see a return statement, this handles the case without returns
724 if (profile
&& m
.return_type is VoidType
) {
725 string prefix
= "_vala_prof_%s".printf (real_name
);
727 var level
= new
CCodeIdentifier (prefix
+ "_level");
728 ccode
.open_if (new
CCodeUnaryExpression (CCodeUnaryOperator
.LOGICAL_NEGATION
, new
CCodeUnaryExpression (CCodeUnaryOperator
.PREFIX_DECREMENT
, level
)));
730 var timer
= new
CCodeIdentifier (prefix
+ "_timer");
732 var stop_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_timer_stop"));
733 stop_call
.add_argument (timer
);
734 ccode
.add_expression (stop_call
);
739 // generate *_real_* functions for virtual methods
740 // also generate them for abstract methods of classes to prevent faulty subclassing
741 if (!m
.is_abstract
|| (m
.is_abstract
&& current_type_symbol is Class
)) {
742 /* Methods imported from a plain C file don't
743 * have a body, e.g. Vala.Parser.parse_file () */
744 if (m
.body
!= null) {
745 if (current_method_inner_error
) {
746 /* always separate error parameter and inner_error local variable
747 * as error may be set to NULL but we're always interested in inner errors
750 closure_struct
.add_field ("GError *", "_inner_error_");
752 // no initialization necessary, closure struct is zeroed
754 ccode
.add_declaration ("GError *", new CCodeVariableDeclarator
.zero ("_inner_error_", new
CCodeConstant ("NULL")));
758 // For non-void return-types GAsyncModule.visit_return_statement () will take care of this
759 if (m
.return_type is VoidType
&& m
.coroutine
) {
764 if (!(m
.return_type is VoidType
) && !m
.return_type
.is_real_non_null_struct_type () && !m
.coroutine
) {
765 // add dummy return if exit block is known to be unreachable to silence C compiler
766 if (m
.return_block
!= null && m
.return_block
.get_predecessors ().size
== 0) {
767 ccode
.add_return (new
CCodeIdentifier ("result"));
771 if (m is CreationMethod
) {
772 if (current_type_symbol is Class
) {
773 creturn_type
= new
ObjectType (current_class
);
775 creturn_type
= new
VoidType ();
779 if (current_type_symbol is Class
&& gobject_type
!= null && current_class
.is_subtype_of (gobject_type
)
780 && current_class
.get_type_parameters ().size
> 0
781 && !((CreationMethod
) m
).chain_up
) {
782 var ccond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.GREATER_THAN
, new
CCodeIdentifier ("__params_it"), new
CCodeIdentifier ("__params"));
783 ccode
.open_while (ccond
);
784 ccode
.add_expression (new
CCodeUnaryExpression (CCodeUnaryOperator
.PREFIX_DECREMENT
, new
CCodeIdentifier ("__params_it")));
785 var cunsetcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_unset"));
786 cunsetcall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("__params_it"), "value")));
787 ccode
.add_expression (cunsetcall
);
790 var cfreeparams
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_free"));
791 cfreeparams
.add_argument (new
CCodeIdentifier ("__params"));
792 ccode
.add_expression (cfreeparams
);
795 if (current_type_symbol is Class
&& !m
.coroutine
) {
796 CCodeExpression cresult
= new
CCodeIdentifier ("self");
797 if (get_ccode_type (m
) != null) {
798 cresult
= new
CCodeCastExpression (cresult
, get_ccode_type (m
));
801 ccode
.add_return (cresult
);
805 cfile
.add_function (ccode
);
809 if (m
.is_abstract
&& current_type_symbol is Class
) {
810 // generate helpful error message if a sublcass does not implement an abstract method.
811 // This is only meaningful for subclasses implemented in C since the vala compiler would
812 // complain during compile time of such en error.
814 // add critical warning that this method should not have been called
815 var cerrorcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_critical"));
816 if (!((Class
) current_type_symbol
).is_compact
) {
817 var type_from_instance_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_TYPE_FROM_INSTANCE"));
818 type_from_instance_call
.add_argument (new
CCodeIdentifier ("self"));
820 var type_name_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_type_name"));
821 type_name_call
.add_argument (type_from_instance_call
);
823 cerrorcall
.add_argument (new
CCodeConstant ("\"Type `%%s' does not implement abstract method `%s'\"".printf (get_ccode_name (m
))));
824 cerrorcall
.add_argument (type_name_call
);
826 cerrorcall
.add_argument (new
CCodeConstant ("\"Abstract method `%s' is not implemented\"".printf (get_ccode_name (m
))));
829 ccode
.add_expression (cerrorcall
);
831 // add return statement
832 return_default_value (creturn_type
);
834 cfile
.add_function (ccode
);
839 if ((m
.is_abstract
|| m
.is_virtual
) && !m
.coroutine
&&
840 /* If the method is a signal handler, the declaration
841 * is not needed. -- the name should be reserved for the
843 m
.signal_reference
== null) {
845 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
846 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
848 generate_vfunc (m
, creturn_type
, cparam_map
, carg_map
);
852 // m is possible entry point, add appropriate startup code
853 var cmain
= new
CCodeFunction ("main", "int");
854 cmain
.line
= function
.line
;
855 cmain
.add_parameter (new
CCodeParameter ("argc", "int"));
856 cmain
.add_parameter (new
CCodeParameter ("argv", "char **"));
857 push_function (cmain
);
859 if (context
.profile
== Profile
.GOBJECT
) {
860 if (context
.mem_profiler
) {
861 var mem_profiler_init_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_mem_set_vtable"));
862 mem_profiler_init_call
.line
= cmain
.line
;
863 mem_profiler_init_call
.add_argument (new
CCodeConstant ("glib_mem_profiler_table"));
864 ccode
.add_expression (mem_profiler_init_call
);
868 var main_call
= new
CCodeFunctionCall (new
CCodeIdentifier (function
.name
));
869 if (m
.get_parameters ().size
== 1) {
870 main_call
.add_argument (new
CCodeIdentifier ("argv"));
871 main_call
.add_argument (new
CCodeIdentifier ("argc"));
873 if (m
.return_type is VoidType
) {
874 // method returns void, always use 0 as exit code
875 ccode
.add_expression (main_call
);
876 ccode
.add_return (new
CCodeConstant ("0"));
878 ccode
.add_return (main_call
);
881 cfile
.add_function (cmain
);
887 public virtual CCodeParameter
generate_parameter (Parameter param
, CCodeFile decl_space
, Map
<int,CCodeParameter
> cparam_map
, Map
<int,CCodeExpression
>? carg_map
) {
888 CCodeParameter cparam
;
889 if (!param
.ellipsis
) {
890 string ctypename
= get_ccode_name (param
.variable_type
);
892 generate_type_declaration (param
.variable_type
, decl_space
);
894 // pass non-simple structs always by reference
895 if (param
.variable_type
.data_type is Struct
) {
896 var st
= (Struct
) param
.variable_type
.data_type
;
897 if (!st
.is_simple_type () && param
.direction
== ParameterDirection
.IN
) {
898 if (st
.is_immutable
&& !param
.variable_type
.value_owned
) {
899 ctypename
= "const " + ctypename
;
902 if (!param
.variable_type
.nullable
) {
908 if (param
.direction
!= ParameterDirection
.IN
) {
912 cparam
= new
CCodeParameter (get_variable_cname (param
.name
), ctypename
);
913 if (param
.format_arg
) {
914 cparam
.modifiers
= CCodeModifiers
.FORMAT_ARG
;
916 } else if (ellipses_to_valist
) {
917 cparam
= new
CCodeParameter ("_vala_va_list", "va_list");
919 cparam
= new CCodeParameter
.with_ellipsis ();
922 cparam_map
.set (get_param_pos (get_ccode_pos (param
), param
.ellipsis
), cparam
);
923 if (carg_map
!= null && !param
.ellipsis
) {
924 carg_map
.set (get_param_pos (get_ccode_pos (param
), param
.ellipsis
), get_variable_cexpression (param
.name
));
930 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) {
932 var closure_block
= current_closure_block
;
933 int block_id
= get_block_id (closure_block
);
934 var instance_param
= new
CCodeParameter ("_data%d_".printf (block_id
), "Block%dData*".printf (block_id
));
935 cparam_map
.set (get_param_pos (get_ccode_instance_pos (m
)), instance_param
);
936 } else if (m
.parent_symbol is Class
&& m is CreationMethod
) {
937 var cl
= (Class
) m
.parent_symbol
;
938 if (!cl
.is_compact
&& vcall
== null && (direction
& 1) == 1) {
939 cparam_map
.set (get_param_pos (get_ccode_instance_pos (m
)), new
CCodeParameter ("object_type", "GType"));
941 } else if ((m
.binding
== MemberBinding
.INSTANCE
|| (m
.parent_symbol is Struct
&& m is CreationMethod
))
942 && (direction
!= 2 || get_ccode_finish_instance (m
))) {
943 TypeSymbol parent_type
= find_parent_type (m
);
945 if (parent_type is Class
) {
946 this_type
= new
ObjectType ((Class
) parent_type
);
947 } else if (parent_type is Interface
) {
948 this_type
= new
ObjectType ((Interface
) parent_type
);
949 } else if (parent_type is Struct
) {
950 this_type
= new
StructValueType ((Struct
) parent_type
);
951 } else if (parent_type is Enum
) {
952 this_type
= new
EnumValueType ((Enum
) parent_type
);
954 assert_not_reached ();
957 generate_type_declaration (this_type
, decl_space
);
959 CCodeParameter instance_param
= null;
960 if (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
) {
961 var base_type
= new
ObjectType ((Interface
) m
.base_interface_method
.parent_symbol
);
962 instance_param
= new
CCodeParameter ("base", get_ccode_name (base_type
));
963 } else if (m
.overrides
) {
964 var base_type
= new
ObjectType ((Class
) m
.base_method
.parent_symbol
);
965 instance_param
= new
CCodeParameter ("base", get_ccode_name (base_type
));
967 if (m
.parent_symbol is Struct
&& !((Struct
) m
.parent_symbol
).is_simple_type ()) {
968 instance_param
= new
CCodeParameter ("*self", get_ccode_name (this_type
));
970 instance_param
= new
CCodeParameter ("self", get_ccode_name (this_type
));
973 cparam_map
.set (get_param_pos (get_ccode_instance_pos (m
)), instance_param
);
974 } else if (m
.binding
== MemberBinding
.CLASS
) {
975 TypeSymbol parent_type
= find_parent_type (m
);
977 this_type
= new
ClassType ((Class
) parent_type
);
978 var class_param
= new
CCodeParameter ("klass", get_ccode_name (this_type
));
979 cparam_map
.set (get_param_pos (get_ccode_instance_pos (m
)), class_param
);
982 if (is_gtypeinstance_creation_method (m
)) {
983 // memory management for generic types
984 int type_param_index
= 0;
985 var cl
= (Class
) m
.parent_symbol
;
986 foreach (TypeParameter type_param
in cl
.get_type_parameters ()) {
987 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeParameter ("%s_type".printf (type_param
.name
.down ()), "GType"));
988 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeParameter ("%s_dup_func".printf (type_param
.name
.down ()), "GBoxedCopyFunc"));
989 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeParameter ("%s_destroy_func".printf (type_param
.name
.down ()), "GDestroyNotify"));
990 if (carg_map
!= null) {
991 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ())));
992 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ())));
993 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ())));
997 } else if (!m
.closure
&& (direction
& 1) == 1) {
998 int type_param_index
= 0;
999 foreach (var type_param
in m
.get_type_parameters ()) {
1000 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeParameter ("%s_type".printf (type_param
.name
.down ()), "GType"));
1001 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeParameter ("%s_dup_func".printf (type_param
.name
.down ()), "GBoxedCopyFunc"));
1002 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeParameter ("%s_destroy_func".printf (type_param
.name
.down ()), "GDestroyNotify"));
1003 if (carg_map
!= null) {
1004 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ())));
1005 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ())));
1006 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ())));
1012 var needs_format_arg
= m
.get_format_arg_index () < 0 && (m
.printf_format
|| m
.scanf_format
);
1014 CCodeParameter? prev_cparam
= null;
1015 foreach (Parameter param
in m
.get_parameters ()) {
1016 if (param
.direction
!= ParameterDirection
.OUT
) {
1017 if ((direction
& 1) == 0) {
1022 if ((direction
& 2) == 0) {
1023 // no out parameters
1028 var cparam
= generate_parameter (param
, decl_space
, cparam_map
, carg_map
);
1030 // if there is no explicit FormatArg annotation while this method throws an error
1031 // it is required to mark the parameter located right before ellipsis as format-arg
1032 // to account for the parameter shifting caused by the inserted GError parameter
1033 if (needs_format_arg
) {
1034 if (prev_cparam
!= null && cparam
.ellipsis
) {
1035 prev_cparam
.modifiers
|= CCodeModifiers
.FORMAT_ARG
;
1037 prev_cparam
= cparam
;
1041 if ((direction
& 2) != 0) {
1042 generate_method_result_declaration (m
, decl_space
, func
, cparam_map
, carg_map
);
1045 // append C parameters in the right order
1050 foreach (int pos
in cparam_map
.get_keys ()) {
1051 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
1055 if (min_pos
== -1) {
1058 func
.add_parameter (cparam_map
.get (min_pos
));
1059 if (vdeclarator
!= null) {
1060 vdeclarator
.add_parameter (cparam_map
.get (min_pos
));
1062 if (vcall
!= null) {
1063 var arg
= carg_map
.get (min_pos
);
1065 vcall
.add_argument (arg
);
1071 if (m
.printf_format
) {
1072 func
.modifiers
|= CCodeModifiers
.PRINTF
;
1073 } else if (m
.scanf_format
) {
1074 func
.modifiers
|= CCodeModifiers
.SCANF
;
1077 if (m
.version
.deprecated
) {
1078 func
.modifiers
|= CCodeModifiers
.DEPRECATED
;
1082 public void generate_vfunc (Method m
, DataType return_type
, Map
<int,CCodeParameter
> cparam_map
, Map
<int,CCodeExpression
> carg_map
, string suffix
= "", int direction
= 3) {
1083 push_context (new
EmitContext ());
1085 string cname
= get_ccode_name (m
);
1086 if (suffix
== "_finish" && cname
.has_suffix ("_async")) {
1087 cname
= cname
.substring (0, cname
.length
- "_async".length
);
1089 var vfunc
= new
CCodeFunction (cname
+ suffix
);
1091 CCodeExpression vcast
;
1092 if (m
.parent_symbol is Interface
) {
1093 var iface
= (Interface
) m
.parent_symbol
;
1095 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface
))));
1096 ((CCodeFunctionCall
) vcast
).add_argument (new
CCodeIdentifier ("self"));
1098 var cl
= (Class
) m
.parent_symbol
;
1099 if (!cl
.is_compact
) {
1100 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS".printf (get_ccode_upper_case_name (cl
))));
1101 ((CCodeFunctionCall
) vcast
).add_argument (new
CCodeIdentifier ("self"));
1103 vcast
= new
CCodeIdentifier ("self");
1107 cname
= get_ccode_vfunc_name (m
);
1108 if (suffix
== "_finish" && cname
.has_suffix ("_async")) {
1109 cname
= cname
.substring (0, cname
.length
- "_async".length
);
1111 var vcall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, cname
+ suffix
));
1112 carg_map
.set (get_param_pos (get_ccode_instance_pos (m
)), new
CCodeIdentifier ("self"));
1114 generate_cparameters (m
, cfile
, cparam_map
, vfunc
, null, carg_map
, vcall
, direction
);
1116 push_function (vfunc
);
1118 if (context
.assert
&& m
.return_type
.data_type is Struct
&& ((Struct
) m
.return_type
.data_type
).is_simple_type () && default_value_for_type (m
.return_type
, false) == null) {
1119 // the type check will use the result variable
1120 var vardecl
= new
CCodeVariableDeclarator ("result", default_value_for_type (m
.return_type
, true));
1121 vardecl
.init0
= true;
1122 ccode
.add_declaration (get_ccode_name (m
.return_type
), vardecl
);
1125 // add a typecheck statement for "self"
1126 create_method_type_check_statement (m
, return_type
, (TypeSymbol
) m
.parent_symbol
, true, "self");
1128 foreach (Expression precondition
in m
.get_preconditions ()) {
1129 create_precondition_statement (m
, return_type
, precondition
);
1132 if (return_type is VoidType
|| return_type
.is_real_non_null_struct_type ()) {
1133 ccode
.add_expression (vcall
);
1134 } else if (m
.get_postconditions ().size
== 0) {
1135 /* pass method return value */
1136 ccode
.add_return (vcall
);
1138 /* store method return value for postconditions */
1139 ccode
.add_declaration (get_creturn_type (m
, get_ccode_name (return_type
)), new
CCodeVariableDeclarator ("result"));
1140 ccode
.add_assignment (new
CCodeIdentifier ("result"), vcall
);
1143 if (m
.get_postconditions ().size
> 0) {
1144 foreach (Expression postcondition
in m
.get_postconditions ()) {
1145 create_postcondition_statement (postcondition
);
1148 if (!(return_type is VoidType
)) {
1149 ccode
.add_return (new
CCodeIdentifier ("result"));
1153 if (m
.printf_format
) {
1154 vfunc
.modifiers
|= CCodeModifiers
.PRINTF
;
1155 } else if (m
.scanf_format
) {
1156 vfunc
.modifiers
|= CCodeModifiers
.SCANF
;
1159 if (m
.version
.deprecated
) {
1160 vfunc
.modifiers
|= CCodeModifiers
.DEPRECATED
;
1163 cfile
.add_function (vfunc
);
1168 private void create_method_type_check_statement (Method m
, DataType return_type
, TypeSymbol t
, bool non_null
, string var_name
) {
1170 create_type_check_statement (m
, return_type
, t
, non_null
, var_name
);
1174 private void create_precondition_statement (CodeNode method_node
, DataType ret_type
, Expression precondition
) {
1175 var ccheck
= new
CCodeFunctionCall ();
1177 precondition
.emit (this
);
1179 ccheck
.add_argument (get_cvalue (precondition
));
1181 string message
= ((string) precondition
.source_reference
.begin
.pos
).substring (0, (int) (precondition
.source_reference
.end
.pos
- precondition
.source_reference
.begin
.pos
));
1182 ccheck
.add_argument (new
CCodeConstant ("\"%s\"".printf (message
.replace ("\n", " ").escape (""))));
1183 requires_assert
= true;
1185 if (method_node is CreationMethod
) {
1186 ccheck
.call
= new
CCodeIdentifier ("_vala_return_val_if_fail");
1187 ccheck
.add_argument (new
CCodeConstant ("NULL"));
1188 } else if (method_node is Method
&& ((Method
) method_node
).coroutine
) {
1190 ccheck
.call
= new
CCodeIdentifier ("_vala_return_val_if_fail");
1191 ccheck
.add_argument (new
CCodeConstant ("FALSE"));
1192 } else if (ret_type is VoidType
) {
1194 ccheck
.call
= new
CCodeIdentifier ("_vala_return_if_fail");
1196 ccheck
.call
= new
CCodeIdentifier ("_vala_return_val_if_fail");
1198 var cdefault
= default_value_for_type (ret_type
, false);
1199 if (cdefault
!= null) {
1200 ccheck
.add_argument (cdefault
);
1206 ccode
.add_expression (ccheck
);
1209 private TypeSymbol?
find_parent_type (Symbol sym
) {
1210 while (sym
!= null) {
1211 if (sym is TypeSymbol
) {
1212 return (TypeSymbol
) sym
;
1214 sym
= sym
.parent_symbol
;
1219 public override void visit_creation_method (CreationMethod m
) {
1220 push_line (m
.source_reference
);
1222 ellipses_to_valist
= true;
1224 ellipses_to_valist
= false;
1226 if (m
.source_type
== SourceFileType
.FAST
) {
1230 // do not generate _new functions for creation methods of abstract classes
1231 if (current_type_symbol is Class
&& !current_class
.is_compact
&& !current_class
.is_abstract
) {
1233 create_aux_constructor (m
, get_ccode_name (m
), false);
1235 // _construct function (if visit_method generated _constructv)
1236 if (m
.is_variadic ()) {
1237 create_aux_constructor (m
, get_ccode_real_name (m
), true);
1244 private void create_aux_constructor (CreationMethod m
, string func_name
, bool self_as_first_parameter
) {
1245 var vfunc
= new
CCodeFunction (func_name
);
1246 if (m
.is_private_symbol ()) {
1247 vfunc
.modifiers
|= CCodeModifiers
.STATIC
;
1248 } else if (context
.hide_internal
&& m
.is_internal_symbol ()) {
1249 vfunc
.modifiers
|= CCodeModifiers
.INTERNAL
;
1252 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
1253 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
1255 push_function (vfunc
);
1257 string constructor
= (m
.is_variadic ()) ?
get_ccode_constructv_name (m
) : get_ccode_real_name (m
);
1258 var vcall
= new
CCodeFunctionCall (new
CCodeIdentifier (constructor
));
1260 if (self_as_first_parameter
) {
1261 cparam_map
.set (get_param_pos (get_ccode_instance_pos (m
)), new
CCodeParameter ("object_type", "GType"));
1262 vcall
.add_argument (get_variable_cexpression ("object_type"));
1264 vcall
.add_argument (new
CCodeIdentifier (get_ccode_type_id (current_class
)));
1268 generate_cparameters (m
, cfile
, cparam_map
, vfunc
, null, carg_map
, vcall
);
1270 if (m
.is_variadic ()) {
1272 int second_last_pos
= -1;
1273 foreach (int pos
in cparam_map
.get_keys ()) {
1274 if (pos
> last_pos
) {
1275 second_last_pos
= last_pos
;
1277 } else if (pos
> second_last_pos
) {
1278 second_last_pos
= pos
;
1282 var va_start
= new
CCodeFunctionCall (new
CCodeIdentifier ("va_start"));
1283 va_start
.add_argument (new
CCodeIdentifier ("_vala_va_list_obj"));
1284 va_start
.add_argument (carg_map
.get (second_last_pos
));
1286 ccode
.add_declaration ("va_list", new
CCodeVariableDeclarator ("_vala_va_list_obj"));
1287 ccode
.add_expression (va_start
);
1289 vcall
.add_argument (new
CCodeIdentifier("_vala_va_list_obj"));
1292 ccode
.add_return (vcall
);
1296 cfile
.add_function (vfunc
);