girparser: Add missing source references to classes and structs
[vala-lang.git] / codegen / valaccodemethodmodule.vala
blobc2d4b880ff4cb5349d16daedd28018c3c65249b2
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;
92 for (int dim = 1; dim <= array_type.rank; dim++) {
93 var cparam = new CCodeParameter (get_array_length_cname ("result", dim), "int*");
94 cparam_map.set (get_param_pos (m.carray_length_parameter_position + 0.01 * dim), cparam);
95 if (carg_map != null) {
96 carg_map.set (get_param_pos (m.carray_length_parameter_position + 0.01 * dim), get_variable_cexpression (cparam.name));
99 } else if (m.return_type is DelegateType) {
100 // return delegate target if appropriate
101 var deleg_type = (DelegateType) m.return_type;
102 var d = deleg_type.delegate_symbol;
103 if (d.has_target) {
104 var cparam = new CCodeParameter (get_delegate_target_cname ("result"), "void**");
105 cparam_map.set (get_param_pos (m.cdelegate_target_parameter_position), cparam);
106 if (carg_map != null) {
107 carg_map.set (get_param_pos (m.cdelegate_target_parameter_position), get_variable_cexpression (cparam.name));
109 if (deleg_type.value_owned) {
110 cparam = new CCodeParameter (get_delegate_target_destroy_notify_cname ("result"), "GDestroyNotify*");
111 cparam_map.set (get_param_pos (m.cdelegate_target_parameter_position + 0.01), cparam);
112 if (carg_map != null) {
113 carg_map.set (get_param_pos (m.cdelegate_target_parameter_position + 0.01), get_variable_cexpression (cparam.name));
119 if (m.get_error_types ().size > 0 || (m.base_method != null && m.base_method.get_error_types ().size > 0) || (m.base_interface_method != null && m.base_interface_method.get_error_types ().size > 0)) {
120 foreach (DataType error_type in m.get_error_types ()) {
121 generate_type_declaration (error_type, decl_space);
124 var cparam = new CCodeParameter ("error", "GError**");
125 cparam_map.set (get_param_pos (-1), cparam);
126 if (carg_map != null) {
127 carg_map.set (get_param_pos (-1), new CCodeIdentifier (cparam.name));
132 public void complete_async () {
133 var state = new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "_state_");
134 var zero = new CCodeConstant ("0");
135 var state_is_zero = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, state, zero);
136 ccode.open_if (state_is_zero);
138 var async_result_expr = new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "_async_result");
140 var idle_call = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_complete_in_idle"));
141 idle_call.add_argument (async_result_expr);
142 ccode.add_expression (idle_call);
144 ccode.add_else ();
146 var direct_call = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_complete"));
147 direct_call.add_argument (async_result_expr);
148 ccode.add_expression (direct_call);
150 ccode.close ();
152 var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
153 unref.add_argument (async_result_expr);
154 ccode.add_expression (unref);
156 ccode.add_return (new CCodeConstant ("FALSE"));
159 public override void generate_method_declaration (Method m, CCodeFile decl_space) {
160 if (m.is_async_callback) {
161 return;
163 if (add_symbol_declaration (decl_space, m, m.get_cname ())) {
164 return;
167 var function = new CCodeFunction (m.get_cname ());
169 if (m.is_private_symbol () && !m.external) {
170 function.modifiers |= CCodeModifiers.STATIC;
171 if (m.is_inline) {
172 function.modifiers |= CCodeModifiers.INLINE;
176 if (m.deprecated) {
177 function.modifiers |= CCodeModifiers.DEPRECATED;
180 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
181 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
183 var cl = m.parent_symbol as Class;
185 // do not generate _new functions for creation methods of abstract classes
186 if (!(m is CreationMethod && cl != null && cl.is_abstract)) {
187 generate_cparameters (m, decl_space, cparam_map, function, null, carg_map, new CCodeFunctionCall (new CCodeIdentifier ("fake")));
189 decl_space.add_function_declaration (function);
192 if (m is CreationMethod && cl != null) {
193 // _construct function
194 function = new CCodeFunction (m.get_real_cname ());
196 if (m.is_private_symbol ()) {
197 function.modifiers |= CCodeModifiers.STATIC;
200 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
201 generate_cparameters (m, decl_space, cparam_map, function);
203 decl_space.add_function_declaration (function);
207 void register_plugin_types (Symbol sym, Set<Symbol> registered_types) {
208 var ns = sym as Namespace;
209 var cl = sym as Class;
210 var iface = sym as Interface;
211 if (ns != null) {
212 foreach (var ns_ns in ns.get_namespaces ()) {
213 register_plugin_types (ns_ns, registered_types);
215 foreach (var ns_cl in ns.get_classes ()) {
216 register_plugin_types (ns_cl, registered_types);
218 foreach (var ns_iface in ns.get_interfaces ()) {
219 register_plugin_types (ns_iface, registered_types);
221 } else if (cl != null) {
222 register_plugin_type (cl, registered_types);
223 foreach (var cl_cl in cl.get_classes ()) {
224 register_plugin_types (cl_cl, registered_types);
226 } else if (iface != null) {
227 register_plugin_type (iface, registered_types);
228 foreach (var iface_cl in iface.get_classes ()) {
229 register_plugin_types (iface_cl, registered_types);
234 void register_plugin_type (ObjectTypeSymbol type_symbol, Set<Symbol> registered_types) {
235 if (type_symbol.external_package) {
236 return;
239 if (!registered_types.add (type_symbol)) {
240 // already registered
241 return;
244 var cl = type_symbol as Class;
245 if (cl != null) {
246 if (cl.is_compact) {
247 return;
250 // register base types first
251 foreach (var base_type in cl.get_base_types ()) {
252 register_plugin_type ((ObjectTypeSymbol) base_type.data_type, registered_types);
256 var register_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_register_type".printf (type_symbol.get_lower_case_cname (null))));
257 register_call.add_argument (new CCodeIdentifier (module_init_param_name));
258 ccode.add_expression (register_call);
261 public override void visit_method (Method m) {
262 push_context (new EmitContext (m));
264 bool in_gobject_creation_method = false;
265 bool in_fundamental_creation_method = false;
267 check_type (m.return_type);
269 if (m is CreationMethod) {
270 var cl = current_type_symbol as Class;
271 if (cl != null && !cl.is_compact) {
272 if (cl.base_class == null) {
273 in_fundamental_creation_method = true;
274 } else if (gobject_type != null && cl.is_subtype_of (gobject_type)) {
275 in_gobject_creation_method = true;
280 if (m.coroutine) {
281 next_coroutine_state = 1;
284 var creturn_type = m.return_type;
285 if (m.return_type.is_real_non_null_struct_type ()) {
286 // structs are returned via out parameter
287 creturn_type = new VoidType ();
290 if (m.binding == MemberBinding.CLASS || m.binding == MemberBinding.STATIC) {
291 in_static_or_class_context = true;
295 foreach (Parameter param in m.get_parameters ()) {
296 param.accept (this);
299 // do not declare overriding methods and interface implementations
300 if (m.is_abstract || m.is_virtual
301 || (m.base_method == null && m.base_interface_method == null)) {
302 generate_method_declaration (m, cfile);
304 if (!m.is_internal_symbol ()) {
305 generate_method_declaration (m, header_file);
307 if (!m.is_private_symbol ()) {
308 generate_method_declaration (m, internal_header_file);
312 CCodeFunction function;
313 function = new CCodeFunction (m.get_real_cname ());
315 if (m.is_inline) {
316 function.modifiers |= CCodeModifiers.INLINE;
319 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
321 generate_cparameters (m, cfile, cparam_map, function);
323 // generate *_real_* functions for virtual methods
324 // also generate them for abstract methods of classes to prevent faulty subclassing
325 if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
326 if (!m.coroutine) {
327 if (m.base_method != null || m.base_interface_method != null) {
328 // declare *_real_* function
329 function.modifiers |= CCodeModifiers.STATIC;
330 cfile.add_function_declaration (function);
331 } else if (m.is_private_symbol ()) {
332 function.modifiers |= CCodeModifiers.STATIC;
337 // generate *_real_* functions for virtual methods
338 // also generate them for abstract methods of classes to prevent faulty subclassing
339 if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
340 if (m.body != null) {
341 if (m.coroutine) {
342 function = new CCodeFunction (m.get_real_cname () + "_co", "gboolean");
344 // data struct to hold parameters, local variables, and the return value
345 function.add_parameter (new CCodeParameter ("data", Symbol.lower_case_to_camel_case (m.get_cname ()) + "Data*"));
347 function.modifiers |= CCodeModifiers.STATIC;
348 cfile.add_function_declaration (function);
353 if (m.comment != null) {
354 cfile.add_type_member_definition (new CCodeComment (m.comment.content));
357 push_function (function);
359 // generate *_real_* functions for virtual methods
360 // also generate them for abstract methods of classes to prevent faulty subclassing
361 if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
362 if (m.body != null) {
363 if (m.coroutine) {
364 ccode.open_switch (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "_state_"));
366 // initial coroutine state
367 ccode.add_case (new CCodeConstant ("0"));
368 ccode.add_goto ("_state_0");
370 for (int state = 1; state <= m.yield_count; state++) {
371 ccode.add_case (new CCodeConstant (state.to_string ()));
372 ccode.add_goto ("_state_%d".printf (state));
376 // let gcc know that this can't happen
377 ccode.add_default ();
378 ccode.add_expression (new CCodeFunctionCall (new CCodeIdentifier ("g_assert_not_reached")));
380 ccode.close ();
382 // coroutine body
383 ccode.add_label ("_state_0");
386 if (m.closure) {
387 // add variables for parent closure blocks
388 // as closures only have one parameter for the innermost closure block
389 var closure_block = current_closure_block;
390 int block_id = get_block_id (closure_block);
391 while (true) {
392 var parent_closure_block = next_closure_block (closure_block.parent_symbol);
393 if (parent_closure_block == null) {
394 break;
396 int parent_block_id = get_block_id (parent_closure_block);
398 var parent_data = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id));
399 ccode.add_declaration ("Block%dData*".printf (parent_block_id), new CCodeVariableDeclarator ("_data%d_".printf (parent_block_id)));
400 ccode.add_expression (new CCodeAssignment (new CCodeIdentifier ("_data%d_".printf (parent_block_id)), parent_data));
402 closure_block = parent_closure_block;
403 block_id = parent_block_id;
406 // add self variable for closures
407 // as closures have block data parameter
408 if (m.binding == MemberBinding.INSTANCE) {
409 var cself = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "self");
410 ccode.add_declaration ("%s *".printf (current_class.get_cname ()), new CCodeVariableDeclarator ("self"));
411 ccode.add_expression (new CCodeAssignment (new CCodeIdentifier ("self"), cself));
414 // allow capturing generic type parameters
415 foreach (var type_param in m.get_type_parameters ()) {
416 string func_name;
418 func_name = "%s_type".printf (type_param.name.down ());
419 ccode.add_declaration ("GType", new CCodeVariableDeclarator (func_name));
420 ccode.add_expression (new CCodeAssignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name)));
422 func_name = "%s_dup_func".printf (type_param.name.down ());
423 ccode.add_declaration ("GBoxedCopyFunc", new CCodeVariableDeclarator (func_name));
424 ccode.add_expression (new CCodeAssignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name)));
426 func_name = "%s_destroy_func".printf (type_param.name.down ());
427 ccode.add_declaration ("GDestroyNotify", new CCodeVariableDeclarator (func_name));
428 ccode.add_expression (new CCodeAssignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name)));
430 } else if (m.parent_symbol is Class && !m.coroutine) {
431 var cl = (Class) m.parent_symbol;
432 if (m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
433 Method base_method;
434 ReferenceType base_expression_type;
435 if (m.overrides) {
436 base_method = m.base_method;
437 base_expression_type = new ObjectType ((Class) base_method.parent_symbol);
438 } else {
439 base_method = m.base_interface_method;
440 base_expression_type = new ObjectType ((Interface) base_method.parent_symbol);
442 var self_target_type = new ObjectType (cl);
443 CCodeExpression cself = transform_expression (new CCodeIdentifier ("base"), base_expression_type, self_target_type);
445 ccode.add_declaration ("%s *".printf (cl.get_cname ()), new CCodeVariableDeclarator ("self"));
446 ccode.add_expression (new CCodeAssignment (new CCodeIdentifier ("self"), cself));
447 } else if (m.binding == MemberBinding.INSTANCE
448 && !(m is CreationMethod)) {
449 create_method_type_check_statement (m, creturn_type, cl, true, "self");
453 foreach (Parameter param in m.get_parameters ()) {
454 if (param.ellipsis) {
455 break;
458 if (param.direction != ParameterDirection.OUT) {
459 var t = param.variable_type.data_type;
460 if (t != null && t.is_reference_type ()) {
461 create_method_type_check_statement (m, creturn_type, t, !param.variable_type.nullable, get_variable_cname (param.name));
463 } else if (!m.coroutine) {
464 // declare local variable for out parameter to allow assignment even when caller passes NULL
465 var vardecl = new CCodeVariableDeclarator.zero (get_variable_cname ("_" + param.name), default_value_for_type (param.variable_type, true));
466 ccode.add_declaration (param.variable_type.get_cname (), vardecl);
468 if (param.variable_type is ArrayType) {
469 // create variables to store array dimensions
470 var array_type = (ArrayType) param.variable_type;
472 if (!array_type.fixed_length) {
473 for (int dim = 1; dim <= array_type.rank; dim++) {
474 vardecl = new CCodeVariableDeclarator.zero (get_array_length_cname (get_variable_cname ("_" + param.name), dim), new CCodeConstant ("0"));
475 ccode.add_declaration ("int", vardecl);
478 } else if (param.variable_type is DelegateType) {
479 var deleg_type = (DelegateType) param.variable_type;
480 var d = deleg_type.delegate_symbol;
481 if (d.has_target) {
482 // create variable to store delegate target
483 vardecl = new CCodeVariableDeclarator.zero (get_delegate_target_cname (get_variable_cname ("_" + param.name)), new CCodeConstant ("NULL"));
484 ccode.add_declaration ("void *", vardecl);
486 if (deleg_type.value_owned) {
487 vardecl = new CCodeVariableDeclarator.zero (get_delegate_target_destroy_notify_cname (get_variable_cname ("_" + param.name)), new CCodeConstant ("NULL"));
488 ccode.add_declaration ("GDestroyNotify", vardecl);
495 if (!(m.return_type is VoidType) && !m.return_type.is_real_non_null_struct_type () && !m.coroutine) {
496 var vardecl = new CCodeVariableDeclarator ("result", default_value_for_type (m.return_type, true));
497 vardecl.init0 = true;
498 ccode.add_declaration (m.return_type.get_cname (), vardecl);
501 if (m is CreationMethod) {
502 if (in_gobject_creation_method) {
503 ccode.add_declaration ("%s *".printf (((Class) current_type_symbol).get_cname ()), new CCodeVariableDeclarator.zero ("self", new CCodeConstant ("NULL")));
504 } else if (is_gtypeinstance_creation_method (m)) {
505 var cl = (Class) m.parent_symbol;
506 ccode.add_declaration (cl.get_cname () + "*", new CCodeVariableDeclarator.zero ("self", new CCodeConstant ("NULL")));
508 if (cl.is_fundamental ()) {
509 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_create_instance"));
510 ccall.add_argument (new CCodeIdentifier ("object_type"));
511 ccode.add_expression (new CCodeAssignment (new CCodeIdentifier ("self"), new CCodeCastExpression (ccall, cl.get_cname () + "*")));
513 /* type, dup func, and destroy func fields for generic types */
514 foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
515 CCodeIdentifier param_name;
516 CCodeAssignment assign;
518 var priv_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv");
520 param_name = new CCodeIdentifier ("%s_type".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_dup_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);
528 param_name = new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ()));
529 assign = new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name);
530 ccode.add_expression (assign);
533 } else if (current_type_symbol is Class) {
534 var cl = (Class) m.parent_symbol;
535 ccode.add_declaration (cl.get_cname () + "*", new CCodeVariableDeclarator ("self"));
537 if (!((CreationMethod) m).chain_up) {
538 // TODO implicitly chain up to base class as in add_object_creation
539 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
540 ccall.add_argument (new CCodeIdentifier (cl.get_cname ()));
541 ccode.add_expression (new CCodeAssignment (new CCodeIdentifier ("self"), ccall));
544 if (cl.base_class == null) {
545 // derived compact classes do not have fields
546 var cinitcall = new CCodeFunctionCall (new CCodeIdentifier ("%s_instance_init".printf (cl.get_lower_case_cname (null))));
547 cinitcall.add_argument (new CCodeIdentifier ("self"));
548 ccode.add_expression (cinitcall);
550 } else {
551 var st = (Struct) m.parent_symbol;
553 // memset needs string.h
554 cfile.add_include ("string.h");
555 var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
556 czero.add_argument (new CCodeIdentifier ("self"));
557 czero.add_argument (new CCodeConstant ("0"));
558 czero.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (st.get_cname ())));
559 ccode.add_expression (czero);
563 if (context.module_init_method == m && in_plugin) {
564 // GTypeModule-based plug-in, register types
565 register_plugin_types (context.root, new HashSet<Symbol> ());
568 foreach (Expression precondition in m.get_preconditions ()) {
569 create_precondition_statement (m, creturn_type, precondition);
574 if (m.body != null) {
575 m.body.emit (this);
578 // generate *_real_* functions for virtual methods
579 // also generate them for abstract methods of classes to prevent faulty subclassing
580 if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
581 /* Methods imported from a plain C file don't
582 * have a body, e.g. Vala.Parser.parse_file () */
583 if (m.body != null) {
584 if (current_method_inner_error) {
585 /* always separate error parameter and inner_error local variable
586 * as error may be set to NULL but we're always interested in inner errors
588 if (m.coroutine) {
589 closure_struct.add_field ("GError *", "_inner_error_");
591 // no initialization necessary, closure struct is zeroed
592 } else {
593 ccode.add_declaration ("GError *", new CCodeVariableDeclarator.zero ("_inner_error_", new CCodeConstant ("NULL")));
597 if (m.coroutine) {
598 // epilogue
599 complete_async ();
602 if (!(m.return_type is VoidType) && !m.return_type.is_real_non_null_struct_type () && !m.coroutine) {
603 // add dummy return if exit block is known to be unreachable to silence C compiler
604 if (m.return_block != null && m.return_block.get_predecessors ().size == 0) {
605 ccode.add_return (new CCodeIdentifier ("result"));
609 if (m is CreationMethod) {
610 if (current_type_symbol is Class) {
611 creturn_type = new ObjectType (current_class);
612 } else {
613 creturn_type = new VoidType ();
617 if (current_type_symbol is Class && gobject_type != null && current_class.is_subtype_of (gobject_type)
618 && current_class.get_type_parameters ().size > 0
619 && !((CreationMethod) m).chain_up) {
620 var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, new CCodeIdentifier ("__params_it"), new CCodeIdentifier ("__params"));
621 var cdofreeparam = new CCodeBlock ();
622 cdofreeparam.add_statement (new CCodeExpressionStatement (new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, new CCodeIdentifier ("__params_it"))));
623 var cunsetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_unset"));
624 cunsetcall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("__params_it"), "value")));
625 cdofreeparam.add_statement (new CCodeExpressionStatement (cunsetcall));
626 ccode.add_statement (new CCodeWhileStatement (ccond, cdofreeparam));
628 var cfreeparams = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
629 cfreeparams.add_argument (new CCodeIdentifier ("__params"));
630 ccode.add_expression (cfreeparams);
633 if (current_type_symbol is Class) {
634 CCodeExpression cresult = new CCodeIdentifier ("self");
635 if (get_custom_creturn_type (m) != null) {
636 cresult = new CCodeCastExpression (cresult, get_custom_creturn_type (m));
639 ccode.add_return (cresult);
643 cfile.add_function (ccode);
647 if (m.is_abstract) {
648 // generate helpful error message if a sublcass does not implement an abstract method.
649 // This is only meaningful for subclasses implemented in C since the vala compiler would
650 // complain during compile time of such en error.
652 // add a typecheck statement for "self"
653 create_method_type_check_statement (m, creturn_type, current_type_symbol, true, "self");
655 // add critical warning that this method should not have been called
656 var type_from_instance_call = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_FROM_INSTANCE"));
657 type_from_instance_call.add_argument (new CCodeIdentifier ("self"));
659 var type_name_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_name"));
660 type_name_call.add_argument (type_from_instance_call);
662 var error_string = "\"Type `%%s' does not implement abstract method `%s'\"".printf (m.get_cname ());
664 var cerrorcall = new CCodeFunctionCall (new CCodeIdentifier ("g_critical"));
665 cerrorcall.add_argument (new CCodeConstant (error_string));
666 cerrorcall.add_argument (type_name_call);
668 ccode.add_expression (cerrorcall);
670 // add return statement
671 return_default_value (creturn_type);
673 cfile.add_function (ccode);
677 in_static_or_class_context = false;
679 pop_context ();
681 if ((m.is_abstract || m.is_virtual) && !m.coroutine &&
682 /* If the method is a signal handler, the declaration
683 * is not needed. -- the name should be reserved for the
684 * emitter! */
685 m.signal_reference == null) {
687 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
688 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
690 generate_vfunc (m, creturn_type, cparam_map, carg_map);
693 if (m.entry_point) {
694 // m is possible entry point, add appropriate startup code
695 var cmain = new CCodeFunction ("main", "int");
696 cmain.line = function.line;
697 cmain.add_parameter (new CCodeParameter ("argc", "int"));
698 cmain.add_parameter (new CCodeParameter ("argv", "char **"));
699 var main_block = new CCodeBlock ();
701 if (context.profile == Profile.GOBJECT) {
702 if (context.mem_profiler) {
703 var mem_profiler_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_mem_set_vtable"));
704 mem_profiler_init_call.line = cmain.line;
705 mem_profiler_init_call.add_argument (new CCodeConstant ("glib_mem_profiler_table"));
706 main_block.add_statement (new CCodeExpressionStatement (mem_profiler_init_call));
709 if (context.thread) {
710 var thread_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_thread_init"));
711 thread_init_call.line = cmain.line;
712 thread_init_call.add_argument (new CCodeConstant ("NULL"));
713 main_block.add_statement (new CCodeExpressionStatement (thread_init_call));
716 var type_init_call = new CCodeExpressionStatement (new CCodeFunctionCall (new CCodeIdentifier ("g_type_init")));
717 type_init_call.line = cmain.line;
718 main_block.add_statement (type_init_call);
721 var main_call = new CCodeFunctionCall (new CCodeIdentifier (function.name));
722 if (m.get_parameters ().size == 1) {
723 main_call.add_argument (new CCodeIdentifier ("argv"));
724 main_call.add_argument (new CCodeIdentifier ("argc"));
726 if (m.return_type is VoidType) {
727 // method returns void, always use 0 as exit code
728 var main_stmt = new CCodeExpressionStatement (main_call);
729 main_stmt.line = cmain.line;
730 main_block.add_statement (main_stmt);
731 var ret_stmt = new CCodeReturnStatement (new CCodeConstant ("0"));
732 ret_stmt.line = cmain.line;
733 main_block.add_statement (ret_stmt);
734 } else {
735 var main_stmt = new CCodeReturnStatement (main_call);
736 main_stmt.line = cmain.line;
737 main_block.add_statement (main_stmt);
739 cmain.block = main_block;
740 cfile.add_function (cmain);
744 public virtual CCodeParameter generate_parameter (Parameter param, CCodeFile decl_space, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
745 CCodeParameter cparam;
746 if (!param.ellipsis) {
747 string ctypename = param.variable_type.get_cname ();
749 generate_type_declaration (param.variable_type, decl_space);
751 // pass non-simple structs always by reference
752 if (param.variable_type.data_type is Struct) {
753 var st = (Struct) param.variable_type.data_type;
754 if (!st.is_simple_type () && param.direction == ParameterDirection.IN) {
755 if (st.is_immutable && !param.variable_type.value_owned) {
756 ctypename = "const " + ctypename;
759 if (!param.variable_type.nullable) {
760 ctypename += "*";
765 if (param.direction != ParameterDirection.IN) {
766 ctypename += "*";
769 cparam = new CCodeParameter (get_variable_cname (param.name), ctypename);
770 } else {
771 cparam = new CCodeParameter.with_ellipsis ();
774 cparam_map.set (get_param_pos (param.cparameter_position, param.ellipsis), cparam);
775 if (carg_map != null && !param.ellipsis) {
776 carg_map.set (get_param_pos (param.cparameter_position, param.ellipsis), get_variable_cexpression (param.name));
779 return cparam;
782 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) {
783 if (m.closure) {
784 var closure_block = current_closure_block;
785 int block_id = get_block_id (closure_block);
786 var instance_param = new CCodeParameter ("_data%d_".printf (block_id), "Block%dData*".printf (block_id));
787 cparam_map.set (get_param_pos (m.cinstance_parameter_position), instance_param);
788 } else if (m.parent_symbol is Class && m is CreationMethod) {
789 var cl = (Class) m.parent_symbol;
790 if (!cl.is_compact && vcall == null) {
791 cparam_map.set (get_param_pos (m.cinstance_parameter_position), new CCodeParameter ("object_type", "GType"));
793 } else if (m.binding == MemberBinding.INSTANCE || (m.parent_symbol is Struct && m is CreationMethod)) {
794 TypeSymbol parent_type = find_parent_type (m);
795 DataType this_type;
796 if (parent_type is Class) {
797 this_type = new ObjectType ((Class) parent_type);
798 } else if (parent_type is Interface) {
799 this_type = new ObjectType ((Interface) parent_type);
800 } else if (parent_type is Struct) {
801 this_type = new StructValueType ((Struct) parent_type);
802 } else if (parent_type is Enum) {
803 this_type = new EnumValueType ((Enum) parent_type);
804 } else {
805 assert_not_reached ();
808 generate_type_declaration (this_type, decl_space);
810 CCodeParameter instance_param = null;
811 if (m.base_interface_method != null && !m.is_abstract && !m.is_virtual) {
812 var base_type = new ObjectType ((Interface) m.base_interface_method.parent_symbol);
813 instance_param = new CCodeParameter ("base", base_type.get_cname ());
814 } else if (m.overrides) {
815 var base_type = new ObjectType ((Class) m.base_method.parent_symbol);
816 instance_param = new CCodeParameter ("base", base_type.get_cname ());
817 } else {
818 if (m.parent_symbol is Struct && !((Struct) m.parent_symbol).is_simple_type ()) {
819 instance_param = new CCodeParameter ("*self", this_type.get_cname ());
820 } else {
821 instance_param = new CCodeParameter ("self", this_type.get_cname ());
824 cparam_map.set (get_param_pos (m.cinstance_parameter_position), instance_param);
825 } else if (m.binding == MemberBinding.CLASS) {
826 TypeSymbol parent_type = find_parent_type (m);
827 DataType this_type;
828 this_type = new ClassType ((Class) parent_type);
829 var class_param = new CCodeParameter ("klass", this_type.get_cname ());
830 cparam_map.set (get_param_pos (m.cinstance_parameter_position), class_param);
833 if (is_gtypeinstance_creation_method (m)) {
834 // memory management for generic types
835 int type_param_index = 0;
836 var cl = (Class) m.parent_symbol;
837 foreach (TypeParameter type_param in cl.get_type_parameters ()) {
838 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeParameter ("%s_type".printf (type_param.name.down ()), "GType"));
839 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeParameter ("%s_dup_func".printf (type_param.name.down ()), "GBoxedCopyFunc"));
840 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeParameter ("%s_destroy_func".printf (type_param.name.down ()), "GDestroyNotify"));
841 if (carg_map != null) {
842 carg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier ("%s_type".printf (type_param.name.down ())));
843 carg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ())));
844 carg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ())));
846 type_param_index++;
848 } else if (!m.closure) {
849 int type_param_index = 0;
850 foreach (var type_param in m.get_type_parameters ()) {
851 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeParameter ("%s_type".printf (type_param.name.down ()), "GType"));
852 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeParameter ("%s_dup_func".printf (type_param.name.down ()), "GBoxedCopyFunc"));
853 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeParameter ("%s_destroy_func".printf (type_param.name.down ()), "GDestroyNotify"));
854 if (carg_map != null) {
855 carg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier ("%s_type".printf (type_param.name.down ())));
856 carg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ())));
857 carg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ())));
859 type_param_index++;
863 foreach (Parameter param in m.get_parameters ()) {
864 if (param.direction != ParameterDirection.OUT) {
865 if ((direction & 1) == 0) {
866 // no in paramters
867 continue;
869 } else {
870 if ((direction & 2) == 0) {
871 // no out paramters
872 continue;
876 generate_parameter (param, decl_space, cparam_map, carg_map);
879 if ((direction & 2) != 0) {
880 generate_method_result_declaration (m, decl_space, func, cparam_map, carg_map);
883 // append C parameters in the right order
884 int last_pos = -1;
885 int min_pos;
886 while (true) {
887 min_pos = -1;
888 foreach (int pos in cparam_map.get_keys ()) {
889 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
890 min_pos = pos;
893 if (min_pos == -1) {
894 break;
896 func.add_parameter (cparam_map.get (min_pos));
897 if (vdeclarator != null) {
898 vdeclarator.add_parameter (cparam_map.get (min_pos));
900 if (vcall != null) {
901 var arg = carg_map.get (min_pos);
902 if (arg != null) {
903 vcall.add_argument (arg);
906 last_pos = min_pos;
910 public void generate_vfunc (Method m, DataType return_type, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression> carg_map, string suffix = "", int direction = 3) {
911 push_context (new EmitContext ());
913 string cname = m.get_cname ();
914 if (suffix == "_finish" && cname.has_suffix ("_async")) {
915 cname = cname.substring (0, cname.length - "_async".length);
917 var vfunc = new CCodeFunction (cname + suffix);
919 CCodeFunctionCall vcast = null;
920 if (m.parent_symbol is Interface) {
921 var iface = (Interface) m.parent_symbol;
923 vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (iface.get_upper_case_cname (null))));
924 } else {
925 var cl = (Class) m.parent_symbol;
927 vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (cl.get_upper_case_cname (null))));
929 vcast.add_argument (new CCodeIdentifier ("self"));
931 cname = m.vfunc_name;
932 if (suffix == "_finish" && cname.has_suffix ("_async")) {
933 cname = cname.substring (0, cname.length - "_async".length);
935 var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, cname + suffix));
936 carg_map.set (get_param_pos (m.cinstance_parameter_position), new CCodeIdentifier ("self"));
938 generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall, direction);
940 push_function (vfunc);
942 foreach (Expression precondition in m.get_preconditions ()) {
943 create_precondition_statement (m, return_type, precondition);
946 if (return_type is VoidType || return_type.is_real_non_null_struct_type ()) {
947 ccode.add_expression (vcall);
948 } else if (m.get_postconditions ().size == 0) {
949 /* pass method return value */
950 ccode.add_return (vcall);
951 } else {
952 /* store method return value for postconditions */
953 ccode.add_declaration (get_creturn_type (m, return_type.get_cname ()), new CCodeVariableDeclarator ("result"));
954 ccode.add_expression (new CCodeAssignment (new CCodeIdentifier ("result"), vcall));
957 if (m.get_postconditions ().size > 0) {
958 foreach (Expression postcondition in m.get_postconditions ()) {
959 create_postcondition_statement (postcondition);
962 if (!(return_type is VoidType)) {
963 ccode.add_return (new CCodeIdentifier ("result"));
967 cfile.add_function (vfunc);
969 pop_context ();
972 private void create_method_type_check_statement (Method m, DataType return_type, TypeSymbol t, bool non_null, string var_name) {
973 if (!m.coroutine) {
974 create_type_check_statement (m, return_type, t, non_null, var_name);
978 private void create_precondition_statement (CodeNode method_node, DataType ret_type, Expression precondition) {
979 var ccheck = new CCodeFunctionCall ();
981 precondition.emit (this);
983 ccheck.add_argument (get_cvalue (precondition));
985 if (method_node is CreationMethod) {
986 ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
987 ccheck.add_argument (new CCodeConstant ("NULL"));
988 } else if (method_node is Method && ((Method) method_node).coroutine) {
989 // _co function
990 ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
991 ccheck.add_argument (new CCodeConstant ("FALSE"));
992 } else if (ret_type is VoidType) {
993 /* void function */
994 ccheck.call = new CCodeIdentifier ("g_return_if_fail");
995 } else {
996 ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
998 var cdefault = default_value_for_type (ret_type, false);
999 if (cdefault != null) {
1000 ccheck.add_argument (cdefault);
1001 } else {
1002 return;
1006 ccode.add_expression (ccheck);
1009 private TypeSymbol? find_parent_type (Symbol sym) {
1010 while (sym != null) {
1011 if (sym is TypeSymbol) {
1012 return (TypeSymbol) sym;
1014 sym = sym.parent_symbol;
1016 return null;
1019 public override void visit_creation_method (CreationMethod m) {
1020 bool visible = !m.is_private_symbol ();
1022 visit_method (m);
1024 if (m.source_type == SourceFileType.FAST) {
1025 return;
1028 // do not generate _new functions for creation methods of abstract classes
1029 if (current_type_symbol is Class && !current_class.is_compact && !current_class.is_abstract) {
1030 var vfunc = new CCodeFunction (m.get_cname ());
1032 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
1033 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
1035 var vblock = new CCodeBlock ();
1037 var vcall = new CCodeFunctionCall (new CCodeIdentifier (m.get_real_cname ()));
1038 vcall.add_argument (new CCodeIdentifier (current_class.get_type_id ()));
1040 generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall);
1041 CCodeStatement cstmt = new CCodeReturnStatement (vcall);
1042 cstmt.line = vfunc.line;
1043 vblock.add_statement (cstmt);
1045 if (!visible) {
1046 vfunc.modifiers |= CCodeModifiers.STATIC;
1049 vfunc.block = vblock;
1051 cfile.add_function (vfunc);
1056 // vim:sw=8 noet