1 /* valaccodemethodmodule.vala
3 * Copyright (C) 2007-2009 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Jürg Billeter <j@bitron.ch>
21 * Raffaele Sandrini <raffaele@sandrini.ch>
28 * The link between a method and generated code.
30 internal class Vala
.CCodeMethodModule
: CCodeStructModule
{
31 public CCodeMethodModule (CCodeGenerator codegen
, CCodeModule? next
) {
35 public override bool method_has_wrapper (Method method
) {
36 return (method
.get_attribute ("NoWrapper") == null);
39 public override string?
get_custom_creturn_type (Method m
) {
40 var attr
= m
.get_attribute ("CCode");
42 string type
= attr
.get_string ("type");
50 string get_creturn_type (Method m
, string default_value
) {
51 string type
= get_custom_creturn_type (m
);
58 bool is_gtypeinstance_creation_method (Method m
) {
61 var cl
= m
.parent_symbol as Class
;
62 if (m is CreationMethod
&& cl
!= null && !cl
.is_compact
) {
69 public virtual void generate_method_result_declaration (Method m
, CCodeDeclarationSpace decl_space
, CCodeFunction cfunc
, Map
<int,CCodeFormalParameter
> cparam_map
, Map
<int,CCodeExpression
>? carg_map
) {
70 var creturn_type
= m
.return_type
;
71 if (m is CreationMethod
) {
72 var cl
= m
.parent_symbol as Class
;
74 // object creation methods return the new object in C
75 // in Vala they have no return type
76 creturn_type
= new
ObjectType (cl
);
79 cfunc
.return_type
= get_creturn_type (m
, creturn_type
.get_cname ());
81 generate_type_declaration (m
.return_type
, decl_space
);
83 if (!m
.no_array_length
&& m
.return_type is ArrayType
) {
84 // return array length if appropriate
85 var array_type
= (ArrayType
) m
.return_type
;
87 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
88 var cparam
= new
CCodeFormalParameter (head
.get_array_length_cname ("result", dim
), "int*");
89 cparam_map
.set (get_param_pos (m
.carray_length_parameter_position
+ 0.01 * dim
), cparam
);
90 if (carg_map
!= null) {
91 carg_map
.set (get_param_pos (m
.carray_length_parameter_position
+ 0.01 * dim
), get_variable_cexpression (cparam
.name
));
94 } else if (m
.return_type is DelegateType
) {
95 // return delegate target if appropriate
96 var deleg_type
= (DelegateType
) m
.return_type
;
97 var d
= deleg_type
.delegate_symbol
;
99 var cparam
= new
CCodeFormalParameter (get_delegate_target_cname ("result"), "void**");
100 cparam_map
.set (get_param_pos (m
.cdelegate_target_parameter_position
), cparam
);
101 if (carg_map
!= null) {
102 carg_map
.set (get_param_pos (m
.cdelegate_target_parameter_position
), get_variable_cexpression (cparam
.name
));
107 if (m
.get_error_types ().size
> 0 || (m
.base_method
!= null && m
.base_method
.get_error_types ().size
> 0)) {
108 foreach (DataType error_type
in m
.get_error_types ()) {
109 generate_type_declaration (error_type
, decl_space
);
112 var cparam
= new
CCodeFormalParameter ("error", "GError**");
113 cparam_map
.set (get_param_pos (-1), cparam
);
114 if (carg_map
!= null) {
115 carg_map
.set (get_param_pos (-1), new
CCodeIdentifier (cparam
.name
));
120 public CCodeStatement
complete_async () {
121 var complete_block
= new
CCodeBlock ();
123 var direct_block
= new
CCodeBlock ();
124 var direct_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_simple_async_result_complete"));
125 var async_result_expr
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "_async_result");
126 direct_call
.add_argument (async_result_expr
);
127 direct_block
.add_statement (new
CCodeExpressionStatement (direct_call
));
129 var idle_block
= new
CCodeBlock ();
130 var idle_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_simple_async_result_complete_in_idle"));
131 idle_call
.add_argument (async_result_expr
);
132 idle_block
.add_statement (new
CCodeExpressionStatement (idle_call
));
134 var state
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "state");
135 var zero
= new
CCodeConstant ("0");
136 var state_is_zero
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, state
, zero
);
137 var dispatch
= new
CCodeIfStatement (state_is_zero
, idle_block
, direct_block
);
138 complete_block
.add_statement (dispatch
);
140 var unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_unref"));
141 unref
.add_argument (async_result_expr
);
142 complete_block
.add_statement (new
CCodeExpressionStatement (unref
));
144 complete_block
.add_statement (new
CCodeReturnStatement (new
CCodeConstant ("FALSE")));
146 return complete_block
;
149 public override void generate_method_declaration (Method m
, CCodeDeclarationSpace decl_space
) {
150 if (m
.is_async_callback
) {
153 if (decl_space
.add_symbol_declaration (m
, m
.get_cname ())) {
157 var function
= new
CCodeFunction (m
.get_cname ());
159 if (m
.is_private_symbol ()) {
160 function
.modifiers
|= CCodeModifiers
.STATIC
;
162 function
.modifiers
|= CCodeModifiers
.INLINE
;
166 var cparam_map
= new HashMap
<int,CCodeFormalParameter
> (direct_hash
, direct_equal
);
167 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
169 var cl
= m
.parent_symbol as Class
;
171 // do not generate _new functions for creation methods of abstract classes
172 if (!(m is CreationMethod
&& cl
!= null && cl
.is_abstract
)) {
173 generate_cparameters (m
, decl_space
, cparam_map
, function
, null, carg_map
, new
CCodeFunctionCall (new
CCodeIdentifier ("fake")));
175 decl_space
.add_type_member_declaration (function
);
178 if (m is CreationMethod
&& cl
!= null) {
179 // _construct function
180 function
= new
CCodeFunction (m
.get_real_cname ());
182 if (m
.is_private_symbol ()) {
183 function
.modifiers
|= CCodeModifiers
.STATIC
;
186 cparam_map
= new HashMap
<int,CCodeFormalParameter
> (direct_hash
, direct_equal
);
187 generate_cparameters (m
, decl_space
, cparam_map
, function
);
189 decl_space
.add_type_member_declaration (function
);
193 public override void visit_method (Method m
) {
194 var old_symbol
= current_symbol
;
195 bool old_method_inner_error
= current_method_inner_error
;
196 int old_next_temp_var_id
= next_temp_var_id
;
197 var old_temp_vars
= temp_vars
;
198 var old_temp_ref_vars
= temp_ref_vars
;
199 var old_variable_name_map
= variable_name_map
;
200 var old_try
= current_try
;
202 current_method_inner_error
= false;
203 next_temp_var_id
= 0;
204 temp_vars
= new ArrayList
<LocalVariable
> ();
205 temp_ref_vars
= new ArrayList
<LocalVariable
> ();
206 variable_name_map
= new HashMap
<string,string> (str_hash
, str_equal
);
209 bool in_gobject_creation_method
= false;
210 bool in_fundamental_creation_method
= false;
212 check_type (m
.return_type
);
214 if (m is CreationMethod
) {
215 var cl
= current_type_symbol as Class
;
216 if (cl
!= null && !cl
.is_compact
) {
217 if (cl
.base_class
== null) {
218 in_fundamental_creation_method
= true;
219 } else if (gobject_type
!= null && cl
.is_subtype_of (gobject_type
)) {
220 in_gobject_creation_method
= true;
225 var creturn_type
= current_return_type
;
227 if (m
.binding
== MemberBinding
.CLASS
|| m
.binding
== MemberBinding
.STATIC
) {
228 in_static_or_class_context
= true;
230 m
.accept_children (codegen
);
231 in_static_or_class_context
= false;
233 if (m is CreationMethod
) {
234 if (in_gobject_creation_method
&& m
.body
!= null) {
235 var cblock
= new
CCodeBlock ();
237 // last property assignment statement
238 CodeNode last_stmt
= null;
240 if (!((CreationMethod
) m
).chain_up
) {
241 // set construct properties
242 foreach (CodeNode stmt
in m
.body
.get_statements ()) {
243 var expr_stmt
= stmt as ExpressionStatement
;
244 if (expr_stmt
!= null) {
245 var prop
= expr_stmt
.assigned_property ();
246 if (prop
!= null && prop
.set_accessor
.construction
) {
251 if (last_stmt
!= null) {
252 foreach (CodeNode stmt
in m
.body
.get_statements ()) {
253 if (stmt
.ccodenode is CCodeFragment
) {
254 foreach (CCodeNode cstmt
in ((CCodeFragment
) stmt
.ccodenode
).get_children ()) {
255 cblock
.add_statement (cstmt
);
258 cblock
.add_statement (stmt
.ccodenode
);
260 if (last_stmt
== stmt
) {
266 add_object_creation (cblock
, ((CreationMethod
) m
).n_construction_params
> 0 || current_class
.get_type_parameters ().size
> 0);
268 var cdeclaration
= new
CCodeDeclaration ("%s *".printf (((Class
) current_type_symbol
).get_cname ()));
269 cdeclaration
.add_declarator (new
CCodeVariableDeclarator ("self"));
271 cblock
.add_statement (cdeclaration
);
274 // other initialization code
275 foreach (CodeNode stmt
in m
.body
.get_statements ()) {
276 if (last_stmt
!= null) {
277 if (last_stmt
== stmt
) {
282 if (stmt
.ccodenode is CCodeFragment
) {
283 foreach (CCodeNode cstmt
in ((CCodeFragment
) stmt
.ccodenode
).get_children ()) {
284 cblock
.add_statement (cstmt
);
287 cblock
.add_statement (stmt
.ccodenode
);
291 foreach (LocalVariable local
in m
.body
.get_local_variables ()) {
292 if (!local
.floating
&& requires_destroy (local
.variable_type
)) {
293 var ma
= new MemberAccess
.simple (local
.name
);
294 ma
.symbol_reference
= local
;
295 cblock
.add_statement (new
CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local
.name
), local
.variable_type
, ma
)));
299 m
.body
.ccodenode
= cblock
;
303 bool inner_error
= current_method_inner_error
;
305 current_symbol
= old_symbol
;
306 current_method_inner_error
= old_method_inner_error
;
307 next_temp_var_id
= old_next_temp_var_id
;
308 temp_vars
= old_temp_vars
;
309 temp_ref_vars
= old_temp_ref_vars
;
310 variable_name_map
= old_variable_name_map
;
311 current_try
= old_try
;
313 // do not declare overriding methods and interface implementations
314 if (m
.is_abstract
|| m
.is_virtual
315 || (m
.base_method
== null && m
.base_interface_method
== null)) {
316 generate_method_declaration (m
, source_declarations
);
318 if (!m
.is_internal_symbol ()) {
319 generate_method_declaration (m
, header_declarations
);
321 generate_method_declaration (m
, internal_header_declarations
);
324 function
= new
CCodeFunction (m
.get_real_cname ());
325 m
.ccodenode
= function
;
328 function
.modifiers
|= CCodeModifiers
.INLINE
;
331 var cparam_map
= new HashMap
<int,CCodeFormalParameter
> (direct_hash
, direct_equal
);
333 generate_cparameters (m
, source_declarations
, cparam_map
, function
);
335 // generate *_real_* functions for virtual methods
336 // also generate them for abstract methods of classes to prevent faulty subclassing
337 if (!m
.is_abstract
|| (m
.is_abstract
&& current_type_symbol is Class
)) {
339 if (m
.base_method
!= null || m
.base_interface_method
!= null) {
340 // declare *_real_* function
341 function
.modifiers
|= CCodeModifiers
.STATIC
;
342 source_declarations
.add_type_member_declaration (function
.copy ());
343 } else if (m
.is_private_symbol ()) {
344 function
.modifiers
|= CCodeModifiers
.STATIC
;
348 /* Methods imported from a plain C file don't
349 * have a body, e.g. Vala.Parser.parse_file () */
350 if (m
.body
!= null) {
351 function
.block
= (CCodeBlock
) m
.body
.ccodenode
;
352 function
.block
.line
= function
.line
;
354 var cinit
= new
CCodeFragment ();
355 function
.block
.prepend_statement (cinit
);
358 var co_function
= new
CCodeFunction (m
.get_real_cname () + "_co", "gboolean");
360 // data struct to hold parameters, local variables, and the return value
361 co_function
.add_parameter (new
CCodeFormalParameter ("data", Symbol
.lower_case_to_camel_case (m
.get_cname ()) + "Data*"));
363 co_function
.modifiers
|= CCodeModifiers
.STATIC
;
364 source_declarations
.add_type_member_declaration (co_function
.copy ());
366 var cswitch
= new
CCodeSwitchStatement (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "state"));
368 // let gcc know that this can't happen
369 cswitch
.add_statement (new
CCodeLabel ("default"));
370 cswitch
.add_statement (new
CCodeExpressionStatement (new
CCodeFunctionCall (new
CCodeIdentifier ("g_assert_not_reached"))));
372 // initial coroutine state
373 cswitch
.add_statement (new
CCodeCaseStatement (new
CCodeConstant ("0")));
376 cswitch
.add_statement (function
.block
);
379 cswitch
.add_statement (complete_async ());
381 co_function
.block
= new
CCodeBlock ();
382 co_function
.block
.add_statement (cswitch
);
384 source_type_member_definition
.append (co_function
);
387 if (m
.parent_symbol is Class
&& !m
.coroutine
) {
388 var cl
= (Class
) m
.parent_symbol
;
389 if (m
.overrides
|| (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
)) {
391 ReferenceType base_expression_type
;
393 base_method
= m
.base_method
;
394 base_expression_type
= new
ObjectType ((Class
) base_method
.parent_symbol
);
396 base_method
= m
.base_interface_method
;
397 base_expression_type
= new
ObjectType ((Interface
) base_method
.parent_symbol
);
399 var self_target_type
= new
ObjectType (cl
);
400 CCodeExpression cself
= transform_expression (new
CCodeIdentifier ("base"), base_expression_type
, self_target_type
);
402 var cdecl
= new
CCodeDeclaration ("%s *".printf (cl
.get_cname ()));
403 cdecl
.add_declarator (new
CCodeVariableDeclarator ("self", cself
));
405 cinit
.append (cdecl
);
406 } else if (m
.binding
== MemberBinding
.INSTANCE
407 && !(m is CreationMethod
)) {
408 var ccheckstmt
= create_method_type_check_statement (m
, creturn_type
, cl
, true, "self");
409 if (ccheckstmt
!= null) {
410 ccheckstmt
.line
= function
.line
;
411 cinit
.append (ccheckstmt
);
415 foreach (FormalParameter param
in m
.get_parameters ()) {
416 if (param
.ellipsis
) {
420 var t
= param
.parameter_type
.data_type
;
421 if (t
!= null && t
.is_reference_type ()) {
422 if (param
.direction
!= ParameterDirection
.OUT
) {
423 var type_check
= create_method_type_check_statement (m
, creturn_type
, t
, !param
.parameter_type
.nullable
, get_variable_cname (param
.name
));
424 if (type_check
!= null) {
425 type_check
.line
= function
.line
;
426 cinit
.append (type_check
);
429 // ensure that the passed reference for output parameter is cleared
430 var a
= new
CCodeAssignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_variable_cexpression (param
.name
)), new
CCodeConstant ("NULL"));
431 var cblock
= new
CCodeBlock ();
432 cblock
.add_statement (new
CCodeExpressionStatement (a
));
434 var condition
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, get_variable_cexpression (param
.name
), new
CCodeConstant ("NULL"));
435 var if_statement
= new
CCodeIfStatement (condition
, cblock
);
436 cinit
.append (if_statement
);
441 if (!(m
.return_type is VoidType
) && !m
.coroutine
) {
442 var cdecl
= new
CCodeDeclaration (m
.return_type
.get_cname ());
443 cdecl
.add_declarator (new
CCodeVariableDeclarator ("result"));
444 cinit
.append (cdecl
);
448 /* always separate error parameter and inner_error local variable
449 * as error may be set to NULL but we're always interested in inner errors
452 closure_struct
.add_field ("GError *", "_inner_error_");
454 // no initialization necessary, closure struct is zeroed
456 var cdecl
= new
CCodeDeclaration ("GError *");
457 cdecl
.add_declarator (new
CCodeVariableDeclarator ("_inner_error_", new
CCodeConstant ("NULL")));
458 cinit
.append (cdecl
);
463 source_type_member_definition
.append (function
);
466 if (m is CreationMethod
) {
467 if (in_gobject_creation_method
) {
468 int n_params
= ((CreationMethod
) m
).n_construction_params
;
470 if (!((CreationMethod
) m
).chain_up
) {
471 if (n_params
> 0 || current_class
.get_type_parameters ().size
> 0) {
472 // declare construction parameter array
473 var cparamsinit
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
474 cparamsinit
.add_argument (new
CCodeIdentifier ("GParameter"));
475 cparamsinit
.add_argument (new
CCodeConstant ((n_params
+ 3 * current_class
.get_type_parameters ().size
).to_string ()));
477 var cdecl
= new
CCodeDeclaration ("GParameter *");
478 cdecl
.add_declarator (new
CCodeVariableDeclarator ("__params", cparamsinit
));
479 cinit
.append (cdecl
);
481 cdecl
= new
CCodeDeclaration ("GParameter *");
482 cdecl
.add_declarator (new
CCodeVariableDeclarator ("__params_it", new
CCodeIdentifier ("__params")));
483 cinit
.append (cdecl
);
486 /* type, dup func, and destroy func properties for generic types */
487 foreach (TypeParameter type_param
in current_class
.get_type_parameters ()) {
488 CCodeConstant prop_name
;
489 CCodeIdentifier param_name
;
491 prop_name
= new
CCodeConstant ("\"%s-type\"".printf (type_param
.name
.down ()));
492 param_name
= new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ()));
493 cinit
.append (new
CCodeExpressionStatement (get_construct_property_assignment (prop_name
, new
IntegerType ((Struct
) gtype_type
), param_name
)));
495 prop_name
= new
CCodeConstant ("\"%s-dup-func\"".printf (type_param
.name
.down ()));
496 param_name
= new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ()));
497 cinit
.append (new
CCodeExpressionStatement (get_construct_property_assignment (prop_name
, new
PointerType (new
VoidType ()), param_name
)));
499 prop_name
= new
CCodeConstant ("\"%s-destroy-func\"".printf (type_param
.name
.down ()));
500 param_name
= new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ()));
501 cinit
.append (new
CCodeExpressionStatement (get_construct_property_assignment (prop_name
, new
PointerType (new
VoidType ()), param_name
)));
504 } else if (is_gtypeinstance_creation_method (m
)) {
505 var cl
= (Class
) m
.parent_symbol
;
506 var cdeclaration
= new
CCodeDeclaration (cl
.get_cname () + "*");
507 var cdecl
= new
CCodeVariableDeclarator ("self");
508 cdeclaration
.add_declarator (cdecl
);
509 cinit
.append (cdeclaration
);
511 if (!((CreationMethod
) m
).chain_up
) {
512 // TODO implicitly chain up to base class as in add_object_creation
513 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_type_create_instance"));
514 ccall
.add_argument (new
CCodeIdentifier ("object_type"));
515 cdecl
.initializer
= new
CCodeCastExpression (ccall
, cl
.get_cname () + "*");
517 /* type, dup func, and destroy func fields for generic types */
518 foreach (TypeParameter type_param
in current_class
.get_type_parameters ()) {
519 CCodeIdentifier param_name
;
520 CCodeAssignment assign
;
522 var priv_access
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv");
524 param_name
= new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ()));
525 assign
= new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
);
526 cinit
.append (new
CCodeExpressionStatement (assign
));
528 param_name
= new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ()));
529 assign
= new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
);
530 cinit
.append (new
CCodeExpressionStatement (assign
));
532 param_name
= new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ()));
533 assign
= new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
);
534 cinit
.append (new
CCodeExpressionStatement (assign
));
537 } else if (current_type_symbol is Class
) {
538 var cl
= (Class
) m
.parent_symbol
;
539 var cdeclaration
= new
CCodeDeclaration (cl
.get_cname () + "*");
540 var cdecl
= new
CCodeVariableDeclarator ("self");
541 cdeclaration
.add_declarator (cdecl
);
542 cinit
.append (cdeclaration
);
544 if (!((CreationMethod
) m
).chain_up
) {
545 // TODO implicitly chain up to base class as in add_object_creation
546 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_new0"));
547 ccall
.add_argument (new
CCodeIdentifier (cl
.get_cname ()));
548 cdecl
.initializer
= ccall
;
551 if (cl
.base_class
== null) {
552 // derived compact classes do not have fields
553 var cinitcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_instance_init".printf (cl
.get_lower_case_cname (null))));
554 cinitcall
.add_argument (new
CCodeIdentifier ("self"));
555 cinit
.append (new
CCodeExpressionStatement (cinitcall
));
558 var st
= (Struct
) m
.parent_symbol
;
560 // memset needs string.h
561 source_declarations
.add_include ("string.h");
562 var czero
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
563 czero
.add_argument (new
CCodeIdentifier ("self"));
564 czero
.add_argument (new
CCodeConstant ("0"));
565 czero
.add_argument (new
CCodeIdentifier ("sizeof (%s)".printf (st
.get_cname ())));
566 cinit
.append (new
CCodeExpressionStatement (czero
));
570 if (context
.module_init_method
== m
&& in_plugin
) {
571 // GTypeModule-based plug-in, register types
572 cinit
.append (module_init_fragment
);
575 foreach (Expression precondition
in m
.get_preconditions ()) {
576 var check_stmt
= create_precondition_statement (m
, creturn_type
, precondition
);
577 if (check_stmt
!= null) {
578 cinit
.append (check_stmt
);
581 } else if (m
.is_abstract
) {
582 // generate helpful error message if a sublcass does not implement an abstract method.
583 // This is only meaningful for subclasses implemented in C since the vala compiler would
584 // complain during compile time of such en error.
586 var cblock
= new
CCodeBlock ();
588 // add a typecheck statement for "self"
589 var check_stmt
= create_method_type_check_statement (m
, creturn_type
, current_type_symbol
, true, "self");
590 if (check_stmt
!= null) {
591 cblock
.add_statement (check_stmt
);
594 // add critical warning that this method should not have been called
595 var type_from_instance_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_TYPE_FROM_INSTANCE"));
596 type_from_instance_call
.add_argument (new
CCodeIdentifier ("self"));
598 var type_name_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_type_name"));
599 type_name_call
.add_argument (type_from_instance_call
);
601 var error_string
= "\"Type `%%s' does not implement abstract method `%s'\"".printf (m
.get_cname ());
603 var cerrorcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_critical"));
604 cerrorcall
.add_argument (new
CCodeConstant (error_string
));
605 cerrorcall
.add_argument (type_name_call
);
607 cblock
.add_statement (new
CCodeExpressionStatement (cerrorcall
));
609 // add return statement
610 cblock
.add_statement (new
CCodeReturnStatement (default_value_for_type (creturn_type
, false)));
612 function
.block
= cblock
;
613 source_type_member_definition
.append (function
);
617 if ((m
.is_abstract
|| m
.is_virtual
) && !m
.coroutine
&&
618 /* If the method is a signal handler, the declaration
619 * is not needed. -- the name should be reserved for the
621 m
.signal_reference
== null) {
623 cparam_map
= new HashMap
<int,CCodeFormalParameter
> (direct_hash
, direct_equal
);
624 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
626 generate_vfunc (m
, creturn_type
, cparam_map
, carg_map
);
630 // m is possible entry point, add appropriate startup code
631 var cmain
= new
CCodeFunction ("main", "int");
632 cmain
.line
= function
.line
;
633 cmain
.add_parameter (new
CCodeFormalParameter ("argc", "int"));
634 cmain
.add_parameter (new
CCodeFormalParameter ("argv", "char **"));
635 var main_block
= new
CCodeBlock ();
637 if (context
.profile
== Profile
.GOBJECT
) {
638 if (context
.thread
) {
639 var thread_init_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_thread_init"));
640 thread_init_call
.line
= cmain
.line
;
641 thread_init_call
.add_argument (new
CCodeConstant ("NULL"));
642 main_block
.add_statement (new
CCodeExpressionStatement (thread_init_call
));
645 var type_init_call
= new
CCodeExpressionStatement (new
CCodeFunctionCall (new
CCodeIdentifier ("g_type_init")));
646 type_init_call
.line
= cmain
.line
;
647 main_block
.add_statement (type_init_call
);
650 var main_call
= new
CCodeFunctionCall (new
CCodeIdentifier (function
.name
));
651 if (m
.get_parameters ().size
== 1) {
652 main_call
.add_argument (new
CCodeIdentifier ("argv"));
653 main_call
.add_argument (new
CCodeIdentifier ("argc"));
655 if (m
.return_type is VoidType
) {
656 // method returns void, always use 0 as exit code
657 var main_stmt
= new
CCodeExpressionStatement (main_call
);
658 main_stmt
.line
= cmain
.line
;
659 main_block
.add_statement (main_stmt
);
660 var ret_stmt
= new
CCodeReturnStatement (new
CCodeConstant ("0"));
661 ret_stmt
.line
= cmain
.line
;
662 main_block
.add_statement (ret_stmt
);
664 var main_stmt
= new
CCodeReturnStatement (main_call
);
665 main_stmt
.line
= cmain
.line
;
666 main_block
.add_statement (main_stmt
);
668 cmain
.block
= main_block
;
669 source_type_member_definition
.append (cmain
);
673 public virtual void generate_parameter (FormalParameter param
, CCodeDeclarationSpace decl_space
, Map
<int,CCodeFormalParameter
> cparam_map
, Map
<int,CCodeExpression
>? carg_map
) {
674 if (!param
.ellipsis
) {
675 string ctypename
= param
.parameter_type
.get_cname ();
677 generate_type_declaration (param
.parameter_type
, decl_space
);
679 // pass non-simple structs always by reference
680 if (param
.parameter_type
.data_type is Struct
) {
681 var st
= (Struct
) param
.parameter_type
.data_type
;
682 if (!st
.is_simple_type () && param
.direction
== ParameterDirection
.IN
) {
683 if (st
.use_const
&& !param
.parameter_type
.value_owned
) {
684 ctypename
= "const " + ctypename
;
687 if (!param
.parameter_type
.nullable
) {
693 if (param
.direction
!= ParameterDirection
.IN
) {
697 param
.ccodenode
= new
CCodeFormalParameter (get_variable_cname (param
.name
), ctypename
);
699 param
.ccodenode
= new CCodeFormalParameter
.with_ellipsis ();
702 cparam_map
.set (get_param_pos (param
.cparameter_position
), (CCodeFormalParameter
) param
.ccodenode
);
703 if (carg_map
!= null && !param
.ellipsis
) {
704 carg_map
.set (get_param_pos (param
.cparameter_position
), get_variable_cexpression (param
.name
));
708 public override void generate_cparameters (Method m
, CCodeDeclarationSpace decl_space
, Map
<int,CCodeFormalParameter
> cparam_map
, CCodeFunction func
, CCodeFunctionDeclarator? vdeclarator
= null, Map
<int,CCodeExpression
>? carg_map
= null, CCodeFunctionCall? vcall
= null, int direction
= 3) {
709 if (m
.parent_symbol is Class
&& m is CreationMethod
) {
710 var cl
= (Class
) m
.parent_symbol
;
711 if (!cl
.is_compact
&& vcall
== null) {
712 cparam_map
.set (get_param_pos (m
.cinstance_parameter_position
), new
CCodeFormalParameter ("object_type", "GType"));
714 } else if (m
.binding
== MemberBinding
.INSTANCE
|| (m
.parent_symbol is Struct
&& m is CreationMethod
)) {
715 TypeSymbol parent_type
= find_parent_type (m
);
717 if (parent_type is Class
) {
718 this_type
= new
ObjectType ((Class
) parent_type
);
719 } else if (parent_type is Interface
) {
720 this_type
= new
ObjectType ((Interface
) parent_type
);
721 } else if (parent_type is Struct
) {
722 this_type
= new
StructValueType ((Struct
) parent_type
);
723 } else if (parent_type is Enum
) {
724 this_type
= new
EnumValueType ((Enum
) parent_type
);
726 assert_not_reached ();
729 generate_type_declaration (this_type
, decl_space
);
731 CCodeFormalParameter instance_param
= null;
732 if (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
) {
733 var base_type
= new
ObjectType ((Interface
) m
.base_interface_method
.parent_symbol
);
734 instance_param
= new
CCodeFormalParameter ("base", base_type
.get_cname ());
735 } else if (m
.overrides
) {
736 var base_type
= new
ObjectType ((Class
) m
.base_method
.parent_symbol
);
737 instance_param
= new
CCodeFormalParameter ("base", base_type
.get_cname ());
739 if (m
.parent_symbol is Struct
&& !((Struct
) m
.parent_symbol
).is_simple_type ()) {
740 instance_param
= new
CCodeFormalParameter ("*self", this_type
.get_cname ());
742 instance_param
= new
CCodeFormalParameter ("self", this_type
.get_cname ());
745 cparam_map
.set (get_param_pos (m
.cinstance_parameter_position
), instance_param
);
746 } else if (m
.binding
== MemberBinding
.CLASS
) {
747 TypeSymbol parent_type
= find_parent_type (m
);
749 this_type
= new
ClassType ((Class
) parent_type
);
750 var class_param
= new
CCodeFormalParameter ("klass", this_type
.get_cname ());
751 cparam_map
.set (get_param_pos (m
.cinstance_parameter_position
), class_param
);
754 if (is_gtypeinstance_creation_method (m
)) {
755 // memory management for generic types
756 int type_param_index
= 0;
757 var cl
= (Class
) m
.parent_symbol
;
758 foreach (TypeParameter type_param
in cl
.get_type_parameters ()) {
759 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeFormalParameter ("%s_type".printf (type_param
.name
.down ()), "GType"));
760 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeFormalParameter ("%s_dup_func".printf (type_param
.name
.down ()), "GBoxedCopyFunc"));
761 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeFormalParameter ("%s_destroy_func".printf (type_param
.name
.down ()), "GDestroyNotify"));
762 if (carg_map
!= null) {
763 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ())));
764 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ())));
765 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ())));
770 int type_param_index
= 0;
771 if (m
.binding
!= MemberBinding
.INSTANCE
&& m
.parent_symbol is ObjectTypeSymbol
) {
772 // support static methods in generic types
773 var type_symbol
= (ObjectTypeSymbol
) m
.parent_symbol
;
774 foreach (var type_param
in type_symbol
.get_type_parameters ()) {
775 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeFormalParameter ("%s_type".printf (type_param
.name
.down ()), "GType"));
776 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeFormalParameter ("%s_dup_func".printf (type_param
.name
.down ()), "GBoxedCopyFunc"));
777 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeFormalParameter ("%s_destroy_func".printf (type_param
.name
.down ()), "GDestroyNotify"));
778 if (carg_map
!= null) {
779 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ())));
780 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ())));
781 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ())));
786 foreach (var type_param
in m
.get_type_parameters ()) {
787 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeFormalParameter ("%s_type".printf (type_param
.name
.down ()), "GType"));
788 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeFormalParameter ("%s_dup_func".printf (type_param
.name
.down ()), "GBoxedCopyFunc"));
789 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeFormalParameter ("%s_destroy_func".printf (type_param
.name
.down ()), "GDestroyNotify"));
790 if (carg_map
!= null) {
791 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ())));
792 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ())));
793 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ())));
799 foreach (FormalParameter param
in m
.get_parameters ()) {
800 if (param
.direction
!= ParameterDirection
.OUT
) {
801 if ((direction
& 1) == 0) {
806 if ((direction
& 2) == 0) {
812 generate_parameter (param
, decl_space
, cparam_map
, carg_map
);
815 if ((direction
& 2) != 0) {
816 generate_method_result_declaration (m
, decl_space
, func
, cparam_map
, carg_map
);
819 // append C parameters in the right order
824 foreach (int pos
in cparam_map
.get_keys ()) {
825 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
832 func
.add_parameter (cparam_map
.get (min_pos
));
833 if (vdeclarator
!= null) {
834 vdeclarator
.add_parameter (cparam_map
.get (min_pos
));
837 var arg
= carg_map
.get (min_pos
);
839 vcall
.add_argument (arg
);
846 public void generate_vfunc (Method m
, DataType return_type
, Map
<int,CCodeFormalParameter
> cparam_map
, Map
<int,CCodeExpression
> carg_map
, string suffix
= "", int direction
= 3) {
847 var vfunc
= new
CCodeFunction (m
.get_cname () + suffix
);
848 if (function
!= null) {
849 vfunc
.line
= function
.line
;
852 var vblock
= new
CCodeBlock ();
854 foreach (Expression precondition
in m
.get_preconditions ()) {
855 var check_stmt
= create_precondition_statement (m
, return_type
, precondition
);
856 if (check_stmt
!= null) {
857 vblock
.add_statement (check_stmt
);
861 CCodeFunctionCall vcast
= null;
862 if (m
.parent_symbol is Interface
) {
863 var iface
= (Interface
) m
.parent_symbol
;
865 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_INTERFACE".printf (iface
.get_upper_case_cname (null))));
867 var cl
= (Class
) m
.parent_symbol
;
869 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS".printf (cl
.get_upper_case_cname (null))));
871 vcast
.add_argument (new
CCodeIdentifier ("self"));
873 var vcall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, m
.vfunc_name
+ suffix
));
874 carg_map
.set (get_param_pos (m
.cinstance_parameter_position
), new
CCodeIdentifier ("self"));
876 generate_cparameters (m
, source_declarations
, cparam_map
, vfunc
, null, carg_map
, vcall
, direction
);
878 CCodeStatement cstmt
;
879 if (return_type is VoidType
) {
880 cstmt
= new
CCodeExpressionStatement (vcall
);
881 } else if (m
.get_postconditions ().size
== 0) {
882 /* pass method return value */
883 cstmt
= new
CCodeReturnStatement (vcall
);
885 /* store method return value for postconditions */
886 var cdecl
= new
CCodeDeclaration (get_creturn_type (m
, return_type
.get_cname ()));
887 cdecl
.add_declarator (new
CCodeVariableDeclarator ("result", vcall
));
890 cstmt
.line
= vfunc
.line
;
891 vblock
.add_statement (cstmt
);
893 if (m
.get_postconditions ().size
> 0) {
894 foreach (Expression postcondition
in m
.get_postconditions ()) {
895 vblock
.add_statement (create_postcondition_statement (postcondition
));
898 if (!(return_type is VoidType
)) {
899 var cret_stmt
= new
CCodeReturnStatement (new
CCodeIdentifier ("result"));
900 cret_stmt
.line
= vfunc
.line
;
901 vblock
.add_statement (cret_stmt
);
905 vfunc
.block
= vblock
;
907 source_type_member_definition
.append (vfunc
);
910 private CCodeStatement?
create_method_type_check_statement (Method m
, DataType return_type
, TypeSymbol t
, bool non_null
, string var_name
) {
914 return create_type_check_statement (m
, return_type
, t
, non_null
, var_name
);
918 private CCodeStatement?
create_precondition_statement (CodeNode method_node
, DataType ret_type
, Expression precondition
) {
919 var ccheck
= new
CCodeFunctionCall ();
921 ccheck
.add_argument ((CCodeExpression
) precondition
.ccodenode
);
923 if (ret_type is VoidType
) {
925 ccheck
.call
= new
CCodeIdentifier ("g_return_if_fail");
927 ccheck
.call
= new
CCodeIdentifier ("g_return_val_if_fail");
929 var cdefault
= default_value_for_type (ret_type
, false);
930 if (cdefault
!= null) {
931 ccheck
.add_argument (cdefault
);
937 return new
CCodeExpressionStatement (ccheck
);
940 private TypeSymbol?
find_parent_type (Symbol sym
) {
941 while (sym
!= null) {
942 if (sym is TypeSymbol
) {
943 return (TypeSymbol
) sym
;
945 sym
= sym
.parent_symbol
;
950 private void add_object_creation (CCodeBlock b
, bool has_params
) {
951 var cl
= (Class
) current_type_symbol
;
953 if (!has_params
&& cl
.base_class
!= gobject_type
) {
954 // possibly report warning or error about missing base call
957 var cdecl
= new
CCodeVariableDeclarator ("self");
958 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_newv"));
959 ccall
.add_argument (new
CCodeIdentifier ("object_type"));
961 ccall
.add_argument (new
CCodeConstant ("__params_it - __params"));
962 ccall
.add_argument (new
CCodeConstant ("__params"));
964 ccall
.add_argument (new
CCodeConstant ("0"));
965 ccall
.add_argument (new
CCodeConstant ("NULL"));
967 cdecl
.initializer
= ccall
;
969 var cdeclaration
= new
CCodeDeclaration ("%s *".printf (cl
.get_cname ()));
970 cdeclaration
.add_declarator (cdecl
);
972 b
.add_statement (cdeclaration
);
975 public override void visit_creation_method (CreationMethod m
) {
976 bool visible
= !m
.is_private_symbol ();
978 head
.visit_method (m
);
980 DataType creturn_type
;
981 if (current_type_symbol is Class
) {
982 creturn_type
= new
ObjectType (current_class
);
984 creturn_type
= new
VoidType ();
987 // do not generate _new functions for creation methods of abstract classes
988 if (current_type_symbol is Class
&& !current_class
.is_compact
&& !current_class
.is_abstract
) {
989 var vfunc
= new
CCodeFunction (m
.get_cname ());
990 vfunc
.line
= function
.line
;
992 var cparam_map
= new HashMap
<int,CCodeFormalParameter
> (direct_hash
, direct_equal
);
993 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
995 var vblock
= new
CCodeBlock ();
997 var vcall
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_real_cname ()));
998 vcall
.add_argument (new
CCodeIdentifier (current_class
.get_type_id ()));
1000 generate_cparameters (m
, source_declarations
, cparam_map
, vfunc
, null, carg_map
, vcall
);
1001 CCodeStatement cstmt
= new
CCodeReturnStatement (vcall
);
1002 cstmt
.line
= vfunc
.line
;
1003 vblock
.add_statement (cstmt
);
1006 vfunc
.modifiers
|= CCodeModifiers
.STATIC
;
1009 vfunc
.block
= vblock
;
1011 source_type_member_definition
.append (vfunc
);
1014 if (current_type_symbol is Class
&& gobject_type
!= null && current_class
.is_subtype_of (gobject_type
)
1015 && (((CreationMethod
) m
).n_construction_params
> 0 || current_class
.get_type_parameters ().size
> 0)
1016 && !((CreationMethod
) m
).chain_up
) {
1017 var ccond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.GREATER_THAN
, new
CCodeIdentifier ("__params_it"), new
CCodeIdentifier ("__params"));
1018 var cdofreeparam
= new
CCodeBlock ();
1019 cdofreeparam
.add_statement (new
CCodeExpressionStatement (new
CCodeUnaryExpression (CCodeUnaryOperator
.PREFIX_DECREMENT
, new
CCodeIdentifier ("__params_it"))));
1020 var cunsetcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_unset"));
1021 cunsetcall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("__params_it"), "value")));
1022 cdofreeparam
.add_statement (new
CCodeExpressionStatement (cunsetcall
));
1023 function
.block
.add_statement (new
CCodeWhileStatement (ccond
, cdofreeparam
));
1025 var cfreeparams
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_free"));
1026 cfreeparams
.add_argument (new
CCodeIdentifier ("__params"));
1027 function
.block
.add_statement (new
CCodeExpressionStatement (cfreeparams
));
1030 if (current_type_symbol is Class
) {
1031 CCodeExpression cresult
= new
CCodeIdentifier ("self");
1032 if (get_custom_creturn_type (m
) != null) {
1033 cresult
= new
CCodeCastExpression (cresult
, get_custom_creturn_type (m
));
1036 var creturn
= new
CCodeReturnStatement ();
1037 creturn
.return_expression
= cresult
;
1038 function
.block
.add_statement (creturn
);