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
;
92 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
93 var cparam
= new
CCodeParameter (get_array_length_cname ("result", dim
), "int*");
94 cparam_map
.set (get_param_pos (m
.carray_length_parameter_position
+ 0.01 * dim
), cparam
);
95 if (carg_map
!= null) {
96 carg_map
.set (get_param_pos (m
.carray_length_parameter_position
+ 0.01 * dim
), get_variable_cexpression (cparam
.name
));
99 } else if (m
.return_type is DelegateType
) {
100 // return delegate target if appropriate
101 var deleg_type
= (DelegateType
) m
.return_type
;
102 var d
= deleg_type
.delegate_symbol
;
104 var cparam
= new
CCodeParameter (get_delegate_target_cname ("result"), "void**");
105 cparam_map
.set (get_param_pos (m
.cdelegate_target_parameter_position
), cparam
);
106 if (carg_map
!= null) {
107 carg_map
.set (get_param_pos (m
.cdelegate_target_parameter_position
), get_variable_cexpression (cparam
.name
));
109 if (deleg_type
.value_owned
) {
110 cparam
= new
CCodeParameter (get_delegate_target_destroy_notify_cname ("result"), "GDestroyNotify*");
111 cparam_map
.set (get_param_pos (m
.cdelegate_target_parameter_position
+ 0.01), cparam
);
112 if (carg_map
!= null) {
113 carg_map
.set (get_param_pos (m
.cdelegate_target_parameter_position
+ 0.01), get_variable_cexpression (cparam
.name
));
119 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)) {
120 foreach (DataType error_type
in m
.get_error_types ()) {
121 generate_type_declaration (error_type
, decl_space
);
124 var cparam
= new
CCodeParameter ("error", "GError**");
125 cparam_map
.set (get_param_pos (-1), cparam
);
126 if (carg_map
!= null) {
127 carg_map
.set (get_param_pos (-1), new
CCodeIdentifier (cparam
.name
));
132 public void complete_async () {
133 var state
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "_state_");
134 var zero
= new
CCodeConstant ("0");
135 var state_is_zero
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, state
, zero
);
136 ccode
.open_if (state_is_zero
);
138 var async_result_expr
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "_async_result");
140 var idle_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_simple_async_result_complete_in_idle"));
141 idle_call
.add_argument (async_result_expr
);
142 ccode
.add_expression (idle_call
);
146 var direct_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_simple_async_result_complete"));
147 direct_call
.add_argument (async_result_expr
);
148 ccode
.add_expression (direct_call
);
152 var unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_unref"));
153 unref
.add_argument (async_result_expr
);
154 ccode
.add_expression (unref
);
156 ccode
.add_return (new
CCodeConstant ("FALSE"));
159 public override void generate_method_declaration (Method m
, CCodeFile decl_space
) {
160 if (m
.is_async_callback
) {
163 if (add_symbol_declaration (decl_space
, m
, m
.get_cname ())) {
167 var function
= new
CCodeFunction (m
.get_cname ());
169 if (m
.is_private_symbol () && !m
.external
) {
170 function
.modifiers
|= CCodeModifiers
.STATIC
;
172 function
.modifiers
|= CCodeModifiers
.INLINE
;
177 function
.modifiers
|= CCodeModifiers
.DEPRECATED
;
180 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
181 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
183 var cl
= m
.parent_symbol as Class
;
185 // do not generate _new functions for creation methods of abstract classes
186 if (!(m is CreationMethod
&& cl
!= null && cl
.is_abstract
)) {
187 generate_cparameters (m
, decl_space
, cparam_map
, function
, null, carg_map
, new
CCodeFunctionCall (new
CCodeIdentifier ("fake")));
189 decl_space
.add_function_declaration (function
);
192 if (m is CreationMethod
&& cl
!= null) {
193 // _construct function
194 function
= new
CCodeFunction (m
.get_real_cname ());
196 if (m
.is_private_symbol ()) {
197 function
.modifiers
|= CCodeModifiers
.STATIC
;
200 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
201 generate_cparameters (m
, decl_space
, cparam_map
, function
);
203 decl_space
.add_function_declaration (function
);
207 void register_plugin_types (Symbol sym
, Set
<Symbol
> registered_types
) {
208 var ns
= sym as Namespace
;
209 var cl
= sym as Class
;
210 var iface
= sym as Interface
;
212 foreach (var ns_ns
in ns
.get_namespaces ()) {
213 register_plugin_types (ns_ns
, registered_types
);
215 foreach (var ns_cl
in ns
.get_classes ()) {
216 register_plugin_types (ns_cl
, registered_types
);
218 foreach (var ns_iface
in ns
.get_interfaces ()) {
219 register_plugin_types (ns_iface
, registered_types
);
221 } else if (cl
!= null) {
222 register_plugin_type (cl
, registered_types
);
223 foreach (var cl_cl
in cl
.get_classes ()) {
224 register_plugin_types (cl_cl
, registered_types
);
226 } else if (iface
!= null) {
227 register_plugin_type (iface
, registered_types
);
228 foreach (var iface_cl
in iface
.get_classes ()) {
229 register_plugin_types (iface_cl
, registered_types
);
234 void register_plugin_type (ObjectTypeSymbol type_symbol
, Set
<Symbol
> registered_types
) {
235 if (type_symbol
.external_package
) {
239 if (!registered_types
.add (type_symbol
)) {
240 // already registered
244 var cl
= type_symbol as Class
;
250 // register base types first
251 foreach (var base_type
in cl
.get_base_types ()) {
252 register_plugin_type ((ObjectTypeSymbol
) base_type
.data_type
, registered_types
);
256 var register_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_register_type".printf (type_symbol
.get_lower_case_cname (null))));
257 register_call
.add_argument (new
CCodeIdentifier (module_init_param_name
));
258 ccode
.add_expression (register_call
);
261 public override void visit_method (Method m
) {
262 push_context (new
EmitContext (m
));
264 bool in_gobject_creation_method
= false;
265 bool in_fundamental_creation_method
= false;
267 check_type (m
.return_type
);
269 if (m is CreationMethod
) {
270 var cl
= current_type_symbol as Class
;
271 if (cl
!= null && !cl
.is_compact
) {
272 if (cl
.base_class
== null) {
273 in_fundamental_creation_method
= true;
274 } else if (gobject_type
!= null && cl
.is_subtype_of (gobject_type
)) {
275 in_gobject_creation_method
= true;
281 next_coroutine_state
= 1;
284 var creturn_type
= m
.return_type
;
285 if (m
.return_type
.is_real_non_null_struct_type ()) {
286 // structs are returned via out parameter
287 creturn_type
= new
VoidType ();
290 if (m
.binding
== MemberBinding
.CLASS
|| m
.binding
== MemberBinding
.STATIC
) {
291 in_static_or_class_context
= true;
295 foreach (Parameter param
in m
.get_parameters ()) {
299 // do not declare overriding methods and interface implementations
300 if (m
.is_abstract
|| m
.is_virtual
301 || (m
.base_method
== null && m
.base_interface_method
== null)) {
302 generate_method_declaration (m
, cfile
);
304 if (!m
.is_internal_symbol ()) {
305 generate_method_declaration (m
, header_file
);
307 if (!m
.is_private_symbol ()) {
308 generate_method_declaration (m
, internal_header_file
);
312 CCodeFunction function
;
313 function
= new
CCodeFunction (m
.get_real_cname ());
316 function
.modifiers
|= CCodeModifiers
.INLINE
;
319 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
321 generate_cparameters (m
, cfile
, cparam_map
, function
);
323 // generate *_real_* functions for virtual methods
324 // also generate them for abstract methods of classes to prevent faulty subclassing
325 if (!m
.is_abstract
|| (m
.is_abstract
&& current_type_symbol is Class
)) {
327 if (m
.base_method
!= null || m
.base_interface_method
!= null) {
328 // declare *_real_* function
329 function
.modifiers
|= CCodeModifiers
.STATIC
;
330 cfile
.add_function_declaration (function
);
331 } else if (m
.is_private_symbol ()) {
332 function
.modifiers
|= CCodeModifiers
.STATIC
;
337 // generate *_real_* functions for virtual methods
338 // also generate them for abstract methods of classes to prevent faulty subclassing
339 if (!m
.is_abstract
|| (m
.is_abstract
&& current_type_symbol is Class
)) {
340 if (m
.body
!= null) {
342 function
= new
CCodeFunction (m
.get_real_cname () + "_co", "gboolean");
344 // data struct to hold parameters, local variables, and the return value
345 function
.add_parameter (new
CCodeParameter ("data", Symbol
.lower_case_to_camel_case (m
.get_cname ()) + "Data*"));
347 function
.modifiers
|= CCodeModifiers
.STATIC
;
348 cfile
.add_function_declaration (function
);
353 if (m
.comment
!= null) {
354 cfile
.add_type_member_definition (new
CCodeComment (m
.comment
.content
));
357 push_function (function
);
359 // generate *_real_* functions for virtual methods
360 // also generate them for abstract methods of classes to prevent faulty subclassing
361 if (!m
.is_abstract
|| (m
.is_abstract
&& current_type_symbol is Class
)) {
362 if (m
.body
!= null) {
364 ccode
.open_switch (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "_state_"));
366 // initial coroutine state
367 ccode
.add_case (new
CCodeConstant ("0"));
368 ccode
.add_goto ("_state_0");
370 for (int state
= 1; state
<= m
.yield_count
; state
++) {
371 ccode
.add_case (new
CCodeConstant (state
.to_string ()));
372 ccode
.add_goto ("_state_%d".printf (state
));
376 // let gcc know that this can't happen
377 ccode
.add_default ();
378 ccode
.add_expression (new
CCodeFunctionCall (new
CCodeIdentifier ("g_assert_not_reached")));
383 ccode
.add_label ("_state_0");
387 // add variables for parent closure blocks
388 // as closures only have one parameter for the innermost closure block
389 var closure_block
= current_closure_block
;
390 int block_id
= get_block_id (closure_block
);
392 var parent_closure_block
= next_closure_block (closure_block
.parent_symbol
);
393 if (parent_closure_block
== null) {
396 int parent_block_id
= get_block_id (parent_closure_block
);
398 var parent_data
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_data%d_".printf (parent_block_id
));
399 ccode
.add_declaration ("Block%dData*".printf (parent_block_id
), new
CCodeVariableDeclarator ("_data%d_".printf (parent_block_id
)));
400 ccode
.add_expression (new
CCodeAssignment (new
CCodeIdentifier ("_data%d_".printf (parent_block_id
)), parent_data
));
402 closure_block
= parent_closure_block
;
403 block_id
= parent_block_id
;
406 // add self variable for closures
407 // as closures have block data parameter
408 if (m
.binding
== MemberBinding
.INSTANCE
) {
409 var cself
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "self");
410 ccode
.add_declaration ("%s *".printf (current_class
.get_cname ()), new
CCodeVariableDeclarator ("self"));
411 ccode
.add_expression (new
CCodeAssignment (new
CCodeIdentifier ("self"), cself
));
414 // allow capturing generic type parameters
415 foreach (var type_param
in m
.get_type_parameters ()) {
418 func_name
= "%s_type".printf (type_param
.name
.down ());
419 ccode
.add_declaration ("GType", new
CCodeVariableDeclarator (func_name
));
420 ccode
.add_expression (new
CCodeAssignment (new
CCodeIdentifier (func_name
), new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
)));
422 func_name
= "%s_dup_func".printf (type_param
.name
.down ());
423 ccode
.add_declaration ("GBoxedCopyFunc", new
CCodeVariableDeclarator (func_name
));
424 ccode
.add_expression (new
CCodeAssignment (new
CCodeIdentifier (func_name
), new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
)));
426 func_name
= "%s_destroy_func".printf (type_param
.name
.down ());
427 ccode
.add_declaration ("GDestroyNotify", new
CCodeVariableDeclarator (func_name
));
428 ccode
.add_expression (new
CCodeAssignment (new
CCodeIdentifier (func_name
), new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
)));
430 } else if (m
.parent_symbol is Class
&& !m
.coroutine
) {
431 var cl
= (Class
) m
.parent_symbol
;
432 if (m
.overrides
|| (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
)) {
434 ReferenceType base_expression_type
;
436 base_method
= m
.base_method
;
437 base_expression_type
= new
ObjectType ((Class
) base_method
.parent_symbol
);
439 base_method
= m
.base_interface_method
;
440 base_expression_type
= new
ObjectType ((Interface
) base_method
.parent_symbol
);
442 var self_target_type
= new
ObjectType (cl
);
443 CCodeExpression cself
= transform_expression (new
CCodeIdentifier ("base"), base_expression_type
, self_target_type
);
445 ccode
.add_declaration ("%s *".printf (cl
.get_cname ()), new
CCodeVariableDeclarator ("self"));
446 ccode
.add_expression (new
CCodeAssignment (new
CCodeIdentifier ("self"), cself
));
447 } else if (m
.binding
== MemberBinding
.INSTANCE
448 && !(m is CreationMethod
)) {
449 create_method_type_check_statement (m
, creturn_type
, cl
, true, "self");
453 foreach (Parameter param
in m
.get_parameters ()) {
454 if (param
.ellipsis
) {
458 if (param
.direction
!= ParameterDirection
.OUT
) {
459 var t
= param
.variable_type
.data_type
;
460 if (t
!= null && t
.is_reference_type ()) {
461 create_method_type_check_statement (m
, creturn_type
, t
, !param
.variable_type
.nullable
, get_variable_cname (param
.name
));
463 } else if (!m
.coroutine
) {
464 // declare local variable for out parameter to allow assignment even when caller passes NULL
465 var vardecl
= new CCodeVariableDeclarator
.zero (get_variable_cname ("_" + param
.name
), default_value_for_type (param
.variable_type
, true));
466 ccode
.add_declaration (param
.variable_type
.get_cname (), vardecl
);
468 if (param
.variable_type is ArrayType
) {
469 // create variables to store array dimensions
470 var array_type
= (ArrayType
) param
.variable_type
;
472 if (!array_type
.fixed_length
) {
473 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
474 vardecl
= new CCodeVariableDeclarator
.zero (get_array_length_cname (get_variable_cname ("_" + param
.name
), dim
), new
CCodeConstant ("0"));
475 ccode
.add_declaration ("int", vardecl
);
478 } else if (param
.variable_type is DelegateType
) {
479 var deleg_type
= (DelegateType
) param
.variable_type
;
480 var d
= deleg_type
.delegate_symbol
;
482 // create variable to store delegate target
483 vardecl
= new CCodeVariableDeclarator
.zero (get_delegate_target_cname (get_variable_cname ("_" + param
.name
)), new
CCodeConstant ("NULL"));
484 ccode
.add_declaration ("void *", vardecl
);
486 if (deleg_type
.value_owned
) {
487 vardecl
= new CCodeVariableDeclarator
.zero (get_delegate_target_destroy_notify_cname (get_variable_cname ("_" + param
.name
)), new
CCodeConstant ("NULL"));
488 ccode
.add_declaration ("GDestroyNotify", vardecl
);
495 if (!(m
.return_type is VoidType
) && !m
.return_type
.is_real_non_null_struct_type () && !m
.coroutine
) {
496 var vardecl
= new
CCodeVariableDeclarator ("result", default_value_for_type (m
.return_type
, true));
497 vardecl
.init0
= true;
498 ccode
.add_declaration (m
.return_type
.get_cname (), vardecl
);
501 if (m is CreationMethod
) {
502 if (in_gobject_creation_method
) {
503 ccode
.add_declaration ("%s *".printf (((Class
) current_type_symbol
).get_cname ()), new CCodeVariableDeclarator
.zero ("self", new
CCodeConstant ("NULL")));
504 } else if (is_gtypeinstance_creation_method (m
)) {
505 var cl
= (Class
) m
.parent_symbol
;
506 ccode
.add_declaration (cl
.get_cname () + "*", new CCodeVariableDeclarator
.zero ("self", new
CCodeConstant ("NULL")));
508 if (cl
.is_fundamental ()) {
509 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_type_create_instance"));
510 ccall
.add_argument (new
CCodeIdentifier ("object_type"));
511 ccode
.add_expression (new
CCodeAssignment (new
CCodeIdentifier ("self"), new
CCodeCastExpression (ccall
, cl
.get_cname () + "*")));
513 /* type, dup func, and destroy func fields for generic types */
514 foreach (TypeParameter type_param
in current_class
.get_type_parameters ()) {
515 CCodeIdentifier param_name
;
516 CCodeAssignment assign
;
518 var priv_access
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv");
520 param_name
= new
CCodeIdentifier ("%s_type".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_dup_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
);
528 param_name
= new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ()));
529 assign
= new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
);
530 ccode
.add_expression (assign
);
533 } else if (current_type_symbol is Class
) {
534 var cl
= (Class
) m
.parent_symbol
;
535 ccode
.add_declaration (cl
.get_cname () + "*", new
CCodeVariableDeclarator ("self"));
537 if (!((CreationMethod
) m
).chain_up
) {
538 // TODO implicitly chain up to base class as in add_object_creation
539 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_new0"));
540 ccall
.add_argument (new
CCodeIdentifier (cl
.get_cname ()));
541 ccode
.add_expression (new
CCodeAssignment (new
CCodeIdentifier ("self"), ccall
));
544 if (cl
.base_class
== null) {
545 // derived compact classes do not have fields
546 var cinitcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_instance_init".printf (cl
.get_lower_case_cname (null))));
547 cinitcall
.add_argument (new
CCodeIdentifier ("self"));
548 ccode
.add_expression (cinitcall
);
551 var st
= (Struct
) m
.parent_symbol
;
553 // memset needs string.h
554 cfile
.add_include ("string.h");
555 var czero
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
556 czero
.add_argument (new
CCodeIdentifier ("self"));
557 czero
.add_argument (new
CCodeConstant ("0"));
558 czero
.add_argument (new
CCodeIdentifier ("sizeof (%s)".printf (st
.get_cname ())));
559 ccode
.add_expression (czero
);
563 if (context
.module_init_method
== m
&& in_plugin
) {
564 // GTypeModule-based plug-in, register types
565 register_plugin_types (context
.root
, new HashSet
<Symbol
> ());
568 foreach (Expression precondition
in m
.get_preconditions ()) {
569 create_precondition_statement (m
, creturn_type
, precondition
);
574 if (m
.body
!= null) {
578 // generate *_real_* functions for virtual methods
579 // also generate them for abstract methods of classes to prevent faulty subclassing
580 if (!m
.is_abstract
|| (m
.is_abstract
&& current_type_symbol is Class
)) {
581 /* Methods imported from a plain C file don't
582 * have a body, e.g. Vala.Parser.parse_file () */
583 if (m
.body
!= null) {
584 if (current_method_inner_error
) {
585 /* always separate error parameter and inner_error local variable
586 * as error may be set to NULL but we're always interested in inner errors
589 closure_struct
.add_field ("GError *", "_inner_error_");
591 // no initialization necessary, closure struct is zeroed
593 ccode
.add_declaration ("GError *", new CCodeVariableDeclarator
.zero ("_inner_error_", new
CCodeConstant ("NULL")));
602 if (!(m
.return_type is VoidType
) && !m
.return_type
.is_real_non_null_struct_type () && !m
.coroutine
) {
603 // add dummy return if exit block is known to be unreachable to silence C compiler
604 if (m
.return_block
!= null && m
.return_block
.get_predecessors ().size
== 0) {
605 ccode
.add_return (new
CCodeIdentifier ("result"));
609 if (m is CreationMethod
) {
610 if (current_type_symbol is Class
) {
611 creturn_type
= new
ObjectType (current_class
);
613 creturn_type
= new
VoidType ();
617 if (current_type_symbol is Class
&& gobject_type
!= null && current_class
.is_subtype_of (gobject_type
)
618 && current_class
.get_type_parameters ().size
> 0
619 && !((CreationMethod
) m
).chain_up
) {
620 var ccond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.GREATER_THAN
, new
CCodeIdentifier ("__params_it"), new
CCodeIdentifier ("__params"));
621 var cdofreeparam
= new
CCodeBlock ();
622 cdofreeparam
.add_statement (new
CCodeExpressionStatement (new
CCodeUnaryExpression (CCodeUnaryOperator
.PREFIX_DECREMENT
, new
CCodeIdentifier ("__params_it"))));
623 var cunsetcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_unset"));
624 cunsetcall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("__params_it"), "value")));
625 cdofreeparam
.add_statement (new
CCodeExpressionStatement (cunsetcall
));
626 ccode
.add_statement (new
CCodeWhileStatement (ccond
, cdofreeparam
));
628 var cfreeparams
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_free"));
629 cfreeparams
.add_argument (new
CCodeIdentifier ("__params"));
630 ccode
.add_expression (cfreeparams
);
633 if (current_type_symbol is Class
) {
634 CCodeExpression cresult
= new
CCodeIdentifier ("self");
635 if (get_custom_creturn_type (m
) != null) {
636 cresult
= new
CCodeCastExpression (cresult
, get_custom_creturn_type (m
));
639 ccode
.add_return (cresult
);
643 cfile
.add_function (ccode
);
648 // generate helpful error message if a sublcass does not implement an abstract method.
649 // This is only meaningful for subclasses implemented in C since the vala compiler would
650 // complain during compile time of such en error.
652 // add a typecheck statement for "self"
653 create_method_type_check_statement (m
, creturn_type
, current_type_symbol
, true, "self");
655 // add critical warning that this method should not have been called
656 var type_from_instance_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_TYPE_FROM_INSTANCE"));
657 type_from_instance_call
.add_argument (new
CCodeIdentifier ("self"));
659 var type_name_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_type_name"));
660 type_name_call
.add_argument (type_from_instance_call
);
662 var error_string
= "\"Type `%%s' does not implement abstract method `%s'\"".printf (m
.get_cname ());
664 var cerrorcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_critical"));
665 cerrorcall
.add_argument (new
CCodeConstant (error_string
));
666 cerrorcall
.add_argument (type_name_call
);
668 ccode
.add_expression (cerrorcall
);
670 // add return statement
671 return_default_value (creturn_type
);
673 cfile
.add_function (ccode
);
677 in_static_or_class_context
= false;
681 if ((m
.is_abstract
|| m
.is_virtual
) && !m
.coroutine
&&
682 /* If the method is a signal handler, the declaration
683 * is not needed. -- the name should be reserved for the
685 m
.signal_reference
== null) {
687 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
688 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
690 generate_vfunc (m
, creturn_type
, cparam_map
, carg_map
);
694 // m is possible entry point, add appropriate startup code
695 var cmain
= new
CCodeFunction ("main", "int");
696 cmain
.line
= function
.line
;
697 cmain
.add_parameter (new
CCodeParameter ("argc", "int"));
698 cmain
.add_parameter (new
CCodeParameter ("argv", "char **"));
699 var main_block
= new
CCodeBlock ();
701 if (context
.profile
== Profile
.GOBJECT
) {
702 if (context
.mem_profiler
) {
703 var mem_profiler_init_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_mem_set_vtable"));
704 mem_profiler_init_call
.line
= cmain
.line
;
705 mem_profiler_init_call
.add_argument (new
CCodeConstant ("glib_mem_profiler_table"));
706 main_block
.add_statement (new
CCodeExpressionStatement (mem_profiler_init_call
));
709 if (context
.thread
) {
710 var thread_init_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_thread_init"));
711 thread_init_call
.line
= cmain
.line
;
712 thread_init_call
.add_argument (new
CCodeConstant ("NULL"));
713 main_block
.add_statement (new
CCodeExpressionStatement (thread_init_call
));
716 var type_init_call
= new
CCodeExpressionStatement (new
CCodeFunctionCall (new
CCodeIdentifier ("g_type_init")));
717 type_init_call
.line
= cmain
.line
;
718 main_block
.add_statement (type_init_call
);
721 var main_call
= new
CCodeFunctionCall (new
CCodeIdentifier (function
.name
));
722 if (m
.get_parameters ().size
== 1) {
723 main_call
.add_argument (new
CCodeIdentifier ("argv"));
724 main_call
.add_argument (new
CCodeIdentifier ("argc"));
726 if (m
.return_type is VoidType
) {
727 // method returns void, always use 0 as exit code
728 var main_stmt
= new
CCodeExpressionStatement (main_call
);
729 main_stmt
.line
= cmain
.line
;
730 main_block
.add_statement (main_stmt
);
731 var ret_stmt
= new
CCodeReturnStatement (new
CCodeConstant ("0"));
732 ret_stmt
.line
= cmain
.line
;
733 main_block
.add_statement (ret_stmt
);
735 var main_stmt
= new
CCodeReturnStatement (main_call
);
736 main_stmt
.line
= cmain
.line
;
737 main_block
.add_statement (main_stmt
);
739 cmain
.block
= main_block
;
740 cfile
.add_function (cmain
);
744 public virtual CCodeParameter
generate_parameter (Parameter param
, CCodeFile decl_space
, Map
<int,CCodeParameter
> cparam_map
, Map
<int,CCodeExpression
>? carg_map
) {
745 CCodeParameter cparam
;
746 if (!param
.ellipsis
) {
747 string ctypename
= param
.variable_type
.get_cname ();
749 generate_type_declaration (param
.variable_type
, decl_space
);
751 // pass non-simple structs always by reference
752 if (param
.variable_type
.data_type is Struct
) {
753 var st
= (Struct
) param
.variable_type
.data_type
;
754 if (!st
.is_simple_type () && param
.direction
== ParameterDirection
.IN
) {
755 if (st
.is_immutable
&& !param
.variable_type
.value_owned
) {
756 ctypename
= "const " + ctypename
;
759 if (!param
.variable_type
.nullable
) {
765 if (param
.direction
!= ParameterDirection
.IN
) {
769 cparam
= new
CCodeParameter (get_variable_cname (param
.name
), ctypename
);
771 cparam
= new CCodeParameter
.with_ellipsis ();
774 cparam_map
.set (get_param_pos (param
.cparameter_position
, param
.ellipsis
), cparam
);
775 if (carg_map
!= null && !param
.ellipsis
) {
776 carg_map
.set (get_param_pos (param
.cparameter_position
, param
.ellipsis
), get_variable_cexpression (param
.name
));
782 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) {
784 var closure_block
= current_closure_block
;
785 int block_id
= get_block_id (closure_block
);
786 var instance_param
= new
CCodeParameter ("_data%d_".printf (block_id
), "Block%dData*".printf (block_id
));
787 cparam_map
.set (get_param_pos (m
.cinstance_parameter_position
), instance_param
);
788 } else if (m
.parent_symbol is Class
&& m is CreationMethod
) {
789 var cl
= (Class
) m
.parent_symbol
;
790 if (!cl
.is_compact
&& vcall
== null) {
791 cparam_map
.set (get_param_pos (m
.cinstance_parameter_position
), new
CCodeParameter ("object_type", "GType"));
793 } else if (m
.binding
== MemberBinding
.INSTANCE
|| (m
.parent_symbol is Struct
&& m is CreationMethod
)) {
794 TypeSymbol parent_type
= find_parent_type (m
);
796 if (parent_type is Class
) {
797 this_type
= new
ObjectType ((Class
) parent_type
);
798 } else if (parent_type is Interface
) {
799 this_type
= new
ObjectType ((Interface
) parent_type
);
800 } else if (parent_type is Struct
) {
801 this_type
= new
StructValueType ((Struct
) parent_type
);
802 } else if (parent_type is Enum
) {
803 this_type
= new
EnumValueType ((Enum
) parent_type
);
805 assert_not_reached ();
808 generate_type_declaration (this_type
, decl_space
);
810 CCodeParameter instance_param
= null;
811 if (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
) {
812 var base_type
= new
ObjectType ((Interface
) m
.base_interface_method
.parent_symbol
);
813 instance_param
= new
CCodeParameter ("base", base_type
.get_cname ());
814 } else if (m
.overrides
) {
815 var base_type
= new
ObjectType ((Class
) m
.base_method
.parent_symbol
);
816 instance_param
= new
CCodeParameter ("base", base_type
.get_cname ());
818 if (m
.parent_symbol is Struct
&& !((Struct
) m
.parent_symbol
).is_simple_type ()) {
819 instance_param
= new
CCodeParameter ("*self", this_type
.get_cname ());
821 instance_param
= new
CCodeParameter ("self", this_type
.get_cname ());
824 cparam_map
.set (get_param_pos (m
.cinstance_parameter_position
), instance_param
);
825 } else if (m
.binding
== MemberBinding
.CLASS
) {
826 TypeSymbol parent_type
= find_parent_type (m
);
828 this_type
= new
ClassType ((Class
) parent_type
);
829 var class_param
= new
CCodeParameter ("klass", this_type
.get_cname ());
830 cparam_map
.set (get_param_pos (m
.cinstance_parameter_position
), class_param
);
833 if (is_gtypeinstance_creation_method (m
)) {
834 // memory management for generic types
835 int type_param_index
= 0;
836 var cl
= (Class
) m
.parent_symbol
;
837 foreach (TypeParameter type_param
in cl
.get_type_parameters ()) {
838 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeParameter ("%s_type".printf (type_param
.name
.down ()), "GType"));
839 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeParameter ("%s_dup_func".printf (type_param
.name
.down ()), "GBoxedCopyFunc"));
840 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeParameter ("%s_destroy_func".printf (type_param
.name
.down ()), "GDestroyNotify"));
841 if (carg_map
!= null) {
842 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ())));
843 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ())));
844 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ())));
848 } else if (!m
.closure
) {
849 int type_param_index
= 0;
850 foreach (var type_param
in m
.get_type_parameters ()) {
851 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeParameter ("%s_type".printf (type_param
.name
.down ()), "GType"));
852 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeParameter ("%s_dup_func".printf (type_param
.name
.down ()), "GBoxedCopyFunc"));
853 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeParameter ("%s_destroy_func".printf (type_param
.name
.down ()), "GDestroyNotify"));
854 if (carg_map
!= null) {
855 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ())));
856 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ())));
857 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ())));
863 foreach (Parameter param
in m
.get_parameters ()) {
864 if (param
.direction
!= ParameterDirection
.OUT
) {
865 if ((direction
& 1) == 0) {
870 if ((direction
& 2) == 0) {
876 generate_parameter (param
, decl_space
, cparam_map
, carg_map
);
879 if ((direction
& 2) != 0) {
880 generate_method_result_declaration (m
, decl_space
, func
, cparam_map
, carg_map
);
883 // append C parameters in the right order
888 foreach (int pos
in cparam_map
.get_keys ()) {
889 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
896 func
.add_parameter (cparam_map
.get (min_pos
));
897 if (vdeclarator
!= null) {
898 vdeclarator
.add_parameter (cparam_map
.get (min_pos
));
901 var arg
= carg_map
.get (min_pos
);
903 vcall
.add_argument (arg
);
910 public void generate_vfunc (Method m
, DataType return_type
, Map
<int,CCodeParameter
> cparam_map
, Map
<int,CCodeExpression
> carg_map
, string suffix
= "", int direction
= 3) {
911 push_context (new
EmitContext ());
913 string cname
= m
.get_cname ();
914 if (suffix
== "_finish" && cname
.has_suffix ("_async")) {
915 cname
= cname
.substring (0, cname
.length
- "_async".length
);
917 var vfunc
= new
CCodeFunction (cname
+ suffix
);
919 CCodeFunctionCall vcast
= null;
920 if (m
.parent_symbol is Interface
) {
921 var iface
= (Interface
) m
.parent_symbol
;
923 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_INTERFACE".printf (iface
.get_upper_case_cname (null))));
925 var cl
= (Class
) m
.parent_symbol
;
927 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS".printf (cl
.get_upper_case_cname (null))));
929 vcast
.add_argument (new
CCodeIdentifier ("self"));
931 cname
= m
.vfunc_name
;
932 if (suffix
== "_finish" && cname
.has_suffix ("_async")) {
933 cname
= cname
.substring (0, cname
.length
- "_async".length
);
935 var vcall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, cname
+ suffix
));
936 carg_map
.set (get_param_pos (m
.cinstance_parameter_position
), new
CCodeIdentifier ("self"));
938 generate_cparameters (m
, cfile
, cparam_map
, vfunc
, null, carg_map
, vcall
, direction
);
940 push_function (vfunc
);
942 foreach (Expression precondition
in m
.get_preconditions ()) {
943 create_precondition_statement (m
, return_type
, precondition
);
946 if (return_type is VoidType
|| return_type
.is_real_non_null_struct_type ()) {
947 ccode
.add_expression (vcall
);
948 } else if (m
.get_postconditions ().size
== 0) {
949 /* pass method return value */
950 ccode
.add_return (vcall
);
952 /* store method return value for postconditions */
953 ccode
.add_declaration (get_creturn_type (m
, return_type
.get_cname ()), new
CCodeVariableDeclarator ("result"));
954 ccode
.add_expression (new
CCodeAssignment (new
CCodeIdentifier ("result"), vcall
));
957 if (m
.get_postconditions ().size
> 0) {
958 foreach (Expression postcondition
in m
.get_postconditions ()) {
959 create_postcondition_statement (postcondition
);
962 if (!(return_type is VoidType
)) {
963 ccode
.add_return (new
CCodeIdentifier ("result"));
967 cfile
.add_function (vfunc
);
972 private void create_method_type_check_statement (Method m
, DataType return_type
, TypeSymbol t
, bool non_null
, string var_name
) {
974 create_type_check_statement (m
, return_type
, t
, non_null
, var_name
);
978 private void create_precondition_statement (CodeNode method_node
, DataType ret_type
, Expression precondition
) {
979 var ccheck
= new
CCodeFunctionCall ();
981 precondition
.emit (this
);
983 ccheck
.add_argument (get_cvalue (precondition
));
985 if (method_node is CreationMethod
) {
986 ccheck
.call
= new
CCodeIdentifier ("g_return_val_if_fail");
987 ccheck
.add_argument (new
CCodeConstant ("NULL"));
988 } else if (method_node is Method
&& ((Method
) method_node
).coroutine
) {
990 ccheck
.call
= new
CCodeIdentifier ("g_return_val_if_fail");
991 ccheck
.add_argument (new
CCodeConstant ("FALSE"));
992 } else if (ret_type is VoidType
) {
994 ccheck
.call
= new
CCodeIdentifier ("g_return_if_fail");
996 ccheck
.call
= new
CCodeIdentifier ("g_return_val_if_fail");
998 var cdefault
= default_value_for_type (ret_type
, false);
999 if (cdefault
!= null) {
1000 ccheck
.add_argument (cdefault
);
1006 ccode
.add_expression (ccheck
);
1009 private TypeSymbol?
find_parent_type (Symbol sym
) {
1010 while (sym
!= null) {
1011 if (sym is TypeSymbol
) {
1012 return (TypeSymbol
) sym
;
1014 sym
= sym
.parent_symbol
;
1019 public override void visit_creation_method (CreationMethod m
) {
1020 bool visible
= !m
.is_private_symbol ();
1024 if (m
.source_type
== SourceFileType
.FAST
) {
1028 // do not generate _new functions for creation methods of abstract classes
1029 if (current_type_symbol is Class
&& !current_class
.is_compact
&& !current_class
.is_abstract
) {
1030 var vfunc
= new
CCodeFunction (m
.get_cname ());
1032 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
1033 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
1035 var vblock
= new
CCodeBlock ();
1037 var vcall
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_real_cname ()));
1038 vcall
.add_argument (new
CCodeIdentifier (current_class
.get_type_id ()));
1040 generate_cparameters (m
, cfile
, cparam_map
, vfunc
, null, carg_map
, vcall
);
1041 CCodeStatement cstmt
= new
CCodeReturnStatement (vcall
);
1042 cstmt
.line
= vfunc
.line
;
1043 vblock
.add_statement (cstmt
);
1046 vfunc
.modifiers
|= CCodeModifiers
.STATIC
;
1049 vfunc
.block
= vblock
;
1051 cfile
.add_function (vfunc
);