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
;
335 if (m
.body
!= null) {
336 function
= new
CCodeFunction (m
.get_real_cname () + "_co", "gboolean");
338 // data struct to hold parameters, local variables, and the return value
339 function
.add_parameter (new
CCodeParameter ("data", Symbol
.lower_case_to_camel_case (m
.get_cname ()) + "Data*"));
341 function
.modifiers
|= CCodeModifiers
.STATIC
;
342 cfile
.add_function_declaration (function
);
347 if (m
.comment
!= null) {
348 cfile
.add_type_member_definition (new
CCodeComment (m
.comment
.content
));
351 push_function (function
);
353 // generate *_real_* functions for virtual methods
354 // also generate them for abstract methods of classes to prevent faulty subclassing
355 if (!m
.is_abstract
|| (m
.is_abstract
&& current_type_symbol is Class
)) {
356 if (m
.body
!= null) {
358 ccode
.open_switch (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "_state_"));
360 // initial coroutine state
361 ccode
.add_case (new
CCodeConstant ("0"));
362 ccode
.add_goto ("_state_0");
364 for (int state
= 1; state
<= m
.yield_count
; state
++) {
365 ccode
.add_case (new
CCodeConstant (state
.to_string ()));
366 ccode
.add_goto ("_state_%d".printf (state
));
370 // let gcc know that this can't happen
371 ccode
.add_default ();
372 ccode
.add_expression (new
CCodeFunctionCall (new
CCodeIdentifier ("g_assert_not_reached")));
377 ccode
.add_label ("_state_0");
381 // add variables for parent closure blocks
382 // as closures only have one parameter for the innermost closure block
383 var closure_block
= current_closure_block
;
384 int block_id
= get_block_id (closure_block
);
386 var parent_closure_block
= next_closure_block (closure_block
.parent_symbol
);
387 if (parent_closure_block
== null) {
390 int parent_block_id
= get_block_id (parent_closure_block
);
392 var parent_data
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "_data%d_".printf (parent_block_id
));
393 ccode
.add_declaration ("Block%dData*".printf (parent_block_id
), new
CCodeVariableDeclarator ("_data%d_".printf (parent_block_id
)));
394 ccode
.add_assignment (new
CCodeIdentifier ("_data%d_".printf (parent_block_id
)), parent_data
);
396 closure_block
= parent_closure_block
;
397 block_id
= parent_block_id
;
400 // add self variable for closures
401 // as closures have block data parameter
402 if (m
.binding
== MemberBinding
.INSTANCE
) {
403 var cself
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data%d_".printf (block_id
)), "self");
404 ccode
.add_declaration ("%s *".printf (current_class
.get_cname ()), new
CCodeVariableDeclarator ("self"));
405 ccode
.add_assignment (new
CCodeIdentifier ("self"), cself
);
408 // allow capturing generic type parameters
409 foreach (var type_param
in m
.get_type_parameters ()) {
412 func_name
= "%s_type".printf (type_param
.name
.down ());
413 ccode
.add_declaration ("GType", new
CCodeVariableDeclarator (func_name
));
414 ccode
.add_assignment (new
CCodeIdentifier (func_name
), new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
));
416 func_name
= "%s_dup_func".printf (type_param
.name
.down ());
417 ccode
.add_declaration ("GBoxedCopyFunc", new
CCodeVariableDeclarator (func_name
));
418 ccode
.add_assignment (new
CCodeIdentifier (func_name
), new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
));
420 func_name
= "%s_destroy_func".printf (type_param
.name
.down ());
421 ccode
.add_declaration ("GDestroyNotify", new
CCodeVariableDeclarator (func_name
));
422 ccode
.add_assignment (new
CCodeIdentifier (func_name
), new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (block_id
)), func_name
));
424 } else if (m
.parent_symbol is Class
&& !m
.coroutine
) {
425 var cl
= (Class
) m
.parent_symbol
;
426 if (m
.overrides
|| (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
)) {
428 ReferenceType base_expression_type
;
430 base_method
= m
.base_method
;
431 base_expression_type
= new
ObjectType ((Class
) base_method
.parent_symbol
);
433 base_method
= m
.base_interface_method
;
434 base_expression_type
= new
ObjectType ((Interface
) base_method
.parent_symbol
);
436 var self_target_type
= new
ObjectType (cl
);
437 CCodeExpression cself
= transform_expression (new
CCodeIdentifier ("base"), base_expression_type
, self_target_type
);
439 ccode
.add_declaration ("%s *".printf (cl
.get_cname ()), new
CCodeVariableDeclarator ("self"));
440 ccode
.add_assignment (new
CCodeIdentifier ("self"), cself
);
441 } else if (m
.binding
== MemberBinding
.INSTANCE
442 && !(m is CreationMethod
)) {
443 create_method_type_check_statement (m
, creturn_type
, cl
, true, "self");
447 foreach (Parameter param
in m
.get_parameters ()) {
448 if (param
.ellipsis
) {
452 if (param
.direction
!= ParameterDirection
.OUT
) {
453 var t
= param
.variable_type
.data_type
;
454 if (t
!= null && t
.is_reference_type ()) {
455 create_method_type_check_statement (m
, creturn_type
, t
, !param
.variable_type
.nullable
, get_variable_cname (param
.name
));
457 } else if (!m
.coroutine
) {
458 // declare local variable for out parameter to allow assignment even when caller passes NULL
459 var vardecl
= new CCodeVariableDeclarator
.zero (get_variable_cname ("_" + param
.name
), default_value_for_type (param
.variable_type
, true));
460 ccode
.add_declaration (param
.variable_type
.get_cname (), vardecl
);
462 if (param
.variable_type is ArrayType
) {
463 // create variables to store array dimensions
464 var array_type
= (ArrayType
) param
.variable_type
;
466 if (!array_type
.fixed_length
) {
467 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
468 vardecl
= new CCodeVariableDeclarator
.zero (get_array_length_cname (get_variable_cname ("_" + param
.name
), dim
), new
CCodeConstant ("0"));
469 ccode
.add_declaration ("int", vardecl
);
472 } else if (param
.variable_type is DelegateType
) {
473 var deleg_type
= (DelegateType
) param
.variable_type
;
474 var d
= deleg_type
.delegate_symbol
;
476 // create variable to store delegate target
477 vardecl
= new CCodeVariableDeclarator
.zero (get_delegate_target_cname (get_variable_cname ("_" + param
.name
)), new
CCodeConstant ("NULL"));
478 ccode
.add_declaration ("void *", vardecl
);
480 if (deleg_type
.value_owned
) {
481 vardecl
= new CCodeVariableDeclarator
.zero (get_delegate_target_destroy_notify_cname (get_variable_cname ("_" + param
.name
)), new
CCodeConstant ("NULL"));
482 ccode
.add_declaration ("GDestroyNotify", vardecl
);
489 if (!(m
.return_type is VoidType
) && !m
.return_type
.is_real_non_null_struct_type () && !m
.coroutine
) {
490 var vardecl
= new
CCodeVariableDeclarator ("result", default_value_for_type (m
.return_type
, true));
491 vardecl
.init0
= true;
492 ccode
.add_declaration (m
.return_type
.get_cname (), vardecl
);
495 if (m is CreationMethod
) {
496 if (in_gobject_creation_method
) {
497 ccode
.add_declaration ("%s *".printf (((Class
) current_type_symbol
).get_cname ()), new CCodeVariableDeclarator
.zero ("self", new
CCodeConstant ("NULL")));
498 } else if (is_gtypeinstance_creation_method (m
)) {
499 var cl
= (Class
) m
.parent_symbol
;
500 ccode
.add_declaration (cl
.get_cname () + "*", new CCodeVariableDeclarator
.zero ("self", new
CCodeConstant ("NULL")));
502 if (cl
.is_fundamental ()) {
503 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_type_create_instance"));
504 ccall
.add_argument (new
CCodeIdentifier ("object_type"));
505 ccode
.add_assignment (new
CCodeIdentifier ("self"), new
CCodeCastExpression (ccall
, cl
.get_cname () + "*"));
507 /* type, dup func, and destroy func fields for generic types */
508 foreach (TypeParameter type_param
in current_class
.get_type_parameters ()) {
509 CCodeIdentifier param_name
;
510 CCodeAssignment assign
;
512 var priv_access
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv");
514 param_name
= new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ()));
515 assign
= new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
);
516 ccode
.add_expression (assign
);
518 param_name
= new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ()));
519 assign
= new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
);
520 ccode
.add_expression (assign
);
522 param_name
= new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ()));
523 assign
= new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
);
524 ccode
.add_expression (assign
);
527 } else if (current_type_symbol is Class
) {
528 var cl
= (Class
) m
.parent_symbol
;
529 ccode
.add_declaration (cl
.get_cname () + "*", new
CCodeVariableDeclarator ("self"));
531 if (!((CreationMethod
) m
).chain_up
) {
532 // TODO implicitly chain up to base class as in add_object_creation
533 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_new0"));
534 ccall
.add_argument (new
CCodeIdentifier (cl
.get_cname ()));
535 ccode
.add_assignment (new
CCodeIdentifier ("self"), ccall
);
538 if (cl
.base_class
== null) {
539 // derived compact classes do not have fields
540 var cinitcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_instance_init".printf (cl
.get_lower_case_cname (null))));
541 cinitcall
.add_argument (new
CCodeIdentifier ("self"));
542 ccode
.add_expression (cinitcall
);
545 var st
= (Struct
) m
.parent_symbol
;
547 // memset needs string.h
548 cfile
.add_include ("string.h");
549 var czero
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
550 czero
.add_argument (new
CCodeIdentifier ("self"));
551 czero
.add_argument (new
CCodeConstant ("0"));
552 czero
.add_argument (new
CCodeIdentifier ("sizeof (%s)".printf (st
.get_cname ())));
553 ccode
.add_expression (czero
);
557 if (context
.module_init_method
== m
&& in_plugin
) {
558 // GTypeModule-based plug-in, register types
559 register_plugin_types (context
.root
, new HashSet
<Symbol
> ());
562 foreach (Expression precondition
in m
.get_preconditions ()) {
563 create_precondition_statement (m
, creturn_type
, precondition
);
568 if (m
.body
!= null) {
572 // generate *_real_* functions for virtual methods
573 // also generate them for abstract methods of classes to prevent faulty subclassing
574 if (!m
.is_abstract
|| (m
.is_abstract
&& current_type_symbol is Class
)) {
575 /* Methods imported from a plain C file don't
576 * have a body, e.g. Vala.Parser.parse_file () */
577 if (m
.body
!= null) {
578 if (current_method_inner_error
) {
579 /* always separate error parameter and inner_error local variable
580 * as error may be set to NULL but we're always interested in inner errors
583 closure_struct
.add_field ("GError *", "_inner_error_");
585 // no initialization necessary, closure struct is zeroed
587 ccode
.add_declaration ("GError *", new CCodeVariableDeclarator
.zero ("_inner_error_", new
CCodeConstant ("NULL")));
596 if (!(m
.return_type is VoidType
) && !m
.return_type
.is_real_non_null_struct_type () && !m
.coroutine
) {
597 // add dummy return if exit block is known to be unreachable to silence C compiler
598 if (m
.return_block
!= null && m
.return_block
.get_predecessors ().size
== 0) {
599 ccode
.add_return (new
CCodeIdentifier ("result"));
603 if (m is CreationMethod
) {
604 if (current_type_symbol is Class
) {
605 creturn_type
= new
ObjectType (current_class
);
607 creturn_type
= new
VoidType ();
611 if (current_type_symbol is Class
&& gobject_type
!= null && current_class
.is_subtype_of (gobject_type
)
612 && current_class
.get_type_parameters ().size
> 0
613 && !((CreationMethod
) m
).chain_up
) {
614 var ccond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.GREATER_THAN
, new
CCodeIdentifier ("__params_it"), new
CCodeIdentifier ("__params"));
615 var cdofreeparam
= new
CCodeBlock ();
616 cdofreeparam
.add_statement (new
CCodeExpressionStatement (new
CCodeUnaryExpression (CCodeUnaryOperator
.PREFIX_DECREMENT
, new
CCodeIdentifier ("__params_it"))));
617 var cunsetcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_unset"));
618 cunsetcall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("__params_it"), "value")));
619 cdofreeparam
.add_statement (new
CCodeExpressionStatement (cunsetcall
));
620 ccode
.add_statement (new
CCodeWhileStatement (ccond
, cdofreeparam
));
622 var cfreeparams
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_free"));
623 cfreeparams
.add_argument (new
CCodeIdentifier ("__params"));
624 ccode
.add_expression (cfreeparams
);
627 if (current_type_symbol is Class
) {
628 CCodeExpression cresult
= new
CCodeIdentifier ("self");
629 if (get_custom_creturn_type (m
) != null) {
630 cresult
= new
CCodeCastExpression (cresult
, get_custom_creturn_type (m
));
633 ccode
.add_return (cresult
);
637 cfile
.add_function (ccode
);
641 if (m
.is_abstract
&& current_type_symbol is Class
) {
642 // generate helpful error message if a sublcass does not implement an abstract method.
643 // This is only meaningful for subclasses implemented in C since the vala compiler would
644 // complain during compile time of such en error.
646 // add a typecheck statement for "self"
647 create_method_type_check_statement (m
, creturn_type
, current_type_symbol
, true, "self");
649 // add critical warning that this method should not have been called
650 var type_from_instance_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_TYPE_FROM_INSTANCE"));
651 type_from_instance_call
.add_argument (new
CCodeIdentifier ("self"));
653 var type_name_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_type_name"));
654 type_name_call
.add_argument (type_from_instance_call
);
656 var error_string
= "\"Type `%%s' does not implement abstract method `%s'\"".printf (m
.get_cname ());
658 var cerrorcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_critical"));
659 cerrorcall
.add_argument (new
CCodeConstant (error_string
));
660 cerrorcall
.add_argument (type_name_call
);
662 ccode
.add_expression (cerrorcall
);
664 // add return statement
665 return_default_value (creturn_type
);
667 cfile
.add_function (ccode
);
671 in_static_or_class_context
= false;
675 if ((m
.is_abstract
|| m
.is_virtual
) && !m
.coroutine
&&
676 /* If the method is a signal handler, the declaration
677 * is not needed. -- the name should be reserved for the
679 m
.signal_reference
== null) {
681 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
682 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
684 generate_vfunc (m
, creturn_type
, cparam_map
, carg_map
);
688 // m is possible entry point, add appropriate startup code
689 var cmain
= new
CCodeFunction ("main", "int");
690 cmain
.line
= function
.line
;
691 cmain
.add_parameter (new
CCodeParameter ("argc", "int"));
692 cmain
.add_parameter (new
CCodeParameter ("argv", "char **"));
693 var main_block
= new
CCodeBlock ();
695 if (context
.profile
== Profile
.GOBJECT
) {
696 if (context
.mem_profiler
) {
697 var mem_profiler_init_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_mem_set_vtable"));
698 mem_profiler_init_call
.line
= cmain
.line
;
699 mem_profiler_init_call
.add_argument (new
CCodeConstant ("glib_mem_profiler_table"));
700 main_block
.add_statement (new
CCodeExpressionStatement (mem_profiler_init_call
));
703 if (context
.thread
) {
704 var thread_init_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_thread_init"));
705 thread_init_call
.line
= cmain
.line
;
706 thread_init_call
.add_argument (new
CCodeConstant ("NULL"));
707 main_block
.add_statement (new
CCodeExpressionStatement (thread_init_call
));
710 var type_init_call
= new
CCodeExpressionStatement (new
CCodeFunctionCall (new
CCodeIdentifier ("g_type_init")));
711 type_init_call
.line
= cmain
.line
;
712 main_block
.add_statement (type_init_call
);
715 var main_call
= new
CCodeFunctionCall (new
CCodeIdentifier (function
.name
));
716 if (m
.get_parameters ().size
== 1) {
717 main_call
.add_argument (new
CCodeIdentifier ("argv"));
718 main_call
.add_argument (new
CCodeIdentifier ("argc"));
720 if (m
.return_type is VoidType
) {
721 // method returns void, always use 0 as exit code
722 var main_stmt
= new
CCodeExpressionStatement (main_call
);
723 main_stmt
.line
= cmain
.line
;
724 main_block
.add_statement (main_stmt
);
725 var ret_stmt
= new
CCodeReturnStatement (new
CCodeConstant ("0"));
726 ret_stmt
.line
= cmain
.line
;
727 main_block
.add_statement (ret_stmt
);
729 var main_stmt
= new
CCodeReturnStatement (main_call
);
730 main_stmt
.line
= cmain
.line
;
731 main_block
.add_statement (main_stmt
);
733 cmain
.block
= main_block
;
734 cfile
.add_function (cmain
);
738 public virtual CCodeParameter
generate_parameter (Parameter param
, CCodeFile decl_space
, Map
<int,CCodeParameter
> cparam_map
, Map
<int,CCodeExpression
>? carg_map
) {
739 CCodeParameter cparam
;
740 if (!param
.ellipsis
) {
741 string ctypename
= param
.variable_type
.get_cname ();
743 generate_type_declaration (param
.variable_type
, decl_space
);
745 // pass non-simple structs always by reference
746 if (param
.variable_type
.data_type is Struct
) {
747 var st
= (Struct
) param
.variable_type
.data_type
;
748 if (!st
.is_simple_type () && param
.direction
== ParameterDirection
.IN
) {
749 if (st
.is_immutable
&& !param
.variable_type
.value_owned
) {
750 ctypename
= "const " + ctypename
;
753 if (!param
.variable_type
.nullable
) {
759 if (param
.direction
!= ParameterDirection
.IN
) {
763 cparam
= new
CCodeParameter (get_variable_cname (param
.name
), ctypename
);
765 cparam
= new CCodeParameter
.with_ellipsis ();
768 cparam_map
.set (get_param_pos (param
.cparameter_position
, param
.ellipsis
), cparam
);
769 if (carg_map
!= null && !param
.ellipsis
) {
770 carg_map
.set (get_param_pos (param
.cparameter_position
, param
.ellipsis
), get_variable_cexpression (param
.name
));
776 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) {
778 var closure_block
= current_closure_block
;
779 int block_id
= get_block_id (closure_block
);
780 var instance_param
= new
CCodeParameter ("_data%d_".printf (block_id
), "Block%dData*".printf (block_id
));
781 cparam_map
.set (get_param_pos (m
.cinstance_parameter_position
), instance_param
);
782 } else if (m
.parent_symbol is Class
&& m is CreationMethod
) {
783 var cl
= (Class
) m
.parent_symbol
;
784 if (!cl
.is_compact
&& vcall
== null) {
785 cparam_map
.set (get_param_pos (m
.cinstance_parameter_position
), new
CCodeParameter ("object_type", "GType"));
787 } else if (m
.binding
== MemberBinding
.INSTANCE
|| (m
.parent_symbol is Struct
&& m is CreationMethod
)) {
788 TypeSymbol parent_type
= find_parent_type (m
);
790 if (parent_type is Class
) {
791 this_type
= new
ObjectType ((Class
) parent_type
);
792 } else if (parent_type is Interface
) {
793 this_type
= new
ObjectType ((Interface
) parent_type
);
794 } else if (parent_type is Struct
) {
795 this_type
= new
StructValueType ((Struct
) parent_type
);
796 } else if (parent_type is Enum
) {
797 this_type
= new
EnumValueType ((Enum
) parent_type
);
799 assert_not_reached ();
802 generate_type_declaration (this_type
, decl_space
);
804 CCodeParameter instance_param
= null;
805 if (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
) {
806 var base_type
= new
ObjectType ((Interface
) m
.base_interface_method
.parent_symbol
);
807 instance_param
= new
CCodeParameter ("base", base_type
.get_cname ());
808 } else if (m
.overrides
) {
809 var base_type
= new
ObjectType ((Class
) m
.base_method
.parent_symbol
);
810 instance_param
= new
CCodeParameter ("base", base_type
.get_cname ());
812 if (m
.parent_symbol is Struct
&& !((Struct
) m
.parent_symbol
).is_simple_type ()) {
813 instance_param
= new
CCodeParameter ("*self", this_type
.get_cname ());
815 instance_param
= new
CCodeParameter ("self", this_type
.get_cname ());
818 cparam_map
.set (get_param_pos (m
.cinstance_parameter_position
), instance_param
);
819 } else if (m
.binding
== MemberBinding
.CLASS
) {
820 TypeSymbol parent_type
= find_parent_type (m
);
822 this_type
= new
ClassType ((Class
) parent_type
);
823 var class_param
= new
CCodeParameter ("klass", this_type
.get_cname ());
824 cparam_map
.set (get_param_pos (m
.cinstance_parameter_position
), class_param
);
827 if (is_gtypeinstance_creation_method (m
)) {
828 // memory management for generic types
829 int type_param_index
= 0;
830 var cl
= (Class
) m
.parent_symbol
;
831 foreach (TypeParameter type_param
in cl
.get_type_parameters ()) {
832 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeParameter ("%s_type".printf (type_param
.name
.down ()), "GType"));
833 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeParameter ("%s_dup_func".printf (type_param
.name
.down ()), "GBoxedCopyFunc"));
834 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeParameter ("%s_destroy_func".printf (type_param
.name
.down ()), "GDestroyNotify"));
835 if (carg_map
!= null) {
836 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ())));
837 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ())));
838 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ())));
842 } else if (!m
.closure
) {
843 int type_param_index
= 0;
844 foreach (var type_param
in m
.get_type_parameters ()) {
845 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeParameter ("%s_type".printf (type_param
.name
.down ()), "GType"));
846 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeParameter ("%s_dup_func".printf (type_param
.name
.down ()), "GBoxedCopyFunc"));
847 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeParameter ("%s_destroy_func".printf (type_param
.name
.down ()), "GDestroyNotify"));
848 if (carg_map
!= null) {
849 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ())));
850 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ())));
851 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ())));
857 foreach (Parameter param
in m
.get_parameters ()) {
858 if (param
.direction
!= ParameterDirection
.OUT
) {
859 if ((direction
& 1) == 0) {
864 if ((direction
& 2) == 0) {
870 generate_parameter (param
, decl_space
, cparam_map
, carg_map
);
873 if ((direction
& 2) != 0) {
874 generate_method_result_declaration (m
, decl_space
, func
, cparam_map
, carg_map
);
877 // append C parameters in the right order
882 foreach (int pos
in cparam_map
.get_keys ()) {
883 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
890 func
.add_parameter (cparam_map
.get (min_pos
));
891 if (vdeclarator
!= null) {
892 vdeclarator
.add_parameter (cparam_map
.get (min_pos
));
895 var arg
= carg_map
.get (min_pos
);
897 vcall
.add_argument (arg
);
904 public void generate_vfunc (Method m
, DataType return_type
, Map
<int,CCodeParameter
> cparam_map
, Map
<int,CCodeExpression
> carg_map
, string suffix
= "", int direction
= 3) {
905 push_context (new
EmitContext ());
907 string cname
= m
.get_cname ();
908 if (suffix
== "_finish" && cname
.has_suffix ("_async")) {
909 cname
= cname
.substring (0, cname
.length
- "_async".length
);
911 var vfunc
= new
CCodeFunction (cname
+ suffix
);
913 CCodeFunctionCall vcast
= null;
914 if (m
.parent_symbol is Interface
) {
915 var iface
= (Interface
) m
.parent_symbol
;
917 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_INTERFACE".printf (iface
.get_upper_case_cname (null))));
919 var cl
= (Class
) m
.parent_symbol
;
921 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS".printf (cl
.get_upper_case_cname (null))));
923 vcast
.add_argument (new
CCodeIdentifier ("self"));
925 cname
= m
.vfunc_name
;
926 if (suffix
== "_finish" && cname
.has_suffix ("_async")) {
927 cname
= cname
.substring (0, cname
.length
- "_async".length
);
929 var vcall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, cname
+ suffix
));
930 carg_map
.set (get_param_pos (m
.cinstance_parameter_position
), new
CCodeIdentifier ("self"));
932 generate_cparameters (m
, cfile
, cparam_map
, vfunc
, null, carg_map
, vcall
, direction
);
934 push_function (vfunc
);
936 foreach (Expression precondition
in m
.get_preconditions ()) {
937 create_precondition_statement (m
, return_type
, precondition
);
940 if (return_type is VoidType
|| return_type
.is_real_non_null_struct_type ()) {
941 ccode
.add_expression (vcall
);
942 } else if (m
.get_postconditions ().size
== 0) {
943 /* pass method return value */
944 ccode
.add_return (vcall
);
946 /* store method return value for postconditions */
947 ccode
.add_declaration (get_creturn_type (m
, return_type
.get_cname ()), new
CCodeVariableDeclarator ("result"));
948 ccode
.add_assignment (new
CCodeIdentifier ("result"), vcall
);
951 if (m
.get_postconditions ().size
> 0) {
952 foreach (Expression postcondition
in m
.get_postconditions ()) {
953 create_postcondition_statement (postcondition
);
956 if (!(return_type is VoidType
)) {
957 ccode
.add_return (new
CCodeIdentifier ("result"));
961 cfile
.add_function (vfunc
);
966 private void create_method_type_check_statement (Method m
, DataType return_type
, TypeSymbol t
, bool non_null
, string var_name
) {
968 create_type_check_statement (m
, return_type
, t
, non_null
, var_name
);
972 private void create_precondition_statement (CodeNode method_node
, DataType ret_type
, Expression precondition
) {
973 var ccheck
= new
CCodeFunctionCall ();
975 precondition
.emit (this
);
977 ccheck
.add_argument (get_cvalue (precondition
));
979 if (method_node is CreationMethod
) {
980 ccheck
.call
= new
CCodeIdentifier ("g_return_val_if_fail");
981 ccheck
.add_argument (new
CCodeConstant ("NULL"));
982 } else if (method_node is Method
&& ((Method
) method_node
).coroutine
) {
984 ccheck
.call
= new
CCodeIdentifier ("g_return_val_if_fail");
985 ccheck
.add_argument (new
CCodeConstant ("FALSE"));
986 } else if (ret_type is VoidType
) {
988 ccheck
.call
= new
CCodeIdentifier ("g_return_if_fail");
990 ccheck
.call
= new
CCodeIdentifier ("g_return_val_if_fail");
992 var cdefault
= default_value_for_type (ret_type
, false);
993 if (cdefault
!= null) {
994 ccheck
.add_argument (cdefault
);
1000 ccode
.add_expression (ccheck
);
1003 private TypeSymbol?
find_parent_type (Symbol sym
) {
1004 while (sym
!= null) {
1005 if (sym is TypeSymbol
) {
1006 return (TypeSymbol
) sym
;
1008 sym
= sym
.parent_symbol
;
1013 public override void visit_creation_method (CreationMethod m
) {
1014 bool visible
= !m
.is_private_symbol ();
1018 if (m
.source_type
== SourceFileType
.FAST
) {
1022 // do not generate _new functions for creation methods of abstract classes
1023 if (current_type_symbol is Class
&& !current_class
.is_compact
&& !current_class
.is_abstract
) {
1024 var vfunc
= new
CCodeFunction (m
.get_cname ());
1026 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
1027 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
1029 var vblock
= new
CCodeBlock ();
1031 var vcall
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_real_cname ()));
1032 vcall
.add_argument (new
CCodeIdentifier (current_class
.get_type_id ()));
1034 generate_cparameters (m
, cfile
, cparam_map
, vfunc
, null, carg_map
, vcall
);
1035 CCodeStatement cstmt
= new
CCodeReturnStatement (vcall
);
1036 cstmt
.line
= vfunc
.line
;
1037 vblock
.add_statement (cstmt
);
1040 vfunc
.modifiers
|= CCodeModifiers
.STATIC
;
1043 vfunc
.block
= vblock
;
1045 cfile
.add_function (vfunc
);