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
, 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
= current_type_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 if (!m
.no_array_length
&& m
.return_type is ArrayType
) {
82 // return array length if appropriate
83 var array_type
= (ArrayType
) m
.return_type
;
85 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
86 var cparam
= new
CCodeFormalParameter (head
.get_array_length_cname ("result", dim
), "int*");
87 cparam_map
.set (get_param_pos (m
.carray_length_parameter_position
+ 0.01 * dim
), cparam
);
88 if (carg_map
!= null) {
89 carg_map
.set (get_param_pos (m
.carray_length_parameter_position
+ 0.01 * dim
), new
CCodeIdentifier (cparam
.name
));
92 } else if (m
.return_type is DelegateType
) {
93 // return delegate target if appropriate
94 var deleg_type
= (DelegateType
) m
.return_type
;
95 var d
= deleg_type
.delegate_symbol
;
97 var cparam
= new
CCodeFormalParameter (get_delegate_target_cname ("result"), "void*");
98 cparam_map
.set (get_param_pos (m
.cdelegate_target_parameter_position
), cparam
);
99 if (carg_map
!= null) {
100 carg_map
.set (get_param_pos (m
.cdelegate_target_parameter_position
), new
CCodeIdentifier (cparam
.name
));
105 if (m
.get_error_types ().size
> 0) {
106 var cparam
= new
CCodeFormalParameter ("error", "GError**");
107 cparam_map
.set (get_param_pos (-1), cparam
);
108 if (carg_map
!= null) {
109 carg_map
.set (get_param_pos (-1), new
CCodeIdentifier (cparam
.name
));
114 public CCodeStatement
complete_async () {
115 var complete_block
= new
CCodeBlock ();
117 var direct_block
= new
CCodeBlock ();
118 var direct_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_simple_async_result_complete"));
119 var async_result_expr
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "_async_result");
120 direct_call
.add_argument (async_result_expr
);
121 direct_block
.add_statement (new
CCodeExpressionStatement (direct_call
));
123 var idle_block
= new
CCodeBlock ();
124 var idle_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_simple_async_result_complete_in_idle"));
125 idle_call
.add_argument (async_result_expr
);
126 idle_block
.add_statement (new
CCodeExpressionStatement (idle_call
));
128 var state
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "state");
129 var zero
= new
CCodeConstant ("0");
130 var state_is_zero
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, state
, zero
);
131 var dispatch
= new
CCodeIfStatement (state_is_zero
, idle_block
, direct_block
);
132 complete_block
.add_statement (dispatch
);
134 var unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_unref"));
135 unref
.add_argument (async_result_expr
);
136 complete_block
.add_statement (new
CCodeExpressionStatement (unref
));
138 complete_block
.add_statement (new
CCodeReturnStatement (new
CCodeConstant ("FALSE")));
140 return complete_block
;
143 public override void visit_method (Method m
) {
144 var old_type_symbol
= current_type_symbol
;
145 var old_symbol
= current_symbol
;
146 Method old_method
= current_method
;
147 DataType old_return_type
= current_return_type
;
148 bool old_method_inner_error
= current_method_inner_error
;
149 bool old_in_creation_method
= in_creation_method
;
150 int old_next_temp_var_id
= next_temp_var_id
;
151 var old_variable_name_map
= variable_name_map
;
152 var old_try
= current_try
;
153 if (m
.parent_symbol is TypeSymbol
) {
154 current_type_symbol
= (TypeSymbol
) m
.parent_symbol
;
158 current_return_type
= m
.return_type
;
159 current_method_inner_error
= false;
160 next_temp_var_id
= 0;
161 variable_name_map
= new HashMap
<string,string> (str_hash
, str_equal
);
164 bool in_gobject_creation_method
= false;
165 bool in_fundamental_creation_method
= false;
167 check_type (m
.return_type
);
169 if (m is CreationMethod
) {
170 in_creation_method
= true;
171 var cl
= current_type_symbol as Class
;
172 if (cl
!= null && !cl
.is_compact
) {
173 if (cl
.base_class
== null) {
174 in_fundamental_creation_method
= true;
175 } else if (cl
.is_subtype_of (gobject_type
)) {
176 in_gobject_creation_method
= true;
180 in_creation_method
= false;
183 var creturn_type
= current_return_type
;
185 m
.accept_children (codegen
);
187 if (m is CreationMethod
) {
188 if (in_gobject_creation_method
&& m
.body
!= null) {
189 var cblock
= new
CCodeBlock ();
191 if (!((CreationMethod
) m
).chain_up
) {
192 // set construct properties
193 foreach (CodeNode stmt
in m
.body
.get_statements ()) {
194 var expr_stmt
= stmt as ExpressionStatement
;
195 if (expr_stmt
!= null) {
196 var prop
= expr_stmt
.assigned_property ();
197 if (prop
!= null && prop
.set_accessor
.construction
) {
198 if (stmt
.ccodenode is CCodeFragment
) {
199 foreach (CCodeNode cstmt
in ((CCodeFragment
) stmt
.ccodenode
).get_children ()) {
200 cblock
.add_statement (cstmt
);
203 cblock
.add_statement (stmt
.ccodenode
);
209 add_object_creation (cblock
, ((CreationMethod
) m
).n_construction_params
> 0 || current_class
.get_type_parameters ().size
> 0);
211 var cdeclaration
= new
CCodeDeclaration ("%s *".printf (((Class
) current_type_symbol
).get_cname ()));
212 cdeclaration
.add_declarator (new
CCodeVariableDeclarator ("self"));
214 cblock
.add_statement (cdeclaration
);
217 // other initialization code
218 foreach (CodeNode stmt
in m
.body
.get_statements ()) {
219 var expr_stmt
= stmt as ExpressionStatement
;
220 if (expr_stmt
!= null) {
221 var prop
= expr_stmt
.assigned_property ();
222 if (prop
!= null && prop
.set_accessor
.construction
) {
226 if (stmt
.ccodenode is CCodeFragment
) {
227 foreach (CCodeNode cstmt
in ((CCodeFragment
) stmt
.ccodenode
).get_children ()) {
228 cblock
.add_statement (cstmt
);
231 cblock
.add_statement (stmt
.ccodenode
);
235 m
.body
.ccodenode
= cblock
;
238 in_creation_method
= old_in_creation_method
;
241 bool inner_error
= current_method_inner_error
;
243 current_type_symbol
= old_type_symbol
;
244 current_symbol
= old_symbol
;
245 current_method
= old_method
;
246 current_return_type
= old_return_type
;
247 current_method_inner_error
= old_method_inner_error
;
248 next_temp_var_id
= old_next_temp_var_id
;
249 variable_name_map
= old_variable_name_map
;
250 current_try
= old_try
;
252 function
= new
CCodeFunction (m
.get_real_cname ());
253 m
.ccodenode
= function
;
256 function
.modifiers
|= CCodeModifiers
.INLINE
;
259 var cparam_map
= new HashMap
<int,CCodeFormalParameter
> (direct_hash
, direct_equal
);
261 CCodeFunctionDeclarator vdeclarator
= null;
262 if ((m
.is_abstract
|| m
.is_virtual
) && !m
.coroutine
) {
263 var vdecl
= new
CCodeDeclaration (get_creturn_type (m
, creturn_type
.get_cname ()));
264 vdeclarator
= new
CCodeFunctionDeclarator (m
.vfunc_name
);
265 vdecl
.add_declarator (vdeclarator
);
266 type_struct
.add_declaration (vdecl
);
269 generate_cparameters (m
, cparam_map
, function
, vdeclarator
);
271 bool visible
= !m
.is_internal_symbol ();
273 // generate *_real_* functions for virtual methods
274 // also generate them for abstract methods of classes to prevent faulty subclassing
275 if (!m
.is_abstract
|| (m
.is_abstract
&& current_type_symbol is Class
)) {
276 if (visible
&& m
.base_method
== null && m
.base_interface_method
== null) {
277 /* public methods need function declaration in
278 * header file except virtual/overridden methods */
279 header_declarations
.add_type_member_declaration (function
.copy ());
281 /* declare all other functions in source file to
282 * avoid dependency on order within source file */
283 function
.modifiers
|= CCodeModifiers
.STATIC
;
284 source_declarations
.add_type_member_declaration (function
.copy ());
287 /* Methods imported from a plain C file don't
288 * have a body, e.g. Vala.Parser.parse_file () */
289 if (m
.body
!= null) {
290 function
.block
= (CCodeBlock
) m
.body
.ccodenode
;
291 function
.block
.line
= function
.line
;
293 var cinit
= new
CCodeFragment ();
294 function
.block
.prepend_statement (cinit
);
297 var co_function
= new
CCodeFunction (m
.get_real_cname () + "_co", "gboolean");
299 // data struct to hold parameters, local variables, and the return value
300 co_function
.add_parameter (new
CCodeFormalParameter ("data", Symbol
.lower_case_to_camel_case (m
.get_cname ()) + "Data*"));
302 co_function
.modifiers
|= CCodeModifiers
.STATIC
;
303 source_declarations
.add_type_member_declaration (co_function
.copy ());
305 var cswitch
= new
CCodeSwitchStatement (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "state"));
307 // let gcc know that this can't happen
308 cswitch
.add_statement (new
CCodeLabel ("default"));
309 cswitch
.add_statement (new
CCodeExpressionStatement (new
CCodeFunctionCall (new
CCodeIdentifier ("g_assert_not_reached"))));
311 // initial coroutine state
312 cswitch
.add_statement (new
CCodeCaseStatement (new
CCodeConstant ("0")));
315 cswitch
.add_statement (function
.block
);
318 cswitch
.add_statement (complete_async ());
320 co_function
.block
= new
CCodeBlock ();
321 co_function
.block
.add_statement (cswitch
);
323 source_type_member_definition
.append (co_function
);
326 if (m
.parent_symbol is Class
&& !m
.coroutine
) {
327 var cl
= (Class
) m
.parent_symbol
;
328 if (m
.overrides
|| (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
)) {
330 ReferenceType base_expression_type
;
332 base_method
= m
.base_method
;
333 base_expression_type
= new
ObjectType ((Class
) base_method
.parent_symbol
);
335 base_method
= m
.base_interface_method
;
336 base_expression_type
= new
ObjectType ((Interface
) base_method
.parent_symbol
);
338 var self_target_type
= new
ObjectType (cl
);
339 CCodeExpression cself
= transform_expression (new
CCodeIdentifier ("base"), base_expression_type
, self_target_type
);
341 var cdecl
= new
CCodeDeclaration ("%s *".printf (cl
.get_cname ()));
342 cdecl
.add_declarator (new
CCodeVariableDeclarator ("self", cself
));
344 cinit
.append (cdecl
);
345 } else if (m
.binding
== MemberBinding
.INSTANCE
346 && !(m is CreationMethod
)) {
347 var ccheckstmt
= create_method_type_check_statement (m
, creturn_type
, cl
, true, "self");
348 if (ccheckstmt
!= null) {
349 ccheckstmt
.line
= function
.line
;
350 cinit
.append (ccheckstmt
);
354 foreach (FormalParameter param
in m
.get_parameters ()) {
355 if (param
.ellipsis
) {
359 var t
= param
.parameter_type
.data_type
;
360 if (t
!= null && t
.is_reference_type ()) {
361 if (param
.direction
!= ParameterDirection
.OUT
) {
362 var type_check
= create_method_type_check_statement (m
, creturn_type
, t
, !param
.parameter_type
.nullable
, param
.name
);
363 if (type_check
!= null) {
364 type_check
.line
= function
.line
;
365 cinit
.append (type_check
);
368 // ensure that the passed reference for output parameter is cleared
369 var a
= new
CCodeAssignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier (param
.name
)), new
CCodeConstant ("NULL"));
370 cinit
.append (new
CCodeExpressionStatement (a
));
376 /* always separate error parameter and inner_error local variable
377 * as error may be set to NULL but we're always interested in inner errors
380 closure_struct
.add_field ("GError *", "inner_error");
382 // no initialization necessary, closure struct is zeroed
384 var cdecl
= new
CCodeDeclaration ("GError *");
385 cdecl
.add_declarator (new
CCodeVariableDeclarator ("inner_error", new
CCodeConstant ("NULL")));
386 cinit
.append (cdecl
);
391 if (m
.source_reference
!= null && m
.source_reference
.comment
!= null) {
392 source_type_member_definition
.append (new
CCodeComment (m
.source_reference
.comment
));
394 source_type_member_definition
.append (function
);
397 if (m is CreationMethod
) {
398 if (in_gobject_creation_method
) {
399 int n_params
= ((CreationMethod
) m
).n_construction_params
;
401 if (n_params
> 0 || current_class
.get_type_parameters ().size
> 0) {
402 // declare construction parameter array
403 var cparamsinit
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
404 cparamsinit
.add_argument (new
CCodeIdentifier ("GParameter"));
405 cparamsinit
.add_argument (new
CCodeConstant ((n_params
+ 3 * current_class
.get_type_parameters ().size
).to_string ()));
407 var cdecl
= new
CCodeDeclaration ("GParameter *");
408 cdecl
.add_declarator (new
CCodeVariableDeclarator ("__params", cparamsinit
));
409 cinit
.append (cdecl
);
411 cdecl
= new
CCodeDeclaration ("GParameter *");
412 cdecl
.add_declarator (new
CCodeVariableDeclarator ("__params_it", new
CCodeIdentifier ("__params")));
413 cinit
.append (cdecl
);
416 /* type, dup func, and destroy func properties for generic types */
417 foreach (TypeParameter type_param
in current_class
.get_type_parameters ()) {
418 CCodeConstant prop_name
;
419 CCodeIdentifier param_name
;
421 prop_name
= new
CCodeConstant ("\"%s-type\"".printf (type_param
.name
.down ()));
422 param_name
= new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ()));
423 cinit
.append (new
CCodeExpressionStatement (get_construct_property_assignment (prop_name
, new
IntegerType ((Struct
) gtype_type
), param_name
)));
425 prop_name
= new
CCodeConstant ("\"%s-dup-func\"".printf (type_param
.name
.down ()));
426 param_name
= new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ()));
427 cinit
.append (new
CCodeExpressionStatement (get_construct_property_assignment (prop_name
, new
PointerType (new
VoidType ()), param_name
)));
429 prop_name
= new
CCodeConstant ("\"%s-destroy-func\"".printf (type_param
.name
.down ()));
430 param_name
= new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ()));
431 cinit
.append (new
CCodeExpressionStatement (get_construct_property_assignment (prop_name
, new
PointerType (new
VoidType ()), param_name
)));
433 } else if (is_gtypeinstance_creation_method (m
)) {
434 var cl
= (Class
) m
.parent_symbol
;
435 var cdeclaration
= new
CCodeDeclaration (cl
.get_cname () + "*");
436 var cdecl
= new
CCodeVariableDeclarator ("self");
437 cdeclaration
.add_declarator (cdecl
);
438 cinit
.append (cdeclaration
);
440 if (!((CreationMethod
) m
).chain_up
) {
441 // TODO implicitly chain up to base class as in add_object_creation
442 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_type_create_instance"));
443 ccall
.add_argument (new
CCodeIdentifier ("object_type"));
444 cdecl
.initializer
= new
CCodeCastExpression (ccall
, cl
.get_cname () + "*");
447 /* type, dup func, and destroy func fields for generic types */
448 foreach (TypeParameter type_param
in current_class
.get_type_parameters ()) {
449 CCodeIdentifier param_name
;
450 CCodeAssignment assign
;
452 var priv_access
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv");
454 param_name
= new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ()));
455 assign
= new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
);
456 cinit
.append (new
CCodeExpressionStatement (assign
));
458 param_name
= new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ()));
459 assign
= new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
);
460 cinit
.append (new
CCodeExpressionStatement (assign
));
462 param_name
= new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ()));
463 assign
= new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
);
464 cinit
.append (new
CCodeExpressionStatement (assign
));
466 } else if (current_type_symbol is Class
) {
467 var cl
= (Class
) m
.parent_symbol
;
468 var cdecl
= new
CCodeDeclaration (cl
.get_cname () + "*");
469 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_new0"));
470 ccall
.add_argument (new
CCodeIdentifier (cl
.get_cname ()));
471 cdecl
.add_declarator (new
CCodeVariableDeclarator ("self", ccall
));
472 cinit
.append (cdecl
);
474 var cinitcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_instance_init".printf (cl
.get_lower_case_cname (null))));
475 cinitcall
.add_argument (new
CCodeIdentifier ("self"));
476 cinit
.append (new
CCodeExpressionStatement (cinitcall
));
478 var st
= (Struct
) m
.parent_symbol
;
480 // memset needs string.h
481 string_h_needed
= true;
482 var czero
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
483 czero
.add_argument (new
CCodeIdentifier ("self"));
484 czero
.add_argument (new
CCodeConstant ("0"));
485 czero
.add_argument (new
CCodeIdentifier ("sizeof (%s)".printf (st
.get_cname ())));
486 cinit
.append (new
CCodeExpressionStatement (czero
));
490 if (context
.module_init_method
== m
&& in_plugin
) {
491 // GTypeModule-based plug-in, register types
492 cinit
.append (module_init_fragment
);
495 foreach (Expression precondition
in m
.get_preconditions ()) {
496 var check_stmt
= create_precondition_statement (m
, creturn_type
, precondition
);
497 if (check_stmt
!= null) {
498 cinit
.append (check_stmt
);
501 } else if (m
.is_abstract
) {
502 // generate helpful error message if a sublcass does not implement an abstract method.
503 // This is only meaningful for subclasses implemented in C since the vala compiler would
504 // complain during compile time of such en error.
506 var cblock
= new
CCodeBlock ();
508 // add a typecheck statement for "self"
509 var check_stmt
= create_method_type_check_statement (m
, creturn_type
, current_type_symbol
, true, "self");
510 if (check_stmt
!= null) {
511 cblock
.add_statement (check_stmt
);
514 // add critical warning that this method should not have been called
515 var type_from_instance_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_TYPE_FROM_INSTANCE"));
516 type_from_instance_call
.add_argument (new
CCodeIdentifier ("self"));
518 var type_name_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_type_name"));
519 type_name_call
.add_argument (type_from_instance_call
);
521 var error_string
= "\"Type `%%s' does not implement abstract method `%s'\"".printf (m
.get_cname ());
523 var cerrorcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_critical"));
524 cerrorcall
.add_argument (new
CCodeConstant (error_string
));
525 cerrorcall
.add_argument (type_name_call
);
527 cblock
.add_statement (new
CCodeExpressionStatement (cerrorcall
));
529 // add return statement
530 cblock
.add_statement (new
CCodeReturnStatement (default_value_for_type (creturn_type
, false)));
532 function
.block
= cblock
;
533 source_type_member_definition
.append (function
);
537 if ((m
.is_abstract
|| m
.is_virtual
) && !m
.coroutine
) {
538 cparam_map
= new HashMap
<int,CCodeFormalParameter
> (direct_hash
, direct_equal
);
539 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
541 generate_vfunc (m
, creturn_type
, cparam_map
, carg_map
);
545 // m is possible entry point, add appropriate startup code
546 var cmain
= new
CCodeFunction ("main", "int");
547 cmain
.line
= function
.line
;
548 cmain
.add_parameter (new
CCodeFormalParameter ("argc", "int"));
549 cmain
.add_parameter (new
CCodeFormalParameter ("argv", "char **"));
550 var main_block
= new
CCodeBlock ();
552 if (context
.thread
) {
553 var thread_init_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_thread_init"));
554 thread_init_call
.line
= cmain
.line
;
555 thread_init_call
.add_argument (new
CCodeConstant ("NULL"));
556 main_block
.add_statement (new
CCodeExpressionStatement (thread_init_call
));
559 var type_init_call
= new
CCodeExpressionStatement (new
CCodeFunctionCall (new
CCodeIdentifier ("g_type_init")));
560 type_init_call
.line
= cmain
.line
;
561 main_block
.add_statement (type_init_call
);
563 var main_call
= new
CCodeFunctionCall (new
CCodeIdentifier (function
.name
));
564 if (m
.get_parameters ().size
== 1) {
565 main_call
.add_argument (new
CCodeIdentifier ("argv"));
566 main_call
.add_argument (new
CCodeIdentifier ("argc"));
568 if (m
.return_type is VoidType
) {
569 // method returns void, always use 0 as exit code
570 var main_stmt
= new
CCodeExpressionStatement (main_call
);
571 main_stmt
.line
= cmain
.line
;
572 main_block
.add_statement (main_stmt
);
573 var ret_stmt
= new
CCodeReturnStatement (new
CCodeConstant ("0"));
574 ret_stmt
.line
= cmain
.line
;
575 main_block
.add_statement (ret_stmt
);
577 var main_stmt
= new
CCodeReturnStatement (main_call
);
578 main_stmt
.line
= cmain
.line
;
579 main_block
.add_statement (main_stmt
);
581 cmain
.block
= main_block
;
582 source_type_member_definition
.append (cmain
);
586 public virtual void generate_parameter (FormalParameter param
, Map
<int,CCodeFormalParameter
> cparam_map
, Map
<int,CCodeExpression
>? carg_map
) {
587 cparam_map
.set (get_param_pos (param
.cparameter_position
), (CCodeFormalParameter
) param
.ccodenode
);
588 if (carg_map
!= null) {
589 carg_map
.set (get_param_pos (param
.cparameter_position
), new
CCodeIdentifier (param
.name
));
593 public override void generate_cparameters (Method m
, Map
<int,CCodeFormalParameter
> cparam_map
, CCodeFunction func
, CCodeFunctionDeclarator? vdeclarator
= null, Map
<int,CCodeExpression
>? carg_map
= null, CCodeFunctionCall? vcall
= null, int direction
= 3) {
594 if (m
.parent_symbol is Class
&& m is CreationMethod
) {
595 var cl
= (Class
) m
.parent_symbol
;
596 if (!cl
.is_compact
&& vcall
== null) {
597 cparam_map
.set (get_param_pos (m
.cinstance_parameter_position
), new
CCodeFormalParameter ("object_type", "GType"));
599 } else if (m
.binding
== MemberBinding
.INSTANCE
|| (m
.parent_symbol is Struct
&& m is CreationMethod
)) {
600 TypeSymbol parent_type
= find_parent_type (m
);
602 if (parent_type is Class
) {
603 this_type
= new
ObjectType ((Class
) parent_type
);
604 } else if (parent_type is Interface
) {
605 this_type
= new
ObjectType ((Interface
) parent_type
);
606 } else if (parent_type is Struct
) {
607 this_type
= new
StructValueType ((Struct
) parent_type
);
608 } else if (parent_type is Enum
) {
609 this_type
= new
EnumValueType ((Enum
) parent_type
);
611 assert_not_reached ();
614 CCodeFormalParameter instance_param
= null;
615 if (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
) {
616 var base_type
= new
ObjectType ((Interface
) m
.base_interface_method
.parent_symbol
);
617 instance_param
= new
CCodeFormalParameter ("base", base_type
.get_cname ());
618 } else if (m
.overrides
) {
619 var base_type
= new
ObjectType ((Class
) m
.base_method
.parent_symbol
);
620 instance_param
= new
CCodeFormalParameter ("base", base_type
.get_cname ());
622 if (m
.parent_symbol is Struct
&& !((Struct
) m
.parent_symbol
).is_simple_type ()) {
623 instance_param
= new
CCodeFormalParameter ("*self", this_type
.get_cname ());
625 instance_param
= new
CCodeFormalParameter ("self", this_type
.get_cname ());
628 cparam_map
.set (get_param_pos (m
.cinstance_parameter_position
), instance_param
);
629 } else if (m
.binding
== MemberBinding
.CLASS
) {
630 TypeSymbol parent_type
= find_parent_type (m
);
632 this_type
= new
ClassType ((Class
) parent_type
);
633 var class_param
= new
CCodeFormalParameter ("klass", this_type
.get_cname ());
634 cparam_map
.set (get_param_pos (m
.cinstance_parameter_position
), class_param
);
637 if (is_gtypeinstance_creation_method (m
)) {
638 // memory management for generic types
639 int type_param_index
= 0;
640 foreach (TypeParameter type_param
in current_class
.get_type_parameters ()) {
641 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeFormalParameter ("%s_type".printf (type_param
.name
.down ()), "GType"));
642 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeFormalParameter ("%s_dup_func".printf (type_param
.name
.down ()), "GBoxedCopyFunc"));
643 cparam_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeFormalParameter ("%s_destroy_func".printf (type_param
.name
.down ()), "GDestroyNotify"));
644 if (carg_map
!= null) {
645 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ())));
646 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ())));
647 carg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ())));
653 foreach (FormalParameter param
in m
.get_parameters ()) {
654 if (param
.direction
!= ParameterDirection
.OUT
) {
655 if ((direction
& 1) == 0) {
660 if ((direction
& 2) == 0) {
666 generate_parameter (param
, cparam_map
, carg_map
);
669 if ((direction
& 2) != 0) {
670 generate_method_result_declaration (m
, func
, cparam_map
, carg_map
);
673 // append C parameters in the right order
678 foreach (int pos
in cparam_map
.get_keys ()) {
679 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
686 func
.add_parameter (cparam_map
.get (min_pos
));
687 if (vdeclarator
!= null) {
688 vdeclarator
.add_parameter (cparam_map
.get (min_pos
));
691 vcall
.add_argument (carg_map
.get (min_pos
));
697 public void generate_vfunc (Method m
, DataType return_type
, Map
<int,CCodeFormalParameter
> cparam_map
, Map
<int,CCodeExpression
> carg_map
, string suffix
= "", int direction
= 3) {
698 bool visible
= !m
.is_internal_symbol ();
700 var vfunc
= new
CCodeFunction (m
.get_cname () + suffix
);
701 vfunc
.line
= function
.line
;
703 var vblock
= new
CCodeBlock ();
705 foreach (Expression precondition
in m
.get_preconditions ()) {
706 var check_stmt
= create_precondition_statement (m
, return_type
, precondition
);
707 if (check_stmt
!= null) {
708 vblock
.add_statement (check_stmt
);
712 CCodeFunctionCall vcast
= null;
713 if (m
.parent_symbol is Interface
) {
714 var iface
= (Interface
) m
.parent_symbol
;
716 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_INTERFACE".printf (iface
.get_upper_case_cname (null))));
718 var cl
= (Class
) m
.parent_symbol
;
720 vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_GET_CLASS".printf (cl
.get_upper_case_cname (null))));
722 vcast
.add_argument (new
CCodeIdentifier ("self"));
724 var vcall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (vcast
, m
.vfunc_name
+ suffix
));
725 carg_map
.set (get_param_pos (m
.cinstance_parameter_position
), new
CCodeIdentifier ("self"));
727 generate_cparameters (m
, cparam_map
, vfunc
, null, carg_map
, vcall
, direction
);
729 CCodeStatement cstmt
;
730 if (return_type is VoidType
) {
731 cstmt
= new
CCodeExpressionStatement (vcall
);
732 } else if (m
.get_postconditions ().size
== 0) {
733 /* pass method return value */
734 cstmt
= new
CCodeReturnStatement (vcall
);
736 /* store method return value for postconditions */
737 var cdecl
= new
CCodeDeclaration (get_creturn_type (m
, return_type
.get_cname ()));
738 cdecl
.add_declarator (new
CCodeVariableDeclarator ("result", vcall
));
741 cstmt
.line
= vfunc
.line
;
742 vblock
.add_statement (cstmt
);
744 if (m
.get_postconditions ().size
> 0) {
745 foreach (Expression postcondition
in m
.get_postconditions ()) {
746 vblock
.add_statement (create_postcondition_statement (postcondition
));
749 if (!(return_type is VoidType
)) {
750 var cret_stmt
= new
CCodeReturnStatement (new
CCodeIdentifier ("result"));
751 cret_stmt
.line
= vfunc
.line
;
752 vblock
.add_statement (cret_stmt
);
757 header_declarations
.add_type_member_declaration (vfunc
.copy ());
759 vfunc
.modifiers
|= CCodeModifiers
.STATIC
;
760 source_declarations
.add_type_member_declaration (vfunc
.copy ());
763 vfunc
.block
= vblock
;
765 if (m
.is_abstract
&& m
.source_reference
!= null && m
.source_reference
.comment
!= null) {
766 source_type_member_definition
.append (new
CCodeComment (m
.source_reference
.comment
));
768 source_type_member_definition
.append (vfunc
);
771 private CCodeStatement?
create_method_type_check_statement (Method m
, DataType return_type
, TypeSymbol t
, bool non_null
, string var_name
) {
775 return create_type_check_statement (m
, return_type
, t
, non_null
, var_name
);
779 private CCodeStatement?
create_precondition_statement (CodeNode method_node
, DataType ret_type
, Expression precondition
) {
780 var ccheck
= new
CCodeFunctionCall ();
782 ccheck
.add_argument ((CCodeExpression
) precondition
.ccodenode
);
784 if (ret_type is VoidType
) {
786 ccheck
.call
= new
CCodeIdentifier ("g_return_if_fail");
788 ccheck
.call
= new
CCodeIdentifier ("g_return_val_if_fail");
790 var cdefault
= default_value_for_type (ret_type
, false);
791 if (cdefault
!= null) {
792 ccheck
.add_argument (cdefault
);
798 return new
CCodeExpressionStatement (ccheck
);
801 private CCodeStatement
create_postcondition_statement (Expression postcondition
) {
802 var cassert
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_assert"));
804 cassert
.add_argument ((CCodeExpression
) postcondition
.ccodenode
);
806 return new
CCodeExpressionStatement (cassert
);
809 private TypeSymbol?
find_parent_type (Symbol sym
) {
810 while (sym
!= null) {
811 if (sym is TypeSymbol
) {
812 return (TypeSymbol
) sym
;
814 sym
= sym
.parent_symbol
;
819 private void add_object_creation (CCodeBlock b
, bool has_params
) {
820 var cl
= (Class
) current_type_symbol
;
822 bool chain_up
= false;
823 CreationMethod cm
= null;
824 if (cl
.base_class
!= null) {
825 cm
= cl
.base_class
.default_construction_method as CreationMethod
;
826 if (cm
!= null && cm
.get_parameters ().size
== 0
827 && cm
.has_construct_function
) {
834 if (!has_params
&& !chain_up
835 && cl
.base_class
!= gobject_type
) {
836 // possibly report warning or error about missing base call
839 var cdecl
= new
CCodeVariableDeclarator ("self");
841 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (cm
.get_real_cname ()));
842 ccall
.add_argument (new
CCodeIdentifier ("object_type"));
843 cdecl
.initializer
= new
CCodeCastExpression (ccall
, "%s*".printf (cl
.get_cname ()));
845 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_newv"));
846 ccall
.add_argument (new
CCodeIdentifier ("object_type"));
848 ccall
.add_argument (new
CCodeConstant ("__params_it - __params"));
849 ccall
.add_argument (new
CCodeConstant ("__params"));
851 ccall
.add_argument (new
CCodeConstant ("0"));
852 ccall
.add_argument (new
CCodeConstant ("NULL"));
854 cdecl
.initializer
= ccall
;
857 var cdeclaration
= new
CCodeDeclaration ("%s *".printf (cl
.get_cname ()));
858 cdeclaration
.add_declarator (cdecl
);
860 b
.add_statement (cdeclaration
);
863 public override void visit_creation_method (CreationMethod m
) {
864 bool visible
= !m
.is_internal_symbol ();
866 if (m
.body
!= null && current_type_symbol is Class
&& current_class
.is_subtype_of (gobject_type
)) {
868 foreach (Statement stmt
in m
.body
.get_statements ()) {
869 var expr_stmt
= stmt as ExpressionStatement
;
870 if (expr_stmt
!= null) {
871 Property prop
= expr_stmt
.assigned_property ();
872 if (prop
!= null && prop
.set_accessor
.construction
) {
877 m
.n_construction_params
= n_params
;
880 head
.visit_method (m
);
882 DataType creturn_type
;
883 if (current_type_symbol is Class
) {
884 creturn_type
= new
ObjectType (current_class
);
886 creturn_type
= new
VoidType ();
889 if (current_type_symbol is Class
&& !current_class
.is_compact
) {
890 var vfunc
= new
CCodeFunction (m
.get_cname ());
891 vfunc
.line
= function
.line
;
893 var cparam_map
= new HashMap
<int,CCodeFormalParameter
> (direct_hash
, direct_equal
);
894 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
896 var vblock
= new
CCodeBlock ();
898 var vcall
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_real_cname ()));
899 vcall
.add_argument (new
CCodeIdentifier (current_class
.get_type_id ()));
901 generate_cparameters (m
, cparam_map
, vfunc
, null, carg_map
, vcall
);
902 CCodeStatement cstmt
= new
CCodeReturnStatement (vcall
);
903 cstmt
.line
= vfunc
.line
;
904 vblock
.add_statement (cstmt
);
907 header_declarations
.add_type_member_declaration (vfunc
.copy ());
909 vfunc
.modifiers
|= CCodeModifiers
.STATIC
;
910 source_declarations
.add_type_member_declaration (vfunc
.copy ());
913 vfunc
.block
= vblock
;
915 source_type_member_definition
.append (vfunc
);
918 if (current_type_symbol is Class
&& current_class
.is_subtype_of (gobject_type
)
919 && (((CreationMethod
) m
).n_construction_params
> 0 || current_class
.get_type_parameters ().size
> 0)) {
920 var ccond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.GREATER_THAN
, new
CCodeIdentifier ("__params_it"), new
CCodeIdentifier ("__params"));
921 var cdofreeparam
= new
CCodeBlock ();
922 cdofreeparam
.add_statement (new
CCodeExpressionStatement (new
CCodeUnaryExpression (CCodeUnaryOperator
.PREFIX_DECREMENT
, new
CCodeIdentifier ("__params_it"))));
923 var cunsetcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_unset"));
924 cunsetcall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("__params_it"), "value")));
925 cdofreeparam
.add_statement (new
CCodeExpressionStatement (cunsetcall
));
926 function
.block
.add_statement (new
CCodeWhileStatement (ccond
, cdofreeparam
));
928 var cfreeparams
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_free"));
929 cfreeparams
.add_argument (new
CCodeIdentifier ("__params"));
930 function
.block
.add_statement (new
CCodeExpressionStatement (cfreeparams
));
933 if (current_type_symbol is Class
) {
934 CCodeExpression cresult
= new
CCodeIdentifier ("self");
935 if (get_custom_creturn_type (m
) != null) {
936 cresult
= new
CCodeCastExpression (cresult
, get_custom_creturn_type (m
));
939 var creturn
= new
CCodeReturnStatement ();
940 creturn
.return_expression
= cresult
;
941 function
.block
.add_statement (creturn
);