Fix error handling in try statements nested across method boundaries
[vala-lang.git] / gobject / valaccodemethodmodule.vala
blob822b976d981b0c8cae5afc7e020b69e63c72c6fc
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
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
21 * Raffaele Sandrini <raffaele@sandrini.ch>
24 using GLib;
25 using Gee;
27 /**
28 * The link between a method and generated code.
30 public class Vala.CCodeMethodModule : CCodeStructModule {
31 public CCodeMethodModule (CCodeGenerator codegen, CCodeModule? next) {
32 base (codegen, 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");
41 if (attr != null) {
42 string type = attr.get_string ("type");
43 if (type != null) {
44 return type;
47 return null;
50 string get_creturn_type (Method m, string default_value) {
51 string type = get_custom_creturn_type (m);
52 if (type == null) {
53 return default_value;
55 return type;
58 public override void visit_method (Method m) {
59 var old_type_symbol = current_type_symbol;
60 var old_symbol = current_symbol;
61 Method old_method = current_method;
62 DataType old_return_type = current_return_type;
63 bool old_method_inner_error = current_method_inner_error;
64 int old_next_temp_var_id = next_temp_var_id;
65 var old_variable_name_map = variable_name_map;
66 var old_try = current_try;
67 if (m.parent_symbol is TypeSymbol) {
68 current_type_symbol = (TypeSymbol) m.parent_symbol;
70 current_symbol = m;
71 current_method = m;
72 current_return_type = m.return_type;
73 current_method_inner_error = false;
74 next_temp_var_id = 0;
75 variable_name_map = new HashMap<string,string> (str_hash, str_equal);
76 current_try = null;
78 bool in_gtypeinstance_creation_method = false;
79 bool in_gobject_creation_method = false;
80 bool in_fundamental_creation_method = false;
82 check_type (m.return_type);
84 if (m is CreationMethod) {
85 in_creation_method = true;
86 var cl = current_type_symbol as Class;
87 if (cl != null && !cl.is_compact) {
88 in_gtypeinstance_creation_method = true;
89 if (cl.base_class == null) {
90 in_fundamental_creation_method = true;
91 } else if (cl.is_subtype_of (gobject_type)) {
92 in_gobject_creation_method = true;
96 if (cl != null) {
97 current_return_type = new ObjectType (cl);
101 var creturn_type = current_return_type;
103 m.accept_children (codegen);
105 if (m is CreationMethod) {
106 if (in_gobject_creation_method && m.body != null) {
107 var cblock = new CCodeBlock ();
109 if (!((CreationMethod) m).chain_up) {
110 // set construct properties
111 foreach (CodeNode stmt in m.body.get_statements ()) {
112 var expr_stmt = stmt as ExpressionStatement;
113 if (expr_stmt != null) {
114 var prop = expr_stmt.assigned_property ();
115 if (prop != null && prop.set_accessor.construction) {
116 if (stmt.ccodenode is CCodeFragment) {
117 foreach (CCodeNode cstmt in ((CCodeFragment) stmt.ccodenode).get_children ()) {
118 cblock.add_statement (cstmt);
120 } else {
121 cblock.add_statement (stmt.ccodenode);
127 add_object_creation (cblock, ((CreationMethod) m).n_construction_params > 0 || current_class.get_type_parameters ().size > 0);
128 } else {
129 var cdeclaration = new CCodeDeclaration ("%s *".printf (((Class) current_type_symbol).get_cname ()));
130 cdeclaration.add_declarator (new CCodeVariableDeclarator ("self"));
132 cblock.add_statement (cdeclaration);
135 // other initialization code
136 foreach (CodeNode stmt in m.body.get_statements ()) {
137 var expr_stmt = stmt as ExpressionStatement;
138 if (expr_stmt != null) {
139 var prop = expr_stmt.assigned_property ();
140 if (prop != null && prop.set_accessor.construction) {
141 continue;
144 if (stmt.ccodenode is CCodeFragment) {
145 foreach (CCodeNode cstmt in ((CCodeFragment) stmt.ccodenode).get_children ()) {
146 cblock.add_statement (cstmt);
148 } else {
149 cblock.add_statement (stmt.ccodenode);
153 m.body.ccodenode = cblock;
156 in_creation_method = false;
159 bool inner_error = current_method_inner_error;
161 current_type_symbol = old_type_symbol;
162 current_symbol = old_symbol;
163 current_method = old_method;
164 current_return_type = old_return_type;
165 current_method_inner_error = old_method_inner_error;
166 next_temp_var_id = old_next_temp_var_id;
167 variable_name_map = old_variable_name_map;
168 current_try = old_try;
170 function = new CCodeFunction (m.get_real_cname (), get_creturn_type (m, creturn_type.get_cname ()));
171 m.ccodenode = function;
173 if (m.is_inline) {
174 function.modifiers |= CCodeModifiers.INLINE;
177 var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
179 CCodeFunctionDeclarator vdeclarator = null;
180 if (m.is_abstract || m.is_virtual) {
181 var vdecl = new CCodeDeclaration (get_creturn_type (m, creturn_type.get_cname ()));
182 vdeclarator = new CCodeFunctionDeclarator (m.vfunc_name);
183 vdecl.add_declarator (vdeclarator);
184 type_struct.add_declaration (vdecl);
187 generate_cparameters (m, creturn_type, in_gtypeinstance_creation_method, cparam_map, function, vdeclarator);
189 bool visible = !m.is_internal_symbol ();
191 // generate *_real_* functions for virtual methods
192 // also generate them for abstract methods of classes to prevent faulty subclassing
193 if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
194 if (visible && m.base_method == null && m.base_interface_method == null) {
195 /* public methods need function declaration in
196 * header file except virtual/overridden methods */
197 header_type_member_declaration.append (function.copy ());
198 } else {
199 /* declare all other functions in source file to
200 * avoid dependency on order within source file */
201 function.modifiers |= CCodeModifiers.STATIC;
202 source_type_member_declaration.append (function.copy ());
205 /* Methods imported from a plain C file don't
206 * have a body, e.g. Vala.Parser.parse_file () */
207 if (m.body != null) {
208 function.block = (CCodeBlock) m.body.ccodenode;
209 function.block.line = function.line;
211 var cinit = new CCodeFragment ();
212 function.block.prepend_statement (cinit);
214 if (m.coroutine) {
215 var co_function = new CCodeFunction (m.get_real_cname () + "_co", "gboolean");
217 // data struct to hold parameters, local variables, and the return value
218 co_function.add_parameter (new CCodeFormalParameter ("data", Symbol.lower_case_to_camel_case (m.get_cname ()) + "Data*"));
220 co_function.modifiers |= CCodeModifiers.STATIC;
221 source_type_member_declaration.append (co_function.copy ());
223 var cswitch = new CCodeSwitchStatement (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "state"));
225 // initial coroutine state
226 cswitch.add_statement (new CCodeCaseStatement (new CCodeConstant ("0")));
228 // coroutine body
229 cswitch.add_statement (function.block);
231 // complete async call by invoking callback
232 var object_creation = new CCodeFunctionCall (new CCodeIdentifier ("g_object_newv"));
233 object_creation.add_argument (new CCodeConstant ("G_TYPE_OBJECT"));
234 object_creation.add_argument (new CCodeConstant ("0"));
235 object_creation.add_argument (new CCodeConstant ("NULL"));
237 var async_result_creation = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_new"));
238 async_result_creation.add_argument (object_creation);
239 async_result_creation.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "callback"));
240 async_result_creation.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "user_data"));
241 async_result_creation.add_argument (new CCodeIdentifier ("data"));
243 var completecall = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_complete"));
244 completecall.add_argument (async_result_creation);
245 cswitch.add_statement (new CCodeExpressionStatement (completecall));
247 cswitch.add_statement (new CCodeReturnStatement (new CCodeConstant ("FALSE")));
249 co_function.block = new CCodeBlock ();
250 co_function.block.add_statement (cswitch);
252 source_type_member_definition.append (co_function);
255 if (m.parent_symbol is Class) {
256 var cl = (Class) m.parent_symbol;
257 if (m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
258 Method base_method;
259 ReferenceType base_expression_type;
260 if (m.overrides) {
261 base_method = m.base_method;
262 base_expression_type = new ObjectType ((Class) base_method.parent_symbol);
263 } else {
264 base_method = m.base_interface_method;
265 base_expression_type = new ObjectType ((Interface) base_method.parent_symbol);
267 var self_target_type = new ObjectType (cl);
268 CCodeExpression cself = transform_expression (new CCodeIdentifier ("base"), base_expression_type, self_target_type);
270 var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
271 cdecl.add_declarator (new CCodeVariableDeclarator ("self", cself));
273 cinit.append (cdecl);
274 } else if (m.binding == MemberBinding.INSTANCE
275 && !(m is CreationMethod)) {
276 var ccheckstmt = create_method_type_check_statement (m, creturn_type, cl, true, "self");
277 if (ccheckstmt != null) {
278 ccheckstmt.line = function.line;
279 cinit.append (ccheckstmt);
283 foreach (FormalParameter param in m.get_parameters ()) {
284 if (param.ellipsis) {
285 break;
288 var t = param.parameter_type.data_type;
289 if (t != null && t.is_reference_type ()) {
290 if (param.direction != ParameterDirection.OUT) {
291 var type_check = create_method_type_check_statement (m, creturn_type, t, (context.non_null && !param.parameter_type.nullable), param.name);
292 if (type_check != null) {
293 type_check.line = function.line;
294 cinit.append (type_check);
296 } else {
297 // ensure that the passed reference for output parameter is cleared
298 var a = new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (param.name)), new CCodeConstant ("NULL"));
299 cinit.append (new CCodeExpressionStatement (a));
304 if (inner_error) {
305 /* always separate error parameter and inner_error local variable
306 * as error may be set to NULL but we're always interested in inner errors
308 if (m.coroutine) {
309 closure_struct.add_field ("GError *", "inner_error");
311 // no initialization necessary, closure struct is zeroed
312 } else {
313 var cdecl = new CCodeDeclaration ("GError *");
314 cdecl.add_declarator (new CCodeVariableDeclarator ("inner_error", new CCodeConstant ("NULL")));
315 cinit.append (cdecl);
319 if (!m.coroutine) {
320 if (m.source_reference != null && m.source_reference.comment != null) {
321 source_type_member_definition.append (new CCodeComment (m.source_reference.comment));
323 source_type_member_definition.append (function);
326 if (m is CreationMethod) {
327 if (in_gobject_creation_method) {
328 int n_params = ((CreationMethod) m).n_construction_params;
330 if (n_params > 0 || current_class.get_type_parameters ().size > 0) {
331 // declare construction parameter array
332 var cparamsinit = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
333 cparamsinit.add_argument (new CCodeIdentifier ("GParameter"));
334 cparamsinit.add_argument (new CCodeConstant ((n_params + 3 * current_class.get_type_parameters ().size).to_string ()));
336 var cdecl = new CCodeDeclaration ("GParameter *");
337 cdecl.add_declarator (new CCodeVariableDeclarator ("__params", cparamsinit));
338 cinit.append (cdecl);
340 cdecl = new CCodeDeclaration ("GParameter *");
341 cdecl.add_declarator (new CCodeVariableDeclarator ("__params_it", new CCodeIdentifier ("__params")));
342 cinit.append (cdecl);
345 /* type, dup func, and destroy func properties for generic types */
346 foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
347 CCodeConstant prop_name;
348 CCodeIdentifier param_name;
350 prop_name = new CCodeConstant ("\"%s-type\"".printf (type_param.name.down ()));
351 param_name = new CCodeIdentifier ("%s_type".printf (type_param.name.down ()));
352 cinit.append (new CCodeExpressionStatement (get_construct_property_assignment (prop_name, new IntegerType ((Struct) gtype_type), param_name)));
354 prop_name = new CCodeConstant ("\"%s-dup-func\"".printf (type_param.name.down ()));
355 param_name = new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ()));
356 cinit.append (new CCodeExpressionStatement (get_construct_property_assignment (prop_name, new PointerType (new VoidType ()), param_name)));
358 prop_name = new CCodeConstant ("\"%s-destroy-func\"".printf (type_param.name.down ()));
359 param_name = new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ()));
360 cinit.append (new CCodeExpressionStatement (get_construct_property_assignment (prop_name, new PointerType (new VoidType ()), param_name)));
362 } else if (in_gtypeinstance_creation_method) {
363 var cl = (Class) m.parent_symbol;
364 var cdeclaration = new CCodeDeclaration (cl.get_cname () + "*");
365 var cdecl = new CCodeVariableDeclarator ("self");
366 cdeclaration.add_declarator (cdecl);
367 cinit.append (cdeclaration);
369 if (!((CreationMethod) m).chain_up) {
370 // TODO implicitly chain up to base class as in add_object_creation
371 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_create_instance"));
372 ccall.add_argument (new CCodeIdentifier ("object_type"));
373 cdecl.initializer = new CCodeCastExpression (ccall, cl.get_cname () + "*");
376 /* type, dup func, and destroy func fields for generic types */
377 foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
378 CCodeIdentifier param_name;
379 CCodeAssignment assign;
381 var priv_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv");
383 param_name = new CCodeIdentifier ("%s_type".printf (type_param.name.down ()));
384 assign = new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name);
385 cinit.append (new CCodeExpressionStatement (assign));
387 param_name = new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ()));
388 assign = new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name);
389 cinit.append (new CCodeExpressionStatement (assign));
391 param_name = new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ()));
392 assign = new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name);
393 cinit.append (new CCodeExpressionStatement (assign));
395 } else if (current_type_symbol is Class) {
396 var cl = (Class) m.parent_symbol;
397 var cdecl = new CCodeDeclaration (cl.get_cname () + "*");
398 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
399 ccall.add_argument (new CCodeIdentifier (cl.get_cname ()));
400 cdecl.add_declarator (new CCodeVariableDeclarator ("self", ccall));
401 cinit.append (cdecl);
403 var cinitcall = new CCodeFunctionCall (new CCodeIdentifier ("%s_instance_init".printf (cl.get_lower_case_cname (null))));
404 cinitcall.add_argument (new CCodeIdentifier ("self"));
405 cinit.append (new CCodeExpressionStatement (cinitcall));
406 } else {
407 var st = (Struct) m.parent_symbol;
409 // memset needs string.h
410 string_h_needed = true;
411 var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
412 czero.add_argument (new CCodeIdentifier ("self"));
413 czero.add_argument (new CCodeConstant ("0"));
414 czero.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (st.get_cname ())));
415 cinit.append (new CCodeExpressionStatement (czero));
419 if (context.module_init_method == m && in_plugin) {
420 // GTypeModule-based plug-in, register types
421 cinit.append (module_init_fragment);
424 foreach (Expression precondition in m.get_preconditions ()) {
425 var check_stmt = create_precondition_statement (m, creturn_type, precondition);
426 if (check_stmt != null) {
427 cinit.append (check_stmt);
430 } else if (m.is_abstract) {
431 // generate helpful error message if a sublcass does not implement an abstract method.
432 // This is only meaningful for subclasses implemented in C since the vala compiler would
433 // complain during compile time of such en error.
435 var cblock = new CCodeBlock ();
437 // add a typecheck statement for "self"
438 var check_stmt = create_method_type_check_statement (m, creturn_type, current_type_symbol, true, "self");
439 if (check_stmt != null) {
440 cblock.add_statement (check_stmt);
443 // add critical warning that this method should not have been called
444 var type_from_instance_call = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_FROM_INSTANCE"));
445 type_from_instance_call.add_argument (new CCodeIdentifier ("self"));
447 var type_name_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_name"));
448 type_name_call.add_argument (type_from_instance_call);
450 var error_string = "\"Type `%%s' does not implement abstract method `%s'\"".printf (m.get_cname ());
452 var cerrorcall = new CCodeFunctionCall (new CCodeIdentifier ("g_critical"));
453 cerrorcall.add_argument (new CCodeConstant (error_string));
454 cerrorcall.add_argument (type_name_call);
456 cblock.add_statement (new CCodeExpressionStatement (cerrorcall));
458 // add return statement
459 cblock.add_statement (new CCodeReturnStatement (default_value_for_type (creturn_type, false)));
461 function.block = cblock;
462 source_type_member_definition.append (function);
466 if (m.is_abstract || m.is_virtual) {
467 cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
468 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
470 generate_vfunc (m, creturn_type, cparam_map, carg_map);
473 if (m.entry_point) {
474 // m is possible entry point, add appropriate startup code
475 var cmain = new CCodeFunction ("main", "int");
476 cmain.line = function.line;
477 cmain.add_parameter (new CCodeFormalParameter ("argc", "int"));
478 cmain.add_parameter (new CCodeFormalParameter ("argv", "char **"));
479 var main_block = new CCodeBlock ();
481 if (context.thread) {
482 var thread_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_thread_init"));
483 thread_init_call.line = cmain.line;
484 thread_init_call.add_argument (new CCodeConstant ("NULL"));
485 main_block.add_statement (new CCodeExpressionStatement (thread_init_call));
488 var type_init_call = new CCodeExpressionStatement (new CCodeFunctionCall (new CCodeIdentifier ("g_type_init")));
489 type_init_call.line = cmain.line;
490 main_block.add_statement (type_init_call);
492 var main_call = new CCodeFunctionCall (new CCodeIdentifier (function.name));
493 if (m.get_parameters ().size == 1) {
494 main_call.add_argument (new CCodeIdentifier ("argv"));
495 main_call.add_argument (new CCodeIdentifier ("argc"));
497 if (m.return_type is VoidType) {
498 // method returns void, always use 0 as exit code
499 var main_stmt = new CCodeExpressionStatement (main_call);
500 main_stmt.line = cmain.line;
501 main_block.add_statement (main_stmt);
502 var ret_stmt = new CCodeReturnStatement (new CCodeConstant ("0"));
503 ret_stmt.line = cmain.line;
504 main_block.add_statement (ret_stmt);
505 } else {
506 var main_stmt = new CCodeReturnStatement (main_call);
507 main_stmt.line = cmain.line;
508 main_block.add_statement (main_stmt);
510 cmain.block = main_block;
511 source_type_member_definition.append (cmain);
515 public override void generate_cparameters (Method m, DataType creturn_type, bool in_gtypeinstance_creation_method, Map<int,CCodeFormalParameter> cparam_map, CCodeFunction func, CCodeFunctionDeclarator? vdeclarator = null, Map<int,CCodeExpression>? carg_map = null, CCodeFunctionCall? vcall = null, int direction = 3) {
516 if (m.parent_symbol is Class && m is CreationMethod) {
517 var cl = (Class) m.parent_symbol;
518 if (!cl.is_compact && vcall == null) {
519 cparam_map.set (get_param_pos (m.cinstance_parameter_position), new CCodeFormalParameter ("object_type", "GType"));
521 } else if (m.binding == MemberBinding.INSTANCE || (m.parent_symbol is Struct && m is CreationMethod)) {
522 TypeSymbol parent_type = find_parent_type (m);
523 DataType this_type;
524 if (parent_type is Class) {
525 this_type = new ObjectType ((Class) parent_type);
526 } else if (parent_type is Interface) {
527 this_type = new ObjectType ((Interface) parent_type);
528 } else if (parent_type is Struct) {
529 this_type = new StructValueType ((Struct) parent_type);
530 } else if (parent_type is Enum) {
531 this_type = new EnumValueType ((Enum) parent_type);
532 } else {
533 assert_not_reached ();
536 CCodeFormalParameter instance_param = null;
537 if (m.base_interface_method != null && !m.is_abstract && !m.is_virtual) {
538 var base_type = new ObjectType ((Interface) m.base_interface_method.parent_symbol);
539 instance_param = new CCodeFormalParameter ("base", base_type.get_cname ());
540 } else if (m.overrides) {
541 var base_type = new ObjectType ((Class) m.base_method.parent_symbol);
542 instance_param = new CCodeFormalParameter ("base", base_type.get_cname ());
543 } else {
544 if (m.parent_symbol is Struct && !((Struct) m.parent_symbol).is_simple_type ()) {
545 instance_param = new CCodeFormalParameter ("*self", this_type.get_cname ());
546 } else {
547 instance_param = new CCodeFormalParameter ("self", this_type.get_cname ());
550 cparam_map.set (get_param_pos (m.cinstance_parameter_position), instance_param);
551 } else if (m.binding == MemberBinding.CLASS) {
552 TypeSymbol parent_type = find_parent_type (m);
553 DataType this_type;
554 this_type = new ClassType ((Class) parent_type);
555 var class_param = new CCodeFormalParameter ("klass", this_type.get_cname ());
556 cparam_map.set (get_param_pos (m.cinstance_parameter_position), class_param);
559 if (in_gtypeinstance_creation_method) {
560 // memory management for generic types
561 int type_param_index = 0;
562 foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
563 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeFormalParameter ("%s_type".printf (type_param.name.down ()), "GType"));
564 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeFormalParameter ("%s_dup_func".printf (type_param.name.down ()), "GBoxedCopyFunc"));
565 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeFormalParameter ("%s_destroy_func".printf (type_param.name.down ()), "GDestroyNotify"));
566 if (carg_map != null) {
567 carg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier ("%s_type".printf (type_param.name.down ())));
568 carg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ())));
569 carg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ())));
571 type_param_index++;
575 foreach (FormalParameter param in m.get_parameters ()) {
576 if (param.direction != ParameterDirection.OUT) {
577 if ((direction & 1) == 0) {
578 // no in paramters
579 continue;
581 } else {
582 if ((direction & 2) == 0) {
583 // no out paramters
584 continue;
588 if (!param.no_array_length && param.parameter_type is ArrayType) {
589 var array_type = (ArrayType) param.parameter_type;
591 var length_ctype = "int";
592 if (param.direction != ParameterDirection.IN) {
593 length_ctype = "int*";
596 for (int dim = 1; dim <= array_type.rank; dim++) {
597 var cparam = new CCodeFormalParameter (head.get_array_length_cname (param.name, dim), length_ctype);
598 cparam_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), cparam);
599 if (carg_map != null) {
600 carg_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), new CCodeIdentifier (cparam.name));
605 cparam_map.set (get_param_pos (param.cparameter_position), (CCodeFormalParameter) param.ccodenode);
606 if (carg_map != null) {
607 carg_map.set (get_param_pos (param.cparameter_position), new CCodeIdentifier (param.name));
610 if (param.parameter_type is DelegateType) {
611 var deleg_type = (DelegateType) param.parameter_type;
612 var d = deleg_type.delegate_symbol;
613 if (d.has_target) {
614 var cparam = new CCodeFormalParameter (get_delegate_target_cname (param.name), "void*");
615 cparam_map.set (get_param_pos (param.cdelegate_target_parameter_position), cparam);
616 if (carg_map != null) {
617 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), new CCodeIdentifier (cparam.name));
619 if (deleg_type.value_owned) {
620 cparam = new CCodeFormalParameter (get_delegate_target_destroy_notify_cname (param.name), "GDestroyNotify");
621 cparam_map.set (get_param_pos (param.cdelegate_target_parameter_position + 0.01), cparam);
622 if (carg_map != null) {
623 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position + 0.01), new CCodeIdentifier (cparam.name));
627 } else if (param.parameter_type is MethodType) {
628 var cparam = new CCodeFormalParameter (get_delegate_target_cname (param.name), "void*");
629 cparam_map.set (get_param_pos (param.cdelegate_target_parameter_position), cparam);
630 if (carg_map != null) {
631 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), new CCodeIdentifier (cparam.name));
636 if ((direction & 2) != 0) {
637 if (!m.no_array_length && creturn_type is ArrayType) {
638 // return array length if appropriate
639 var array_type = (ArrayType) creturn_type;
641 for (int dim = 1; dim <= array_type.rank; dim++) {
642 var cparam = new CCodeFormalParameter (head.get_array_length_cname ("result", dim), "int*");
643 cparam_map.set (get_param_pos (m.carray_length_parameter_position + 0.01 * dim), cparam);
644 if (carg_map != null) {
645 carg_map.set (get_param_pos (m.carray_length_parameter_position + 0.01 * dim), new CCodeIdentifier (cparam.name));
648 } else if (creturn_type is DelegateType) {
649 // return delegate target if appropriate
650 var deleg_type = (DelegateType) creturn_type;
651 var d = deleg_type.delegate_symbol;
652 if (d.has_target) {
653 var cparam = new CCodeFormalParameter (get_delegate_target_cname ("result"), "void*");
654 cparam_map.set (get_param_pos (m.cdelegate_target_parameter_position), cparam);
655 if (carg_map != null) {
656 carg_map.set (get_param_pos (m.cdelegate_target_parameter_position), new CCodeIdentifier (cparam.name));
661 if (m.get_error_types ().size > 0) {
662 var cparam = new CCodeFormalParameter ("error", "GError**");
663 cparam_map.set (get_param_pos (-1), cparam);
664 if (carg_map != null) {
665 carg_map.set (get_param_pos (-1), new CCodeIdentifier (cparam.name));
670 // append C parameters in the right order
671 int last_pos = -1;
672 int min_pos;
673 while (true) {
674 min_pos = -1;
675 foreach (int pos in cparam_map.get_keys ()) {
676 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
677 min_pos = pos;
680 if (min_pos == -1) {
681 break;
683 func.add_parameter (cparam_map.get (min_pos));
684 if (vdeclarator != null) {
685 vdeclarator.add_parameter (cparam_map.get (min_pos));
687 if (vcall != null) {
688 vcall.add_argument (carg_map.get (min_pos));
690 last_pos = min_pos;
694 public void generate_vfunc (Method m, DataType return_type, Map<int,CCodeFormalParameter> cparam_map, Map<int,CCodeExpression> carg_map, string suffix = "", int direction = 3) {
695 bool visible = !m.is_internal_symbol ();
697 var vfunc = new CCodeFunction (m.get_cname () + suffix, return_type.get_cname ());
698 vfunc.line = function.line;
700 var vblock = new CCodeBlock ();
702 foreach (Expression precondition in m.get_preconditions ()) {
703 var check_stmt = create_precondition_statement (m, return_type, precondition);
704 if (check_stmt != null) {
705 vblock.add_statement (check_stmt);
709 CCodeFunctionCall vcast = null;
710 if (m.parent_symbol is Interface) {
711 var iface = (Interface) m.parent_symbol;
713 vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (iface.get_upper_case_cname (null))));
714 } else {
715 var cl = (Class) m.parent_symbol;
717 vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (cl.get_upper_case_cname (null))));
719 vcast.add_argument (new CCodeIdentifier ("self"));
721 var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, m.vfunc_name + suffix));
722 carg_map.set (get_param_pos (m.cinstance_parameter_position), new CCodeIdentifier ("self"));
724 generate_cparameters (m, return_type, false, cparam_map, vfunc, null, carg_map, vcall, direction);
726 CCodeStatement cstmt;
727 if (return_type is VoidType) {
728 cstmt = new CCodeExpressionStatement (vcall);
729 } else if (m.get_postconditions ().size == 0) {
730 /* pass method return value */
731 cstmt = new CCodeReturnStatement (vcall);
732 } else {
733 /* store method return value for postconditions */
734 var cdecl = new CCodeDeclaration (get_creturn_type (m, return_type.get_cname ()));
735 cdecl.add_declarator (new CCodeVariableDeclarator ("result", vcall));
736 cstmt = cdecl;
738 cstmt.line = vfunc.line;
739 vblock.add_statement (cstmt);
741 if (m.get_postconditions ().size > 0) {
742 foreach (Expression postcondition in m.get_postconditions ()) {
743 vblock.add_statement (create_postcondition_statement (postcondition));
746 if (!(return_type is VoidType)) {
747 var cret_stmt = new CCodeReturnStatement (new CCodeIdentifier ("result"));
748 cret_stmt.line = vfunc.line;
749 vblock.add_statement (cret_stmt);
753 if (visible) {
754 header_type_member_declaration.append (vfunc.copy ());
755 } else {
756 vfunc.modifiers |= CCodeModifiers.STATIC;
757 source_type_member_declaration.append (vfunc.copy ());
760 vfunc.block = vblock;
762 if (m.is_abstract && m.source_reference != null && m.source_reference.comment != null) {
763 source_type_member_definition.append (new CCodeComment (m.source_reference.comment));
765 source_type_member_definition.append (vfunc);
768 private CCodeStatement? create_method_type_check_statement (Method m, DataType return_type, TypeSymbol t, bool non_null, string var_name) {
769 if (m.coroutine) {
770 return null;
771 } else {
772 return create_type_check_statement (m, return_type, t, non_null, var_name);
776 private CCodeStatement? create_precondition_statement (CodeNode method_node, DataType ret_type, Expression precondition) {
777 var ccheck = new CCodeFunctionCall ();
779 ccheck.add_argument ((CCodeExpression) precondition.ccodenode);
781 if (ret_type is VoidType) {
782 /* void function */
783 ccheck.call = new CCodeIdentifier ("g_return_if_fail");
784 } else {
785 ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
787 var cdefault = default_value_for_type (ret_type, false);
788 if (cdefault != null) {
789 ccheck.add_argument (cdefault);
790 } else {
791 return null;
795 return new CCodeExpressionStatement (ccheck);
798 private CCodeStatement create_postcondition_statement (Expression postcondition) {
799 var cassert = new CCodeFunctionCall (new CCodeIdentifier ("g_assert"));
801 cassert.add_argument ((CCodeExpression) postcondition.ccodenode);
803 return new CCodeExpressionStatement (cassert);
806 private TypeSymbol? find_parent_type (Symbol sym) {
807 while (sym != null) {
808 if (sym is TypeSymbol) {
809 return (TypeSymbol) sym;
811 sym = sym.parent_symbol;
813 return null;
816 private void add_object_creation (CCodeBlock b, bool has_params) {
817 var cl = (Class) current_type_symbol;
819 bool chain_up = false;
820 CreationMethod cm = null;
821 if (cl.base_class != null) {
822 cm = cl.base_class.default_construction_method as CreationMethod;
823 if (cm != null && cm.get_parameters ().size == 0
824 && cm.has_construct_function) {
825 if (!has_params) {
826 chain_up = true;
831 if (!has_params && !chain_up
832 && cl.base_class != gobject_type) {
833 // possibly report warning or error about missing base call
836 var cdecl = new CCodeVariableDeclarator ("self");
837 if (chain_up) {
838 var ccall = new CCodeFunctionCall (new CCodeIdentifier (cm.get_real_cname ()));
839 ccall.add_argument (new CCodeIdentifier ("object_type"));
840 cdecl.initializer = new CCodeCastExpression (ccall, "%s*".printf (cl.get_cname ()));
841 } else {
842 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_newv"));
843 ccall.add_argument (new CCodeIdentifier ("object_type"));
844 if (has_params) {
845 ccall.add_argument (new CCodeConstant ("__params_it - __params"));
846 ccall.add_argument (new CCodeConstant ("__params"));
847 } else {
848 ccall.add_argument (new CCodeConstant ("0"));
849 ccall.add_argument (new CCodeConstant ("NULL"));
851 cdecl.initializer = ccall;
854 var cdeclaration = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
855 cdeclaration.add_declarator (cdecl);
857 b.add_statement (cdeclaration);
860 public override void visit_creation_method (CreationMethod m) {
861 bool visible = !m.is_internal_symbol ();
863 if (m.body != null && current_type_symbol is Class && current_class.is_subtype_of (gobject_type)) {
864 int n_params = 0;
865 foreach (Statement stmt in m.body.get_statements ()) {
866 var expr_stmt = stmt as ExpressionStatement;
867 if (expr_stmt != null) {
868 Property prop = expr_stmt.assigned_property ();
869 if (prop != null && prop.set_accessor.construction) {
870 n_params++;
874 m.n_construction_params = n_params;
877 head.visit_method (m);
879 DataType creturn_type;
880 if (current_type_symbol is Class) {
881 creturn_type = new ObjectType (current_class);
882 } else {
883 creturn_type = new VoidType ();
886 if (current_type_symbol is Class && !current_class.is_compact) {
887 var vfunc = new CCodeFunction (m.get_cname (), creturn_type.get_cname ());
888 vfunc.line = function.line;
890 var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
891 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
893 var vblock = new CCodeBlock ();
895 var vcall = new CCodeFunctionCall (new CCodeIdentifier (m.get_real_cname ()));
896 vcall.add_argument (new CCodeIdentifier (current_class.get_type_id ()));
898 generate_cparameters (m, creturn_type, true, cparam_map, vfunc, null, carg_map, vcall);
899 CCodeStatement cstmt = new CCodeReturnStatement (vcall);
900 cstmt.line = vfunc.line;
901 vblock.add_statement (cstmt);
903 if (visible) {
904 header_type_member_declaration.append (vfunc.copy ());
905 } else {
906 vfunc.modifiers |= CCodeModifiers.STATIC;
907 source_type_member_declaration.append (vfunc.copy ());
910 vfunc.block = vblock;
912 source_type_member_definition.append (vfunc);
915 if (current_type_symbol is Class && current_class.is_subtype_of (gobject_type)
916 && (((CreationMethod) m).n_construction_params > 0 || current_class.get_type_parameters ().size > 0)) {
917 var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, new CCodeIdentifier ("__params_it"), new CCodeIdentifier ("__params"));
918 var cdofreeparam = new CCodeBlock ();
919 cdofreeparam.add_statement (new CCodeExpressionStatement (new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, new CCodeIdentifier ("__params_it"))));
920 var cunsetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_unset"));
921 cunsetcall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("__params_it"), "value")));
922 cdofreeparam.add_statement (new CCodeExpressionStatement (cunsetcall));
923 function.block.add_statement (new CCodeWhileStatement (ccond, cdofreeparam));
925 var cfreeparams = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
926 cfreeparams.add_argument (new CCodeIdentifier ("__params"));
927 function.block.add_statement (new CCodeExpressionStatement (cfreeparams));
930 if (current_type_symbol is Class) {
931 CCodeExpression cresult = new CCodeIdentifier ("self");
932 if (get_custom_creturn_type (m) != null) {
933 cresult = new CCodeCastExpression (cresult, get_custom_creturn_type (m));
936 var creturn = new CCodeReturnStatement ();
937 creturn.return_expression = cresult;
938 function.block.add_statement (creturn);