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