libgda-4.0, gedit-2.20: Fix gedit typo and GdaXaTransactionId.data
[vala-lang.git] / codegen / valaccodemethodmodule.vala
blob96355a72452318ced2a3eb5a5dd4bc901be8e948
1 /* valaccodemethodmodule.vala
3 * Copyright (C) 2007-2010 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
21 * Raffaele Sandrini <raffaele@sandrini.ch>
24 using GLib;
26 /**
27 * The link between a method and generated code.
29 public abstract class Vala.CCodeMethodModule : CCodeStructModule {
30 public override bool method_has_wrapper (Method method) {
31 return (method.get_attribute ("NoWrapper") == null);
34 public override string? get_custom_creturn_type (Method m) {
35 var attr = m.get_attribute ("CCode");
36 if (attr != null) {
37 string type = attr.get_string ("type");
38 if (type != null) {
39 return type;
42 return null;
45 string get_creturn_type (Method m, string default_value) {
46 string type = get_custom_creturn_type (m);
47 if (type == null) {
48 return default_value;
50 return type;
53 bool is_gtypeinstance_creation_method (Method m) {
54 bool result = false;
56 var cl = m.parent_symbol as Class;
57 if (m is CreationMethod && cl != null && !cl.is_compact) {
58 result = true;
61 return result;
64 public virtual void generate_method_result_declaration (Method m, CCodeFile decl_space, CCodeFunction cfunc, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
65 var creturn_type = m.return_type;
66 if (m is CreationMethod) {
67 var cl = m.parent_symbol as Class;
68 if (cl != null) {
69 // object creation methods return the new object in C
70 // in Vala they have no return type
71 creturn_type = new ObjectType (cl);
73 } else if (m.return_type.is_real_non_null_struct_type ()) {
74 // structs are returned via out parameter
75 creturn_type = new VoidType ();
77 cfunc.return_type = get_creturn_type (m, creturn_type.get_cname ());
79 generate_type_declaration (m.return_type, decl_space);
81 if (m.return_type.is_real_non_null_struct_type ()) {
82 // structs are returned via out parameter
83 var cparam = new CCodeParameter ("result", m.return_type.get_cname () + "*");
84 cparam_map.set (get_param_pos (-3), cparam);
85 if (carg_map != null) {
86 carg_map.set (get_param_pos (-3), get_result_cexpression ());
88 } else if (!m.no_array_length && m.return_type is ArrayType) {
89 // return array length if appropriate
90 var array_type = (ArrayType) m.return_type;
91 var array_length_type = m.array_length_type != null ? m.array_length_type : "int";
92 array_length_type += "*";
94 for (int dim = 1; dim <= array_type.rank; dim++) {
95 var cparam = new CCodeParameter (get_array_length_cname ("result", dim), array_length_type);
96 cparam_map.set (get_param_pos (m.carray_length_parameter_position + 0.01 * dim), cparam);
97 if (carg_map != null) {
98 carg_map.set (get_param_pos (m.carray_length_parameter_position + 0.01 * dim), get_variable_cexpression (cparam.name));
101 } else if (m.return_type is DelegateType) {
102 // return delegate target if appropriate
103 var deleg_type = (DelegateType) m.return_type;
104 var d = deleg_type.delegate_symbol;
105 if (d.has_target) {
106 var cparam = new CCodeParameter (get_delegate_target_cname ("result"), "void**");
107 cparam_map.set (get_param_pos (m.cdelegate_target_parameter_position), cparam);
108 if (carg_map != null) {
109 carg_map.set (get_param_pos (m.cdelegate_target_parameter_position), get_variable_cexpression (cparam.name));
111 if (deleg_type.value_owned) {
112 cparam = new CCodeParameter (get_delegate_target_destroy_notify_cname ("result"), "GDestroyNotify*");
113 cparam_map.set (get_param_pos (m.cdelegate_target_parameter_position + 0.01), cparam);
114 if (carg_map != null) {
115 carg_map.set (get_param_pos (m.cdelegate_target_parameter_position + 0.01), get_variable_cexpression (cparam.name));
121 if (m.get_error_types ().size > 0 || (m.base_method != null && m.base_method.get_error_types ().size > 0) || (m.base_interface_method != null && m.base_interface_method.get_error_types ().size > 0)) {
122 foreach (DataType error_type in m.get_error_types ()) {
123 generate_type_declaration (error_type, decl_space);
126 var cparam = new CCodeParameter ("error", "GError**");
127 cparam_map.set (get_param_pos (-1), cparam);
128 if (carg_map != null) {
129 carg_map.set (get_param_pos (-1), new CCodeIdentifier (cparam.name));
134 public void complete_async () {
135 var state = new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "_state_");
136 var zero = new CCodeConstant ("0");
137 var state_is_zero = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, state, zero);
138 ccode.open_if (state_is_zero);
140 var async_result_expr = new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "_async_result");
142 var idle_call = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_complete_in_idle"));
143 idle_call.add_argument (async_result_expr);
144 ccode.add_expression (idle_call);
146 ccode.add_else ();
148 var direct_call = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_complete"));
149 direct_call.add_argument (async_result_expr);
150 ccode.add_expression (direct_call);
152 ccode.close ();
154 var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
155 unref.add_argument (async_result_expr);
156 ccode.add_expression (unref);
158 ccode.add_return (new CCodeConstant ("FALSE"));
161 public override void generate_method_declaration (Method m, CCodeFile decl_space) {
162 if (m.is_async_callback) {
163 return;
165 if (add_symbol_declaration (decl_space, m, m.get_cname ())) {
166 return;
169 var function = new CCodeFunction (m.get_cname ());
171 if (m.is_private_symbol () && !m.external) {
172 function.modifiers |= CCodeModifiers.STATIC;
173 if (m.is_inline) {
174 function.modifiers |= CCodeModifiers.INLINE;
178 if (m.deprecated) {
179 function.modifiers |= CCodeModifiers.DEPRECATED;
182 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
183 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
185 var cl = m.parent_symbol as Class;
187 // do not generate _new functions for creation methods of abstract classes
188 if (!(m is CreationMethod && cl != null && cl.is_abstract)) {
189 generate_cparameters (m, decl_space, cparam_map, function, null, carg_map, new CCodeFunctionCall (new CCodeIdentifier ("fake")));
191 decl_space.add_function_declaration (function);
194 if (m is CreationMethod && cl != null) {
195 // _construct function
196 function = new CCodeFunction (m.get_real_cname ());
198 if (m.is_private_symbol ()) {
199 function.modifiers |= CCodeModifiers.STATIC;
202 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
203 generate_cparameters (m, decl_space, cparam_map, function);
205 decl_space.add_function_declaration (function);
209 void register_plugin_types (Symbol sym, Set<Symbol> registered_types) {
210 var ns = sym as Namespace;
211 var cl = sym as Class;
212 var iface = sym as Interface;
213 if (ns != null) {
214 foreach (var ns_ns in ns.get_namespaces ()) {
215 register_plugin_types (ns_ns, registered_types);
217 foreach (var ns_cl in ns.get_classes ()) {
218 register_plugin_types (ns_cl, registered_types);
220 foreach (var ns_iface in ns.get_interfaces ()) {
221 register_plugin_types (ns_iface, registered_types);
223 } else if (cl != null) {
224 register_plugin_type (cl, registered_types);
225 foreach (var cl_cl in cl.get_classes ()) {
226 register_plugin_types (cl_cl, registered_types);
228 } else if (iface != null) {
229 register_plugin_type (iface, registered_types);
230 foreach (var iface_cl in iface.get_classes ()) {
231 register_plugin_types (iface_cl, registered_types);
236 void register_plugin_type (ObjectTypeSymbol type_symbol, Set<Symbol> registered_types) {
237 if (type_symbol.external_package) {
238 return;
241 if (!registered_types.add (type_symbol)) {
242 // already registered
243 return;
246 var cl = type_symbol as Class;
247 if (cl != null) {
248 if (cl.is_compact) {
249 return;
252 // register base types first
253 foreach (var base_type in cl.get_base_types ()) {
254 register_plugin_type ((ObjectTypeSymbol) base_type.data_type, registered_types);
258 var register_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_register_type".printf (type_symbol.get_lower_case_cname (null))));
259 register_call.add_argument (new CCodeIdentifier (module_init_param_name));
260 ccode.add_expression (register_call);
263 public override void visit_method (Method m) {
264 push_context (new EmitContext (m));
266 bool in_gobject_creation_method = false;
267 bool in_fundamental_creation_method = false;
269 check_type (m.return_type);
271 if (m is CreationMethod) {
272 var cl = current_type_symbol as Class;
273 if (cl != null && !cl.is_compact) {
274 if (cl.base_class == null) {
275 in_fundamental_creation_method = true;
276 } else if (gobject_type != null && cl.is_subtype_of (gobject_type)) {
277 in_gobject_creation_method = true;
282 if (m.coroutine) {
283 next_coroutine_state = 1;
286 var creturn_type = m.return_type;
287 if (m.return_type.is_real_non_null_struct_type ()) {
288 // structs are returned via out parameter
289 creturn_type = new VoidType ();
292 if (m.binding == MemberBinding.CLASS || m.binding == MemberBinding.STATIC) {
293 in_static_or_class_context = true;
297 foreach (Parameter param in m.get_parameters ()) {
298 param.accept (this);
301 // do not declare overriding methods and interface implementations
302 if (m.is_abstract || m.is_virtual
303 || (m.base_method == null && m.base_interface_method == null)) {
304 generate_method_declaration (m, cfile);
306 if (!m.is_internal_symbol ()) {
307 generate_method_declaration (m, header_file);
309 if (!m.is_private_symbol ()) {
310 generate_method_declaration (m, internal_header_file);
314 CCodeFunction function;
315 function = new CCodeFunction (m.get_real_cname ());
317 if (m.is_inline) {
318 function.modifiers |= CCodeModifiers.INLINE;
321 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
323 generate_cparameters (m, cfile, cparam_map, function);
325 // generate *_real_* functions for virtual methods
326 // also generate them for abstract methods of classes to prevent faulty subclassing
327 if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
328 if (!m.coroutine) {
329 if (m.base_method != null || m.base_interface_method != null) {
330 // declare *_real_* function
331 function.modifiers |= CCodeModifiers.STATIC;
332 cfile.add_function_declaration (function);
333 } else if (m.is_private_symbol ()) {
334 function.modifiers |= CCodeModifiers.STATIC;
336 } else {
337 if (m.body != null) {
338 function = new CCodeFunction (m.get_real_cname () + "_co", "gboolean");
340 // data struct to hold parameters, local variables, and the return value
341 function.add_parameter (new CCodeParameter ("data", Symbol.lower_case_to_camel_case (m.get_cname ()) + "Data*"));
343 function.modifiers |= CCodeModifiers.STATIC;
344 cfile.add_function_declaration (function);
349 if (m.comment != null) {
350 cfile.add_type_member_definition (new CCodeComment (m.comment.content));
353 push_function (function);
355 // generate *_real_* functions for virtual methods
356 // also generate them for abstract methods of classes to prevent faulty subclassing
357 if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
358 if (m.body != null) {
359 if (m.coroutine) {
360 ccode.open_switch (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "_state_"));
362 // initial coroutine state
363 ccode.add_case (new CCodeConstant ("0"));
364 ccode.add_goto ("_state_0");
366 for (int state = 1; state <= m.yield_count; state++) {
367 ccode.add_case (new CCodeConstant (state.to_string ()));
368 ccode.add_goto ("_state_%d".printf (state));
372 // let gcc know that this can't happen
373 ccode.add_default ();
374 ccode.add_expression (new CCodeFunctionCall (new CCodeIdentifier ("g_assert_not_reached")));
376 ccode.close ();
378 // coroutine body
379 ccode.add_label ("_state_0");
382 if (m.closure) {
383 // add variables for parent closure blocks
384 // as closures only have one parameter for the innermost closure block
385 var closure_block = current_closure_block;
386 int block_id = get_block_id (closure_block);
387 while (true) {
388 var parent_closure_block = next_closure_block (closure_block.parent_symbol);
389 if (parent_closure_block == null) {
390 break;
392 int parent_block_id = get_block_id (parent_closure_block);
394 var parent_data = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id));
395 ccode.add_declaration ("Block%dData*".printf (parent_block_id), new CCodeVariableDeclarator ("_data%d_".printf (parent_block_id)));
396 ccode.add_assignment (new CCodeIdentifier ("_data%d_".printf (parent_block_id)), parent_data);
398 closure_block = parent_closure_block;
399 block_id = parent_block_id;
402 // add self variable for closures
403 // as closures have block data parameter
404 if (m.binding == MemberBinding.INSTANCE) {
405 var cself = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "self");
406 ccode.add_declaration ("%s *".printf (current_class.get_cname ()), new CCodeVariableDeclarator ("self"));
407 ccode.add_assignment (new CCodeIdentifier ("self"), cself);
410 // allow capturing generic type parameters
411 foreach (var type_param in m.get_type_parameters ()) {
412 string func_name;
414 func_name = "%s_type".printf (type_param.name.down ());
415 ccode.add_declaration ("GType", new CCodeVariableDeclarator (func_name));
416 ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name));
418 func_name = "%s_dup_func".printf (type_param.name.down ());
419 ccode.add_declaration ("GBoxedCopyFunc", new CCodeVariableDeclarator (func_name));
420 ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name));
422 func_name = "%s_destroy_func".printf (type_param.name.down ());
423 ccode.add_declaration ("GDestroyNotify", new CCodeVariableDeclarator (func_name));
424 ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name));
426 } else if (m.parent_symbol is Class && !m.coroutine) {
427 var cl = (Class) m.parent_symbol;
428 if (m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
429 Method base_method;
430 ReferenceType base_expression_type;
431 if (m.overrides) {
432 base_method = m.base_method;
433 base_expression_type = new ObjectType ((Class) base_method.parent_symbol);
434 } else {
435 base_method = m.base_interface_method;
436 base_expression_type = new ObjectType ((Interface) base_method.parent_symbol);
438 var self_target_type = new ObjectType (cl);
439 CCodeExpression cself = transform_expression (new CCodeIdentifier ("base"), base_expression_type, self_target_type);
441 ccode.add_declaration ("%s *".printf (cl.get_cname ()), new CCodeVariableDeclarator ("self"));
442 ccode.add_assignment (new CCodeIdentifier ("self"), cself);
443 } else if (m.binding == MemberBinding.INSTANCE
444 && !(m is CreationMethod)) {
445 create_method_type_check_statement (m, creturn_type, cl, true, "self");
449 foreach (Parameter param in m.get_parameters ()) {
450 if (param.ellipsis) {
451 break;
454 if (param.direction != ParameterDirection.OUT) {
455 var t = param.variable_type.data_type;
456 if (t != null && t.is_reference_type ()) {
457 create_method_type_check_statement (m, creturn_type, t, !param.variable_type.nullable, get_variable_cname (param.name));
459 } else if (!m.coroutine) {
460 // declare local variable for out parameter to allow assignment even when caller passes NULL
461 var vardecl = new CCodeVariableDeclarator.zero (get_variable_cname ("_" + param.name), default_value_for_type (param.variable_type, true));
462 ccode.add_declaration (param.variable_type.get_cname (), vardecl);
464 if (param.variable_type is ArrayType) {
465 // create variables to store array dimensions
466 var array_type = (ArrayType) param.variable_type;
468 if (!array_type.fixed_length) {
469 for (int dim = 1; dim <= array_type.rank; dim++) {
470 vardecl = new CCodeVariableDeclarator.zero (get_array_length_cname (get_variable_cname ("_" + param.name), dim), new CCodeConstant ("0"));
471 ccode.add_declaration ("int", vardecl);
474 } else if (param.variable_type is DelegateType) {
475 var deleg_type = (DelegateType) param.variable_type;
476 var d = deleg_type.delegate_symbol;
477 if (d.has_target) {
478 // create variable to store delegate target
479 vardecl = new CCodeVariableDeclarator.zero (get_delegate_target_cname (get_variable_cname ("_" + param.name)), new CCodeConstant ("NULL"));
480 ccode.add_declaration ("void *", vardecl);
482 if (deleg_type.value_owned) {
483 vardecl = new CCodeVariableDeclarator.zero (get_delegate_target_destroy_notify_cname (get_variable_cname ("_" + param.name)), new CCodeConstant ("NULL"));
484 ccode.add_declaration ("GDestroyNotify", vardecl);
491 if (!(m.return_type is VoidType) && !m.return_type.is_real_non_null_struct_type () && !m.coroutine) {
492 var vardecl = new CCodeVariableDeclarator ("result", default_value_for_type (m.return_type, true));
493 vardecl.init0 = true;
494 ccode.add_declaration (m.return_type.get_cname (), vardecl);
497 if (m is CreationMethod) {
498 if (in_gobject_creation_method) {
499 ccode.add_declaration ("%s *".printf (((Class) current_type_symbol).get_cname ()), new CCodeVariableDeclarator.zero ("self", new CCodeConstant ("NULL")));
500 } else if (is_gtypeinstance_creation_method (m)) {
501 var cl = (Class) m.parent_symbol;
502 ccode.add_declaration (cl.get_cname () + "*", new CCodeVariableDeclarator.zero ("self", new CCodeConstant ("NULL")));
504 if (cl.is_fundamental ()) {
505 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_create_instance"));
506 ccall.add_argument (new CCodeIdentifier ("object_type"));
507 ccode.add_assignment (new CCodeIdentifier ("self"), new CCodeCastExpression (ccall, cl.get_cname () + "*"));
509 /* type, dup func, and destroy func fields for generic types */
510 foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
511 CCodeIdentifier param_name;
512 CCodeAssignment assign;
514 var priv_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv");
516 param_name = new CCodeIdentifier ("%s_type".printf (type_param.name.down ()));
517 assign = new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name);
518 ccode.add_expression (assign);
520 param_name = new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ()));
521 assign = new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name);
522 ccode.add_expression (assign);
524 param_name = new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ()));
525 assign = new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name);
526 ccode.add_expression (assign);
529 } else if (current_type_symbol is Class) {
530 var cl = (Class) m.parent_symbol;
531 ccode.add_declaration (cl.get_cname () + "*", new CCodeVariableDeclarator ("self"));
533 if (!((CreationMethod) m).chain_up) {
534 // TODO implicitly chain up to base class as in add_object_creation
535 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
536 ccall.add_argument (new CCodeIdentifier (cl.get_cname ()));
537 ccode.add_assignment (new CCodeIdentifier ("self"), ccall);
540 if (cl.base_class == null) {
541 // derived compact classes do not have fields
542 var cinitcall = new CCodeFunctionCall (new CCodeIdentifier ("%s_instance_init".printf (cl.get_lower_case_cname (null))));
543 cinitcall.add_argument (new CCodeIdentifier ("self"));
544 ccode.add_expression (cinitcall);
546 } else {
547 var st = (Struct) m.parent_symbol;
549 // memset needs string.h
550 cfile.add_include ("string.h");
551 var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
552 czero.add_argument (new CCodeIdentifier ("self"));
553 czero.add_argument (new CCodeConstant ("0"));
554 czero.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (st.get_cname ())));
555 ccode.add_expression (czero);
559 if (context.module_init_method == m && in_plugin) {
560 // GTypeModule-based plug-in, register types
561 register_plugin_types (context.root, new HashSet<Symbol> ());
564 foreach (Expression precondition in m.get_preconditions ()) {
565 create_precondition_statement (m, creturn_type, precondition);
570 if (m.body != null) {
571 m.body.emit (this);
574 // generate *_real_* functions for virtual methods
575 // also generate them for abstract methods of classes to prevent faulty subclassing
576 if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
577 /* Methods imported from a plain C file don't
578 * have a body, e.g. Vala.Parser.parse_file () */
579 if (m.body != null) {
580 if (current_method_inner_error) {
581 /* always separate error parameter and inner_error local variable
582 * as error may be set to NULL but we're always interested in inner errors
584 if (m.coroutine) {
585 closure_struct.add_field ("GError *", "_inner_error_");
587 // no initialization necessary, closure struct is zeroed
588 } else {
589 ccode.add_declaration ("GError *", new CCodeVariableDeclarator.zero ("_inner_error_", new CCodeConstant ("NULL")));
593 if (m.coroutine) {
594 // epilogue
595 complete_async ();
598 if (!(m.return_type is VoidType) && !m.return_type.is_real_non_null_struct_type () && !m.coroutine) {
599 // add dummy return if exit block is known to be unreachable to silence C compiler
600 if (m.return_block != null && m.return_block.get_predecessors ().size == 0) {
601 ccode.add_return (new CCodeIdentifier ("result"));
605 if (m is CreationMethod) {
606 if (current_type_symbol is Class) {
607 creturn_type = new ObjectType (current_class);
608 } else {
609 creturn_type = new VoidType ();
613 if (current_type_symbol is Class && gobject_type != null && current_class.is_subtype_of (gobject_type)
614 && current_class.get_type_parameters ().size > 0
615 && !((CreationMethod) m).chain_up) {
616 var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, new CCodeIdentifier ("__params_it"), new CCodeIdentifier ("__params"));
617 var cdofreeparam = new CCodeBlock ();
618 cdofreeparam.add_statement (new CCodeExpressionStatement (new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, new CCodeIdentifier ("__params_it"))));
619 var cunsetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_unset"));
620 cunsetcall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("__params_it"), "value")));
621 cdofreeparam.add_statement (new CCodeExpressionStatement (cunsetcall));
622 ccode.add_statement (new CCodeWhileStatement (ccond, cdofreeparam));
624 var cfreeparams = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
625 cfreeparams.add_argument (new CCodeIdentifier ("__params"));
626 ccode.add_expression (cfreeparams);
629 if (current_type_symbol is Class) {
630 CCodeExpression cresult = new CCodeIdentifier ("self");
631 if (get_custom_creturn_type (m) != null) {
632 cresult = new CCodeCastExpression (cresult, get_custom_creturn_type (m));
635 ccode.add_return (cresult);
639 cfile.add_function (ccode);
643 if (m.is_abstract && current_type_symbol is Class) {
644 // generate helpful error message if a sublcass does not implement an abstract method.
645 // This is only meaningful for subclasses implemented in C since the vala compiler would
646 // complain during compile time of such en error.
648 // add a typecheck statement for "self"
649 create_method_type_check_statement (m, creturn_type, current_type_symbol, true, "self");
651 // add critical warning that this method should not have been called
652 var type_from_instance_call = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_FROM_INSTANCE"));
653 type_from_instance_call.add_argument (new CCodeIdentifier ("self"));
655 var type_name_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_name"));
656 type_name_call.add_argument (type_from_instance_call);
658 var error_string = "\"Type `%%s' does not implement abstract method `%s'\"".printf (m.get_cname ());
660 var cerrorcall = new CCodeFunctionCall (new CCodeIdentifier ("g_critical"));
661 cerrorcall.add_argument (new CCodeConstant (error_string));
662 cerrorcall.add_argument (type_name_call);
664 ccode.add_expression (cerrorcall);
666 // add return statement
667 return_default_value (creturn_type);
669 cfile.add_function (ccode);
673 in_static_or_class_context = false;
675 pop_context ();
677 if ((m.is_abstract || m.is_virtual) && !m.coroutine &&
678 /* If the method is a signal handler, the declaration
679 * is not needed. -- the name should be reserved for the
680 * emitter! */
681 m.signal_reference == null) {
683 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
684 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
686 generate_vfunc (m, creturn_type, cparam_map, carg_map);
689 if (m.entry_point) {
690 // m is possible entry point, add appropriate startup code
691 var cmain = new CCodeFunction ("main", "int");
692 cmain.line = function.line;
693 cmain.add_parameter (new CCodeParameter ("argc", "int"));
694 cmain.add_parameter (new CCodeParameter ("argv", "char **"));
695 var main_block = new CCodeBlock ();
697 if (context.profile == Profile.GOBJECT) {
698 if (context.mem_profiler) {
699 var mem_profiler_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_mem_set_vtable"));
700 mem_profiler_init_call.line = cmain.line;
701 mem_profiler_init_call.add_argument (new CCodeConstant ("glib_mem_profiler_table"));
702 main_block.add_statement (new CCodeExpressionStatement (mem_profiler_init_call));
705 if (context.thread) {
706 var thread_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_thread_init"));
707 thread_init_call.line = cmain.line;
708 thread_init_call.add_argument (new CCodeConstant ("NULL"));
709 main_block.add_statement (new CCodeExpressionStatement (thread_init_call));
712 var type_init_call = new CCodeExpressionStatement (new CCodeFunctionCall (new CCodeIdentifier ("g_type_init")));
713 type_init_call.line = cmain.line;
714 main_block.add_statement (type_init_call);
717 var main_call = new CCodeFunctionCall (new CCodeIdentifier (function.name));
718 if (m.get_parameters ().size == 1) {
719 main_call.add_argument (new CCodeIdentifier ("argv"));
720 main_call.add_argument (new CCodeIdentifier ("argc"));
722 if (m.return_type is VoidType) {
723 // method returns void, always use 0 as exit code
724 var main_stmt = new CCodeExpressionStatement (main_call);
725 main_stmt.line = cmain.line;
726 main_block.add_statement (main_stmt);
727 var ret_stmt = new CCodeReturnStatement (new CCodeConstant ("0"));
728 ret_stmt.line = cmain.line;
729 main_block.add_statement (ret_stmt);
730 } else {
731 var main_stmt = new CCodeReturnStatement (main_call);
732 main_stmt.line = cmain.line;
733 main_block.add_statement (main_stmt);
735 cmain.block = main_block;
736 cfile.add_function (cmain);
740 public virtual CCodeParameter generate_parameter (Parameter param, CCodeFile decl_space, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
741 CCodeParameter cparam;
742 if (!param.ellipsis) {
743 string ctypename = param.variable_type.get_cname ();
745 generate_type_declaration (param.variable_type, decl_space);
747 // pass non-simple structs always by reference
748 if (param.variable_type.data_type is Struct) {
749 var st = (Struct) param.variable_type.data_type;
750 if (!st.is_simple_type () && param.direction == ParameterDirection.IN) {
751 if (st.is_immutable && !param.variable_type.value_owned) {
752 ctypename = "const " + ctypename;
755 if (!param.variable_type.nullable) {
756 ctypename += "*";
761 if (param.direction != ParameterDirection.IN) {
762 ctypename += "*";
765 cparam = new CCodeParameter (get_variable_cname (param.name), ctypename);
766 } else {
767 cparam = new CCodeParameter.with_ellipsis ();
770 cparam_map.set (get_param_pos (param.cparameter_position, param.ellipsis), cparam);
771 if (carg_map != null && !param.ellipsis) {
772 carg_map.set (get_param_pos (param.cparameter_position, param.ellipsis), get_variable_cexpression (param.name));
775 return cparam;
778 public override void generate_cparameters (Method m, CCodeFile decl_space, Map<int,CCodeParameter> cparam_map, CCodeFunction func, CCodeFunctionDeclarator? vdeclarator = null, Map<int,CCodeExpression>? carg_map = null, CCodeFunctionCall? vcall = null, int direction = 3) {
779 if (m.closure) {
780 var closure_block = current_closure_block;
781 int block_id = get_block_id (closure_block);
782 var instance_param = new CCodeParameter ("_data%d_".printf (block_id), "Block%dData*".printf (block_id));
783 cparam_map.set (get_param_pos (m.cinstance_parameter_position), instance_param);
784 } else if (m.parent_symbol is Class && m is CreationMethod) {
785 var cl = (Class) m.parent_symbol;
786 if (!cl.is_compact && vcall == null) {
787 cparam_map.set (get_param_pos (m.cinstance_parameter_position), new CCodeParameter ("object_type", "GType"));
789 } else if (m.binding == MemberBinding.INSTANCE || (m.parent_symbol is Struct && m is CreationMethod)) {
790 TypeSymbol parent_type = find_parent_type (m);
791 DataType this_type;
792 if (parent_type is Class) {
793 this_type = new ObjectType ((Class) parent_type);
794 } else if (parent_type is Interface) {
795 this_type = new ObjectType ((Interface) parent_type);
796 } else if (parent_type is Struct) {
797 this_type = new StructValueType ((Struct) parent_type);
798 } else if (parent_type is Enum) {
799 this_type = new EnumValueType ((Enum) parent_type);
800 } else {
801 assert_not_reached ();
804 generate_type_declaration (this_type, decl_space);
806 CCodeParameter instance_param = null;
807 if (m.base_interface_method != null && !m.is_abstract && !m.is_virtual) {
808 var base_type = new ObjectType ((Interface) m.base_interface_method.parent_symbol);
809 instance_param = new CCodeParameter ("base", base_type.get_cname ());
810 } else if (m.overrides) {
811 var base_type = new ObjectType ((Class) m.base_method.parent_symbol);
812 instance_param = new CCodeParameter ("base", base_type.get_cname ());
813 } else {
814 if (m.parent_symbol is Struct && !((Struct) m.parent_symbol).is_simple_type ()) {
815 instance_param = new CCodeParameter ("*self", this_type.get_cname ());
816 } else {
817 instance_param = new CCodeParameter ("self", this_type.get_cname ());
820 cparam_map.set (get_param_pos (m.cinstance_parameter_position), instance_param);
821 } else if (m.binding == MemberBinding.CLASS) {
822 TypeSymbol parent_type = find_parent_type (m);
823 DataType this_type;
824 this_type = new ClassType ((Class) parent_type);
825 var class_param = new CCodeParameter ("klass", this_type.get_cname ());
826 cparam_map.set (get_param_pos (m.cinstance_parameter_position), class_param);
829 if (is_gtypeinstance_creation_method (m)) {
830 // memory management for generic types
831 int type_param_index = 0;
832 var cl = (Class) m.parent_symbol;
833 foreach (TypeParameter type_param in cl.get_type_parameters ()) {
834 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeParameter ("%s_type".printf (type_param.name.down ()), "GType"));
835 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeParameter ("%s_dup_func".printf (type_param.name.down ()), "GBoxedCopyFunc"));
836 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeParameter ("%s_destroy_func".printf (type_param.name.down ()), "GDestroyNotify"));
837 if (carg_map != null) {
838 carg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier ("%s_type".printf (type_param.name.down ())));
839 carg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ())));
840 carg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ())));
842 type_param_index++;
844 } else if (!m.closure) {
845 int type_param_index = 0;
846 foreach (var type_param in m.get_type_parameters ()) {
847 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeParameter ("%s_type".printf (type_param.name.down ()), "GType"));
848 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeParameter ("%s_dup_func".printf (type_param.name.down ()), "GBoxedCopyFunc"));
849 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeParameter ("%s_destroy_func".printf (type_param.name.down ()), "GDestroyNotify"));
850 if (carg_map != null) {
851 carg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier ("%s_type".printf (type_param.name.down ())));
852 carg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ())));
853 carg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ())));
855 type_param_index++;
859 foreach (Parameter param in m.get_parameters ()) {
860 if (param.direction != ParameterDirection.OUT) {
861 if ((direction & 1) == 0) {
862 // no in paramters
863 continue;
865 } else {
866 if ((direction & 2) == 0) {
867 // no out paramters
868 continue;
872 generate_parameter (param, decl_space, cparam_map, carg_map);
875 if ((direction & 2) != 0) {
876 generate_method_result_declaration (m, decl_space, func, cparam_map, carg_map);
879 // append C parameters in the right order
880 int last_pos = -1;
881 int min_pos;
882 while (true) {
883 min_pos = -1;
884 foreach (int pos in cparam_map.get_keys ()) {
885 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
886 min_pos = pos;
889 if (min_pos == -1) {
890 break;
892 func.add_parameter (cparam_map.get (min_pos));
893 if (vdeclarator != null) {
894 vdeclarator.add_parameter (cparam_map.get (min_pos));
896 if (vcall != null) {
897 var arg = carg_map.get (min_pos);
898 if (arg != null) {
899 vcall.add_argument (arg);
902 last_pos = min_pos;
906 public void generate_vfunc (Method m, DataType return_type, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression> carg_map, string suffix = "", int direction = 3) {
907 push_context (new EmitContext ());
909 string cname = m.get_cname ();
910 if (suffix == "_finish" && cname.has_suffix ("_async")) {
911 cname = cname.substring (0, cname.length - "_async".length);
913 var vfunc = new CCodeFunction (cname + suffix);
915 CCodeFunctionCall vcast = null;
916 if (m.parent_symbol is Interface) {
917 var iface = (Interface) m.parent_symbol;
919 vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (iface.get_upper_case_cname (null))));
920 } else {
921 var cl = (Class) m.parent_symbol;
923 vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (cl.get_upper_case_cname (null))));
925 vcast.add_argument (new CCodeIdentifier ("self"));
927 cname = m.vfunc_name;
928 if (suffix == "_finish" && cname.has_suffix ("_async")) {
929 cname = cname.substring (0, cname.length - "_async".length);
931 var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, cname + suffix));
932 carg_map.set (get_param_pos (m.cinstance_parameter_position), new CCodeIdentifier ("self"));
934 generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall, direction);
936 push_function (vfunc);
938 foreach (Expression precondition in m.get_preconditions ()) {
939 create_precondition_statement (m, return_type, precondition);
942 if (return_type is VoidType || return_type.is_real_non_null_struct_type ()) {
943 ccode.add_expression (vcall);
944 } else if (m.get_postconditions ().size == 0) {
945 /* pass method return value */
946 ccode.add_return (vcall);
947 } else {
948 /* store method return value for postconditions */
949 ccode.add_declaration (get_creturn_type (m, return_type.get_cname ()), new CCodeVariableDeclarator ("result"));
950 ccode.add_assignment (new CCodeIdentifier ("result"), vcall);
953 if (m.get_postconditions ().size > 0) {
954 foreach (Expression postcondition in m.get_postconditions ()) {
955 create_postcondition_statement (postcondition);
958 if (!(return_type is VoidType)) {
959 ccode.add_return (new CCodeIdentifier ("result"));
963 cfile.add_function (vfunc);
965 pop_context ();
968 private void create_method_type_check_statement (Method m, DataType return_type, TypeSymbol t, bool non_null, string var_name) {
969 if (!m.coroutine) {
970 create_type_check_statement (m, return_type, t, non_null, var_name);
974 private void create_precondition_statement (CodeNode method_node, DataType ret_type, Expression precondition) {
975 var ccheck = new CCodeFunctionCall ();
977 precondition.emit (this);
979 ccheck.add_argument (get_cvalue (precondition));
981 if (method_node is CreationMethod) {
982 ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
983 ccheck.add_argument (new CCodeConstant ("NULL"));
984 } else if (method_node is Method && ((Method) method_node).coroutine) {
985 // _co function
986 ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
987 ccheck.add_argument (new CCodeConstant ("FALSE"));
988 } else if (ret_type is VoidType) {
989 /* void function */
990 ccheck.call = new CCodeIdentifier ("g_return_if_fail");
991 } else {
992 ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
994 var cdefault = default_value_for_type (ret_type, false);
995 if (cdefault != null) {
996 ccheck.add_argument (cdefault);
997 } else {
998 return;
1002 ccode.add_expression (ccheck);
1005 private TypeSymbol? find_parent_type (Symbol sym) {
1006 while (sym != null) {
1007 if (sym is TypeSymbol) {
1008 return (TypeSymbol) sym;
1010 sym = sym.parent_symbol;
1012 return null;
1015 public override void visit_creation_method (CreationMethod m) {
1016 bool visible = !m.is_private_symbol ();
1018 visit_method (m);
1020 if (m.source_type == SourceFileType.FAST) {
1021 return;
1024 // do not generate _new functions for creation methods of abstract classes
1025 if (current_type_symbol is Class && !current_class.is_compact && !current_class.is_abstract) {
1026 var vfunc = new CCodeFunction (m.get_cname ());
1028 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
1029 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
1031 var vblock = new CCodeBlock ();
1033 var vcall = new CCodeFunctionCall (new CCodeIdentifier (m.get_real_cname ()));
1034 vcall.add_argument (new CCodeIdentifier (current_class.get_type_id ()));
1036 generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall);
1037 CCodeStatement cstmt = new CCodeReturnStatement (vcall);
1038 cstmt.line = vfunc.line;
1039 vblock.add_statement (cstmt);
1041 if (!visible) {
1042 vfunc.modifiers |= CCodeModifiers.STATIC;
1045 vfunc.block = vblock;
1047 cfile.add_function (vfunc);
1052 // vim:sw=8 noet