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
20
* JĆ¼rg Billeter <j@bitron.ch>
21
* Raffaele Sandrini <raffaele@sandrini.ch>
27
* The link between a method and generated code.
29
public abstract class Vala.CCodeMethodModule : CCodeStructModule {
31
private bool ellipses_to_valist = false;
33
public override bool method_has_wrapper (Method method) {
34
return (method.get_attribute ("NoWrapper") == null);
37
string get_creturn_type (Method m, string default_value) {
38
string type = get_ccode_type (m);
45
bool is_gtypeinstance_creation_method (Method m) {
48
var cl = m.parent_symbol as Class;
49
if (m is CreationMethod && cl != null && !cl.is_compact) {
56
public virtual void generate_method_result_declaration (Method m, CCodeFile decl_space, CCodeFunction cfunc, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
57
var creturn_type = m.return_type;
58
if (m is CreationMethod) {
59
var cl = m.parent_symbol as Class;
61
// object creation methods return the new object in C
62
// in Vala they have no return type
63
creturn_type = new ObjectType (cl);
65
} else if (m.return_type.is_real_non_null_struct_type ()) {
66
// structs are returned via out parameter
67
creturn_type = new VoidType ();
69
cfunc.return_type = get_creturn_type (m, get_ccode_name (creturn_type));
71
generate_type_declaration (m.return_type, decl_space);
73
if (m.return_type.is_real_non_null_struct_type ()) {
74
// structs are returned via out parameter
75
var cparam = new CCodeParameter ("result", get_ccode_name (m.return_type) + "*");
76
cparam_map.set (get_param_pos (-3), cparam);
77
if (carg_map != null) {
78
carg_map.set (get_param_pos (-3), get_result_cexpression ());
80
} else if (get_ccode_array_length (m) && m.return_type is ArrayType) {
81
// return array length if appropriate
82
var array_type = (ArrayType) m.return_type;
83
var array_length_type = get_ccode_array_length_type (m) != null ? get_ccode_array_length_type (m) : "int";
84
array_length_type += "*";
86
for (int dim = 1; dim <= array_type.rank; dim++) {
87
var cparam = new CCodeParameter (get_array_length_cname ("result", dim), array_length_type);
88
cparam_map.set (get_param_pos (get_ccode_array_length_pos (m) + 0.01 * dim), cparam);
89
if (carg_map != null) {
90
carg_map.set (get_param_pos (get_ccode_array_length_pos (m) + 0.01 * dim), get_variable_cexpression (cparam.name));
93
} else if (m.return_type is DelegateType) {
94
// return delegate target if appropriate
95
var deleg_type = (DelegateType) m.return_type;
96
var d = deleg_type.delegate_symbol;
98
var cparam = new CCodeParameter (get_delegate_target_cname ("result"), "void**");
99
cparam_map.set (get_param_pos (get_ccode_delegate_target_pos (m)), cparam);
100
if (carg_map != null) {
101
carg_map.set (get_param_pos (get_ccode_delegate_target_pos (m)), get_variable_cexpression (cparam.name));
103
if (deleg_type.value_owned) {
104
cparam = new CCodeParameter (get_delegate_target_destroy_notify_cname ("result"), "GDestroyNotify*");
105
cparam_map.set (get_param_pos (get_ccode_delegate_target_pos (m) + 0.01), cparam);
106
if (carg_map != null) {
107
carg_map.set (get_param_pos (get_ccode_delegate_target_pos (m) + 0.01), get_variable_cexpression (cparam.name));
113
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)) {
114
foreach (DataType error_type in m.get_error_types ()) {
115
generate_type_declaration (error_type, decl_space);
118
var cparam = new CCodeParameter ("error", "GError**");
119
cparam_map.set (get_param_pos (-1), cparam);
120
if (carg_map != null) {
121
carg_map.set (get_param_pos (-1), new CCodeIdentifier (cparam.name));
126
public void complete_async () {
127
var state = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_");
128
var zero = new CCodeConstant ("0");
129
var state_is_zero = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, state, zero);
130
ccode.open_if (state_is_zero);
132
var async_result_expr = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_async_result");
134
var idle_call = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_complete_in_idle"));
135
idle_call.add_argument (async_result_expr);
136
ccode.add_expression (idle_call);
140
var direct_call = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_complete"));
141
direct_call.add_argument (async_result_expr);
142
ccode.add_expression (direct_call);
146
var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
147
unref.add_argument (async_result_expr);
148
ccode.add_expression (unref);
150
ccode.add_return (new CCodeConstant ("FALSE"));
153
public override void generate_method_declaration (Method m, CCodeFile decl_space) {
154
if (m.is_async_callback) {
157
if (add_symbol_declaration (decl_space, m, get_ccode_name (m))) {
161
var function = new CCodeFunction (get_ccode_name (m));
163
if (m.is_private_symbol () && !m.external) {
164
function.modifiers |= CCodeModifiers.STATIC;
166
function.modifiers |= CCodeModifiers.INLINE;
171
function.modifiers |= CCodeModifiers.DEPRECATED;
174
var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
175
var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
177
var cl = m.parent_symbol as Class;
179
// do not generate _new functions for creation methods of abstract classes
180
if (!(m is CreationMethod && cl != null && cl.is_abstract)) {
181
bool etv_tmp = ellipses_to_valist;
182
ellipses_to_valist = false;
183
generate_cparameters (m, decl_space, cparam_map, function, null, carg_map, new CCodeFunctionCall (new CCodeIdentifier ("fake")));
184
ellipses_to_valist = etv_tmp;
186
decl_space.add_function_declaration (function);
189
if (m is CreationMethod && cl != null) {
190
// _construct function
191
function = new CCodeFunction (get_ccode_real_name (m));
193
if (m.is_private_symbol ()) {
194
function.modifiers |= CCodeModifiers.STATIC;
197
cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
198
bool etv_tmp = ellipses_to_valist;
199
ellipses_to_valist = false;
200
generate_cparameters (m, decl_space, cparam_map, function);
201
ellipses_to_valist = etv_tmp;
203
decl_space.add_function_declaration (function);
205
if (m.is_variadic ()) {
206
// _constructv function
207
function = new CCodeFunction (get_constructv_name ((CreationMethod) m));
208
function.modifiers |= CCodeModifiers.STATIC;
210
cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
211
generate_cparameters (m, decl_space, cparam_map, function);
213
decl_space.add_function_declaration (function);
218
private string get_constructv_name (CreationMethod m) {
219
const string infix = "constructv";
221
var parent = m.parent_symbol as Class;
223
if (m.name == ".new") {
224
return "%s%s".printf (CCodeBaseModule.get_ccode_lower_case_prefix (parent), infix);
226
return "%s%s_%s".printf (CCodeBaseModule.get_ccode_lower_case_prefix (parent), infix, m.name);
230
void register_plugin_types (Symbol sym, Set<Symbol> registered_types) {
231
var ns = sym as Namespace;
232
var cl = sym as Class;
233
var iface = sym as Interface;
235
foreach (var ns_ns in ns.get_namespaces ()) {
236
register_plugin_types (ns_ns, registered_types);
238
foreach (var ns_cl in ns.get_classes ()) {
239
register_plugin_types (ns_cl, registered_types);
241
foreach (var ns_iface in ns.get_interfaces ()) {
242
register_plugin_types (ns_iface, registered_types);
244
} else if (cl != null) {
245
register_plugin_type (cl, registered_types);
246
foreach (var cl_cl in cl.get_classes ()) {
247
register_plugin_types (cl_cl, registered_types);
249
} else if (iface != null) {
250
register_plugin_type (iface, registered_types);
251
foreach (var iface_cl in iface.get_classes ()) {
252
register_plugin_types (iface_cl, registered_types);
257
void register_plugin_type (ObjectTypeSymbol type_symbol, Set<Symbol> registered_types) {
258
if (type_symbol.external_package) {
262
if (!registered_types.add (type_symbol)) {
263
// already registered
267
var cl = type_symbol as Class;
273
// register base types first
274
foreach (var base_type in cl.get_base_types ()) {
275
register_plugin_type ((ObjectTypeSymbol) base_type.data_type, registered_types);
279
var register_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_register_type".printf (get_ccode_lower_case_name (type_symbol, null))));
280
register_call.add_argument (new CCodeIdentifier (module_init_param_name));
281
ccode.add_expression (register_call);
285
* This function generates the code the given method. If the method is
286
* a constructor, _construct is generated, unless it's variadic, in which
287
* case _constructv is generated (and _construct is generated together
288
* with _new in visit_creation_method).
290
public override void visit_method (Method m) {
291
string real_name = get_ccode_real_name (m);
292
if (m is CreationMethod && m.is_variadic ()) {
293
real_name = get_constructv_name ((CreationMethod) m);
296
push_context (new EmitContext (m));
297
push_line (m.source_reference);
299
bool in_gobject_creation_method = false;
300
bool in_fundamental_creation_method = false;
302
check_type (m.return_type);
304
bool profile = m.get_attribute ("Profile") != null;
306
if (m.get_attribute ("NoArrayLength") != null) {
307
Report.deprecated (m.source_reference, "NoArrayLength attribute is deprecated, use [CCode (array_length = false)] instead.");
310
if (m is CreationMethod) {
311
var cl = current_type_symbol as Class;
312
if (cl != null && !cl.is_compact) {
313
if (cl.base_class == null) {
314
in_fundamental_creation_method = true;
315
} else if (gobject_type != null && cl.is_subtype_of (gobject_type)) {
316
in_gobject_creation_method = true;
322
next_coroutine_state = 1;
325
var creturn_type = m.return_type;
326
if (m.return_type.is_real_non_null_struct_type ()) {
327
// structs are returned via out parameter
328
creturn_type = new VoidType ();
331
foreach (Parameter param in m.get_parameters ()) {
335
// do not declare overriding methods and interface implementations
336
if ((m.is_abstract || m.is_virtual
337
|| (m.base_method == null && m.base_interface_method == null)) && m.signal_reference == null) {
338
generate_method_declaration (m, cfile);
340
if (!m.is_internal_symbol ()) {
341
generate_method_declaration (m, header_file);
343
if (!m.is_private_symbol ()) {
344
generate_method_declaration (m, internal_header_file);
349
string prefix = "_vala_prof_%s".printf (real_name);
351
cfile.add_include ("stdio.h");
353
var counter = new CCodeIdentifier (prefix + "_counter");
354
var counter_decl = new CCodeDeclaration ("gint");
355
counter_decl.add_declarator (new CCodeVariableDeclarator (counter.name));
356
counter_decl.modifiers = CCodeModifiers.STATIC;
357
cfile.add_type_member_declaration (counter_decl);
359
// nesting level for recursive functions
360
var level = new CCodeIdentifier (prefix + "_level");
361
var level_decl = new CCodeDeclaration ("gint");
362
level_decl.add_declarator (new CCodeVariableDeclarator (level.name));
363
level_decl.modifiers = CCodeModifiers.STATIC;
364
cfile.add_type_member_declaration (level_decl);
366
var timer = new CCodeIdentifier (prefix + "_timer");
367
var timer_decl = new CCodeDeclaration ("GTimer *");
368
timer_decl.add_declarator (new CCodeVariableDeclarator (timer.name));
369
timer_decl.modifiers = CCodeModifiers.STATIC;
370
cfile.add_type_member_declaration (timer_decl);
372
var constructor = new CCodeFunction (prefix + "_init");
373
constructor.modifiers = CCodeModifiers.STATIC;
374
constructor.attributes = "__attribute__((constructor))";
375
cfile.add_function_declaration (constructor);
376
push_function (constructor);
378
ccode.add_assignment (timer, new CCodeFunctionCall (new CCodeIdentifier ("g_timer_new")));
380
var stop_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_stop"));
381
stop_call.add_argument (timer);
382
ccode.add_expression (stop_call);
385
cfile.add_function (constructor);
388
var destructor = new CCodeFunction (prefix + "_exit");
389
destructor.modifiers = CCodeModifiers.STATIC;
390
destructor.attributes = "__attribute__((destructor))";
391
cfile.add_function_declaration (destructor);
392
push_function (destructor);
394
var elapsed_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_elapsed"));
395
elapsed_call.add_argument (timer);
396
elapsed_call.add_argument (new CCodeConstant ("NULL"));
398
var print_call = new CCodeFunctionCall (new CCodeIdentifier ("fprintf"));
399
print_call.add_argument (new CCodeIdentifier ("stderr"));
400
print_call.add_argument (new CCodeConstant ("\"%s: %%gs (%%d calls)\\n\"".printf (m.get_full_name ())));
401
print_call.add_argument (elapsed_call);
402
print_call.add_argument (counter);
403
ccode.add_expression (print_call);
406
cfile.add_function (destructor);
409
CCodeFunction function;
410
function = new CCodeFunction (real_name);
413
function.modifiers |= CCodeModifiers.INLINE;
416
if (m is CreationMethod && m.is_variadic ()) {
417
function.modifiers |= CCodeModifiers.STATIC;
420
var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
422
generate_cparameters (m, cfile, cparam_map, function);
424
// generate *_real_* functions for virtual methods
425
// also generate them for abstract methods of classes to prevent faulty subclassing
426
if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
428
if (m.base_method != null || m.base_interface_method != null) {
429
// declare *_real_* function
430
function.modifiers |= CCodeModifiers.STATIC;
431
cfile.add_function_declaration (function);
432
} else if (m.is_private_symbol ()) {
433
function.modifiers |= CCodeModifiers.STATIC;
436
if (m.body != null) {
437
function = new CCodeFunction (real_name + "_co", "gboolean");
439
// data struct to hold parameters, local variables, and the return value
440
function.add_parameter (new CCodeParameter ("_data_", Symbol.lower_case_to_camel_case (get_ccode_const_name (m)) + "Data*"));
441
function.modifiers |= CCodeModifiers.STATIC;
442
cfile.add_function_declaration (function);
447
if (m.comment != null) {
448
cfile.add_type_member_definition (new CCodeComment (m.comment.content));
451
push_function (function);
453
// generate *_real_* functions for virtual methods
454
// also generate them for abstract methods of classes to prevent faulty subclassing
455
if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
456
if (m.body != null) {
458
ccode.open_switch (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"));
460
// initial coroutine state
461
ccode.add_case (new CCodeConstant ("0"));
462
ccode.add_goto ("_state_0");
464
for (int state = 1; state <= m.yield_count; state++) {
465
ccode.add_case (new CCodeConstant (state.to_string ()));
466
ccode.add_goto ("_state_%d".printf (state));
470
// let gcc know that this can't happen
471
ccode.add_default ();
472
ccode.add_expression (new CCodeFunctionCall (new CCodeIdentifier ("g_assert_not_reached")));
477
ccode.add_label ("_state_0");
481
// add variables for parent closure blocks
482
// as closures only have one parameter for the innermost closure block
483
var closure_block = current_closure_block;
484
int block_id = get_block_id (closure_block);
486
var parent_closure_block = next_closure_block (closure_block.parent_symbol);
487
if (parent_closure_block == null) {
490
int parent_block_id = get_block_id (parent_closure_block);
492
var parent_data = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id));
493
ccode.add_declaration ("Block%dData*".printf (parent_block_id), new CCodeVariableDeclarator ("_data%d_".printf (parent_block_id)));
494
ccode.add_assignment (new CCodeIdentifier ("_data%d_".printf (parent_block_id)), parent_data);
496
closure_block = parent_closure_block;
497
block_id = parent_block_id;
500
// add self variable for closures
501
// as closures have block data parameter
502
if (m.binding == MemberBinding.INSTANCE) {
503
var cself = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "self");
504
ccode.add_declaration ("%s *".printf (get_ccode_name (current_type_symbol)), new CCodeVariableDeclarator ("self"));
505
ccode.add_assignment (new CCodeIdentifier ("self"), cself);
508
// allow capturing generic type parameters
509
foreach (var type_param in m.get_type_parameters ()) {
512
func_name = "%s_type".printf (type_param.name.down ());
513
ccode.add_declaration ("GType", new CCodeVariableDeclarator (func_name));
514
ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name));
516
func_name = "%s_dup_func".printf (type_param.name.down ());
517
ccode.add_declaration ("GBoxedCopyFunc", new CCodeVariableDeclarator (func_name));
518
ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name));
520
func_name = "%s_destroy_func".printf (type_param.name.down ());
521
ccode.add_declaration ("GDestroyNotify", new CCodeVariableDeclarator (func_name));
522
ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name));
524
} else if (m.parent_symbol is Class && !m.coroutine) {
525
var cl = (Class) m.parent_symbol;
526
if (m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
528
ReferenceType base_expression_type;
530
base_method = m.base_method;
531
base_expression_type = new ObjectType ((Class) base_method.parent_symbol);
533
base_method = m.base_interface_method;
534
base_expression_type = new ObjectType ((Interface) base_method.parent_symbol);
536
var self_target_type = new ObjectType (cl);
537
CCodeExpression cself = get_cvalue_ (transform_value (new GLibValue (base_expression_type, new CCodeIdentifier ("base"), true), self_target_type, m));
539
ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("self"));
540
ccode.add_assignment (new CCodeIdentifier ("self"), cself);
541
} else if (m.binding == MemberBinding.INSTANCE
542
&& !(m is CreationMethod)
543
&& m.base_method == null && m.base_interface_method == null) {
544
create_method_type_check_statement (m, creturn_type, cl, true, "self");
548
foreach (Parameter param in m.get_parameters ()) {
549
if (param.ellipsis) {
553
if (param.direction != ParameterDirection.OUT) {
554
var t = param.variable_type.data_type;
555
if (t != null && (t.is_reference_type () || param.variable_type.is_real_struct_type ())) {
556
var cname = get_variable_cname (param.name);
557
if (param.direction == ParameterDirection.REF && !param.variable_type.is_real_struct_type ()) {
560
create_method_type_check_statement (m, creturn_type, t, !param.variable_type.nullable, cname);
562
} else if (!m.coroutine) {
563
// declare local variable for out parameter to allow assignment even when caller passes NULL
564
var vardecl = new CCodeVariableDeclarator.zero (get_variable_cname ("_vala_" + param.name), default_value_for_type (param.variable_type, true));
565
ccode.add_declaration (get_ccode_name (param.variable_type), vardecl);
567
if (param.variable_type is ArrayType) {
568
// create variables to store array dimensions
569
var array_type = (ArrayType) param.variable_type;
571
if (!array_type.fixed_length) {
572
for (int dim = 1; dim <= array_type.rank; dim++) {
573
vardecl = new CCodeVariableDeclarator.zero (get_array_length_cname (get_variable_cname ("_vala_" + param.name), dim), new CCodeConstant ("0"));
574
ccode.add_declaration ("int", vardecl);
577
} else if (param.variable_type is DelegateType) {
578
var deleg_type = (DelegateType) param.variable_type;
579
var d = deleg_type.delegate_symbol;
581
// create variable to store delegate target
582
vardecl = new CCodeVariableDeclarator.zero ("_vala_" + get_ccode_delegate_target_name (param), new CCodeConstant ("NULL"));
583
ccode.add_declaration ("void *", vardecl);
585
if (deleg_type.value_owned) {
586
vardecl = new CCodeVariableDeclarator.zero (get_delegate_target_destroy_notify_cname (get_variable_cname ("_vala_" + param.name)), new CCodeConstant ("NULL"));
587
ccode.add_declaration ("GDestroyNotify", vardecl);
594
if (!(m.return_type is VoidType) && !m.return_type.is_real_non_null_struct_type () && !m.coroutine) {
595
var vardecl = new CCodeVariableDeclarator ("result", default_value_for_type (m.return_type, true));
596
vardecl.init0 = true;
597
ccode.add_declaration (get_ccode_name (m.return_type), vardecl);
600
if (m is CreationMethod) {
601
if (in_gobject_creation_method) {
603
ccode.add_declaration ("%s *".printf (get_ccode_name (current_type_symbol)), new CCodeVariableDeclarator.zero ("self", new CCodeConstant ("NULL")));
605
} else if (is_gtypeinstance_creation_method (m)) {
606
var cl = (Class) m.parent_symbol;
607
ccode.add_declaration (get_ccode_name (cl) + "*", new CCodeVariableDeclarator.zero ("self", new CCodeConstant ("NULL")));
609
if (cl.is_fundamental () && !((CreationMethod) m).chain_up) {
610
var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_create_instance"));
611
ccall.add_argument (get_variable_cexpression ("object_type"));
612
ccode.add_assignment (get_this_cexpression (), new CCodeCastExpression (ccall, get_ccode_name (cl) + "*"));
614
/* type, dup func, and destroy func fields for generic types */
615
foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
616
CCodeIdentifier param_name;
617
CCodeAssignment assign;
619
var priv_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv");
621
param_name = new CCodeIdentifier ("%s_type".printf (type_param.name.down ()));
622
assign = new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name);
623
ccode.add_expression (assign);
625
param_name = new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ()));
626
assign = new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name);
627
ccode.add_expression (assign);
629
param_name = new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ()));
630
assign = new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name);
631
ccode.add_expression (assign);
634
} else if (current_type_symbol is Class) {
635
var cl = (Class) m.parent_symbol;
637
ccode.add_declaration (get_ccode_name (cl) + "*", new CCodeVariableDeclarator ("self"));
640
if (!((CreationMethod) m).chain_up) {
641
// TODO implicitly chain up to base class as in add_object_creation
642
var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
643
ccall.add_argument (new CCodeIdentifier (get_ccode_name (cl)));
644
ccode.add_assignment (get_this_cexpression (), ccall);
647
if (cl.base_class == null) {
648
// derived compact classes do not have fields
649
var cinitcall = new CCodeFunctionCall (new CCodeIdentifier ("%s_instance_init".printf (get_ccode_lower_case_name (cl, null))));
650
cinitcall.add_argument (get_this_cexpression ());
651
ccode.add_expression (cinitcall);
654
var st = (Struct) m.parent_symbol;
656
// memset needs string.h
657
cfile.add_include ("string.h");
658
var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
659
czero.add_argument (new CCodeIdentifier ("self"));
660
czero.add_argument (new CCodeConstant ("0"));
661
czero.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (st))));
662
ccode.add_expression (czero);
666
if (context.module_init_method == m && in_plugin) {
667
// GTypeModule-based plug-in, register types
668
register_plugin_types (context.root, new HashSet<Symbol> ());
671
foreach (Expression precondition in m.get_preconditions ()) {
672
create_precondition_statement (m, creturn_type, precondition);
678
string prefix = "_vala_prof_%s".printf (real_name);
680
var level = new CCodeIdentifier (prefix + "_level");
681
ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, level)));
683
var counter = new CCodeIdentifier (prefix + "_counter");
684
ccode.add_expression (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, counter));
686
var timer = new CCodeIdentifier (prefix + "_timer");
687
var cont_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_continue"));
688
cont_call.add_argument (timer);
689
ccode.add_expression (cont_call);
694
if (m.body != null) {
699
string prefix = "_vala_prof_%s".printf (real_name);
701
var level = new CCodeIdentifier (prefix + "_level");
702
ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, level)));
704
var timer = new CCodeIdentifier (prefix + "_timer");
706
var stop_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_stop"));
707
stop_call.add_argument (timer);
708
ccode.add_expression (stop_call);
713
// generate *_real_* functions for virtual methods
714
// also generate them for abstract methods of classes to prevent faulty subclassing
715
if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
716
/* Methods imported from a plain C file don't
717
* have a body, e.g. Vala.Parser.parse_file () */
718
if (m.body != null) {
719
if (current_method_inner_error) {
720
/* always separate error parameter and inner_error local variable
721
* as error may be set to NULL but we're always interested in inner errors
724
closure_struct.add_field ("GError *", "_inner_error_");
726
// no initialization necessary, closure struct is zeroed
728
ccode.add_declaration ("GError *", new CCodeVariableDeclarator.zero ("_inner_error_", new CCodeConstant ("NULL")));
737
if (!(m.return_type is VoidType) && !m.return_type.is_real_non_null_struct_type () && !m.coroutine) {
738
// add dummy return if exit block is known to be unreachable to silence C compiler
739
if (m.return_block != null && m.return_block.get_predecessors ().size == 0) {
740
ccode.add_return (new CCodeIdentifier ("result"));
744
if (m is CreationMethod) {
745
if (current_type_symbol is Class) {
746
creturn_type = new ObjectType (current_class);
748
creturn_type = new VoidType ();
752
if (current_type_symbol is Class && gobject_type != null && current_class.is_subtype_of (gobject_type)
753
&& current_class.get_type_parameters ().size > 0
754
&& !((CreationMethod) m).chain_up) {
755
var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, new CCodeIdentifier ("__params_it"), new CCodeIdentifier ("__params"));
756
ccode.open_while (ccond);
757
ccode.add_expression (new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, new CCodeIdentifier ("__params_it")));
758
var cunsetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_unset"));
759
cunsetcall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("__params_it"), "value")));
760
ccode.add_expression (cunsetcall);
763
var cfreeparams = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
764
cfreeparams.add_argument (new CCodeIdentifier ("__params"));
765
ccode.add_expression (cfreeparams);
768
if (current_type_symbol is Class && !m.coroutine) {
769
CCodeExpression cresult = new CCodeIdentifier ("self");
770
if (get_ccode_type (m) != null) {
771
cresult = new CCodeCastExpression (cresult, get_ccode_type (m));
774
ccode.add_return (cresult);
778
cfile.add_function (ccode);
782
if (m.is_abstract && current_type_symbol is Class) {
783
// generate helpful error message if a sublcass does not implement an abstract method.
784
// This is only meaningful for subclasses implemented in C since the vala compiler would
785
// complain during compile time of such en error.
787
// add critical warning that this method should not have been called
788
var type_from_instance_call = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_FROM_INSTANCE"));
789
type_from_instance_call.add_argument (new CCodeIdentifier ("self"));
791
var type_name_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_name"));
792
type_name_call.add_argument (type_from_instance_call);
794
var error_string = "\"Type `%%s' does not implement abstract method `%s'\"".printf (get_ccode_name (m));
796
var cerrorcall = new CCodeFunctionCall (new CCodeIdentifier ("g_critical"));
797
cerrorcall.add_argument (new CCodeConstant (error_string));
798
cerrorcall.add_argument (type_name_call);
800
ccode.add_expression (cerrorcall);
802
// add return statement
803
return_default_value (creturn_type);
805
cfile.add_function (ccode);
810
if ((m.is_abstract || m.is_virtual) && !m.coroutine &&
811
/* If the method is a signal handler, the declaration
812
* is not needed. -- the name should be reserved for the
814
m.signal_reference == null) {
816
cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
817
var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
819
generate_vfunc (m, creturn_type, cparam_map, carg_map);
823
// m is possible entry point, add appropriate startup code
824
var cmain = new CCodeFunction ("main", "int");
825
cmain.line = function.line;
826
cmain.add_parameter (new CCodeParameter ("argc", "int"));
827
cmain.add_parameter (new CCodeParameter ("argv", "char **"));
828
push_function (cmain);
830
if (context.mem_profiler) {
831
var mem_profiler_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_mem_set_vtable"));
832
mem_profiler_init_call.line = cmain.line;
833
mem_profiler_init_call.add_argument (new CCodeConstant ("glib_mem_profiler_table"));
834
ccode.add_expression (mem_profiler_init_call);
837
if (context.thread && !context.require_glib_version (2, 32)) {
838
var thread_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_thread_init"));
839
thread_init_call.line = cmain.line;
840
thread_init_call.add_argument (new CCodeConstant ("NULL"));
841
ccode.add_expression (thread_init_call);
844
if (!context.require_glib_version (2, 36)) {
845
ccode.add_expression (new CCodeFunctionCall (new CCodeIdentifier ("g_type_init")));
848
var main_call = new CCodeFunctionCall (new CCodeIdentifier (function.name));
849
if (m.get_parameters ().size == 1) {
850
main_call.add_argument (new CCodeIdentifier ("argv"));
851
main_call.add_argument (new CCodeIdentifier ("argc"));
853
if (m.return_type is VoidType) {
854
// method returns void, always use 0 as exit code
855
ccode.add_expression (main_call);
856
ccode.add_return (new CCodeConstant ("0"));
858
ccode.add_return (main_call);
861
cfile.add_function (cmain);
867
public virtual CCodeParameter generate_parameter (Parameter param, CCodeFile decl_space, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
868
CCodeParameter cparam;
869
if (!param.ellipsis) {
870
string ctypename = get_ccode_name (param.variable_type);
872
generate_type_declaration (param.variable_type, decl_space);
874
// pass non-simple structs always by reference
875
if (param.variable_type.data_type is Struct) {
876
var st = (Struct) param.variable_type.data_type;
877
if (!st.is_simple_type () && param.direction == ParameterDirection.IN) {
878
if (st.is_immutable && !param.variable_type.value_owned) {
879
ctypename = "const " + ctypename;
882
if (!param.variable_type.nullable) {
888
if (param.direction != ParameterDirection.IN) {
892
cparam = new CCodeParameter (get_variable_cname (param.name), ctypename);
893
} else if (ellipses_to_valist) {
894
cparam = new CCodeParameter ("_vala_va_list", "va_list");
896
cparam = new CCodeParameter.with_ellipsis ();
899
cparam_map.set (get_param_pos (get_ccode_pos (param), param.ellipsis), cparam);
900
if (carg_map != null && !param.ellipsis) {
901
carg_map.set (get_param_pos (get_ccode_pos (param), param.ellipsis), get_variable_cexpression (param.name));
907
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) {
909
var closure_block = current_closure_block;
910
int block_id = get_block_id (closure_block);
911
var instance_param = new CCodeParameter ("_data%d_".printf (block_id), "Block%dData*".printf (block_id));
912
cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), instance_param);
913
} else if (m.parent_symbol is Class && m is CreationMethod) {
914
var cl = (Class) m.parent_symbol;
915
if (!cl.is_compact && vcall == null && (direction & 1) == 1) {
916
cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), new CCodeParameter ("object_type", "GType"));
918
} else if (m.binding == MemberBinding.INSTANCE || (m.parent_symbol is Struct && m is CreationMethod)) {
919
TypeSymbol parent_type = find_parent_type (m);
921
if (parent_type is Class) {
922
this_type = new ObjectType ((Class) parent_type);
923
} else if (parent_type is Interface) {
924
this_type = new ObjectType ((Interface) parent_type);
925
} else if (parent_type is Struct) {
926
this_type = new StructValueType ((Struct) parent_type);
927
} else if (parent_type is Enum) {
928
this_type = new EnumValueType ((Enum) parent_type);
930
assert_not_reached ();
933
generate_type_declaration (this_type, decl_space);
935
CCodeParameter instance_param = null;
936
if (m.base_interface_method != null && !m.is_abstract && !m.is_virtual) {
937
var base_type = new ObjectType ((Interface) m.base_interface_method.parent_symbol);
938
instance_param = new CCodeParameter ("base", get_ccode_name (base_type));
939
} else if (m.overrides) {
940
var base_type = new ObjectType ((Class) m.base_method.parent_symbol);
941
instance_param = new CCodeParameter ("base", get_ccode_name (base_type));
943
if (m.parent_symbol is Struct && !((Struct) m.parent_symbol).is_simple_type ()) {
944
instance_param = new CCodeParameter ("*self", get_ccode_name (this_type));
946
instance_param = new CCodeParameter ("self", get_ccode_name (this_type));
949
cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), instance_param);
950
} else if (m.binding == MemberBinding.CLASS) {
951
TypeSymbol parent_type = find_parent_type (m);
953
this_type = new ClassType ((Class) parent_type);
954
var class_param = new CCodeParameter ("klass", get_ccode_name (this_type));
955
cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), class_param);
958
if (is_gtypeinstance_creation_method (m)) {
959
// memory management for generic types
960
int type_param_index = 0;
961
var cl = (Class) m.parent_symbol;
962
foreach (TypeParameter type_param in cl.get_type_parameters ()) {
963
cparam_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeParameter ("%s_type".printf (type_param.name.down ()), "GType"));
964
cparam_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeParameter ("%s_dup_func".printf (type_param.name.down ()), "GBoxedCopyFunc"));
965
cparam_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeParameter ("%s_destroy_func".printf (type_param.name.down ()), "GDestroyNotify"));
966
if (carg_map != null) {
967
carg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier ("%s_type".printf (type_param.name.down ())));
968
carg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ())));
969
carg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ())));
973
} else if (!m.closure && (direction & 1) == 1) {
974
int type_param_index = 0;
975
foreach (var type_param in m.get_type_parameters ()) {
976
cparam_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeParameter ("%s_type".printf (type_param.name.down ()), "GType"));
977
cparam_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeParameter ("%s_dup_func".printf (type_param.name.down ()), "GBoxedCopyFunc"));
978
cparam_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeParameter ("%s_destroy_func".printf (type_param.name.down ()), "GDestroyNotify"));
979
if (carg_map != null) {
980
carg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier ("%s_type".printf (type_param.name.down ())));
981
carg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ())));
982
carg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ())));
988
foreach (Parameter param in m.get_parameters ()) {
989
if (param.direction != ParameterDirection.OUT) {
990
if ((direction & 1) == 0) {
995
if ((direction & 2) == 0) {
1001
generate_parameter (param, decl_space, cparam_map, carg_map);
1004
if ((direction & 2) != 0) {
1005
generate_method_result_declaration (m, decl_space, func, cparam_map, carg_map);
1008
// append C parameters in the right order
1013
foreach (int pos in cparam_map.get_keys ()) {
1014
if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
1018
if (min_pos == -1) {
1021
func.add_parameter (cparam_map.get (min_pos));
1022
if (vdeclarator != null) {
1023
vdeclarator.add_parameter (cparam_map.get (min_pos));
1025
if (vcall != null) {
1026
var arg = carg_map.get (min_pos);
1028
vcall.add_argument (arg);
1035
public void generate_vfunc (Method m, DataType return_type, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression> carg_map, string suffix = "", int direction = 3) {
1036
push_context (new EmitContext ());
1038
string cname = get_ccode_name (m);
1039
if (suffix == "_finish" && cname.has_suffix ("_async")) {
1040
cname = cname.substring (0, cname.length - "_async".length);
1042
var vfunc = new CCodeFunction (cname + suffix);
1044
CCodeFunctionCall vcast = null;
1045
if (m.parent_symbol is Interface) {
1046
var iface = (Interface) m.parent_symbol;
1048
vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface))));
1050
var cl = (Class) m.parent_symbol;
1052
vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (get_ccode_upper_case_name (cl))));
1054
vcast.add_argument (new CCodeIdentifier ("self"));
1056
cname = get_ccode_vfunc_name (m);
1057
if (suffix == "_finish" && cname.has_suffix ("_async")) {
1058
cname = cname.substring (0, cname.length - "_async".length);
1060
var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, cname + suffix));
1061
carg_map.set (get_param_pos (get_ccode_instance_pos (m)), new CCodeIdentifier ("self"));
1063
generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall, direction);
1065
push_function (vfunc);
1067
if (context.assert && m.return_type.data_type is Struct && ((Struct) m.return_type.data_type).is_simple_type () && default_value_for_type (m.return_type, false) == null) {
1068
// the type check will use the result variable
1069
var vardecl = new CCodeVariableDeclarator ("result", default_value_for_type (m.return_type, true));
1070
vardecl.init0 = true;
1071
ccode.add_declaration (get_ccode_name (m.return_type), vardecl);
1074
// add a typecheck statement for "self"
1075
create_method_type_check_statement (m, return_type, (TypeSymbol) m.parent_symbol, true, "self");
1077
foreach (Expression precondition in m.get_preconditions ()) {
1078
create_precondition_statement (m, return_type, precondition);
1081
if (return_type is VoidType || return_type.is_real_non_null_struct_type ()) {
1082
ccode.add_expression (vcall);
1083
} else if (m.get_postconditions ().size == 0) {
1084
/* pass method return value */
1085
ccode.add_return (vcall);
1087
/* store method return value for postconditions */
1088
ccode.add_declaration (get_creturn_type (m, get_ccode_name (return_type)), new CCodeVariableDeclarator ("result"));
1089
ccode.add_assignment (new CCodeIdentifier ("result"), vcall);
1092
if (m.get_postconditions ().size > 0) {
1093
foreach (Expression postcondition in m.get_postconditions ()) {
1094
create_postcondition_statement (postcondition);
1097
if (!(return_type is VoidType)) {
1098
ccode.add_return (new CCodeIdentifier ("result"));
1102
cfile.add_function (vfunc);
1107
private void create_method_type_check_statement (Method m, DataType return_type, TypeSymbol t, bool non_null, string var_name) {
1109
create_type_check_statement (m, return_type, t, non_null, var_name);
1113
private void create_precondition_statement (CodeNode method_node, DataType ret_type, Expression precondition) {
1114
var ccheck = new CCodeFunctionCall ();
1116
precondition.emit (this);
1118
ccheck.add_argument (get_cvalue (precondition));
1120
if (method_node is CreationMethod) {
1121
ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
1122
ccheck.add_argument (new CCodeConstant ("NULL"));
1123
} else if (method_node is Method && ((Method) method_node).coroutine) {
1125
ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
1126
ccheck.add_argument (new CCodeConstant ("FALSE"));
1127
} else if (ret_type is VoidType) {
1129
ccheck.call = new CCodeIdentifier ("g_return_if_fail");
1131
ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
1133
var cdefault = default_value_for_type (ret_type, false);
1134
if (cdefault != null) {
1135
ccheck.add_argument (cdefault);
1141
ccode.add_expression (ccheck);
1144
private TypeSymbol? find_parent_type (Symbol sym) {
1145
while (sym != null) {
1146
if (sym is TypeSymbol) {
1147
return (TypeSymbol) sym;
1149
sym = sym.parent_symbol;
1154
public override void visit_creation_method (CreationMethod m) {
1155
push_line (m.source_reference);
1157
ellipses_to_valist = true;
1159
ellipses_to_valist = false;
1161
if (m.source_type == SourceFileType.FAST) {
1165
// do not generate _new functions for creation methods of abstract classes
1166
if (current_type_symbol is Class && !current_class.is_compact && !current_class.is_abstract) {
1168
create_aux_constructor (m, get_ccode_name (m), false);
1170
// _construct function (if visit_method generated _constructv)
1171
if (m.is_variadic ()) {
1172
create_aux_constructor (m, get_ccode_real_name (m), true);
1179
private void create_aux_constructor (CreationMethod m, string func_name, bool self_as_first_parameter) {
1180
var vfunc = new CCodeFunction (func_name);
1181
if (m.is_private_symbol ()) {
1182
vfunc.modifiers |= CCodeModifiers.STATIC;
1185
var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
1186
var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
1188
push_function (vfunc);
1190
string constructor = (m.is_variadic ()) ? get_constructv_name (m) : get_ccode_real_name (m);
1191
var vcall = new CCodeFunctionCall (new CCodeIdentifier (constructor));
1193
if (self_as_first_parameter) {
1194
cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), new CCodeParameter ("object_type", "GType"));
1195
vcall.add_argument (get_variable_cexpression ("object_type"));
1197
vcall.add_argument (new CCodeIdentifier (get_ccode_type_id (current_class)));
1201
generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall);
1203
if (m.is_variadic ()) {
1205
int second_last_pos = -1;
1206
foreach (int pos in cparam_map.get_keys ()) {
1207
if (pos > last_pos) {
1208
second_last_pos = last_pos;
1210
} else if (pos > second_last_pos) {
1211
second_last_pos = pos;
1215
var va_start = new CCodeFunctionCall (new CCodeIdentifier ("va_start"));
1216
va_start.add_argument (new CCodeIdentifier ("_vala_va_list_obj"));
1217
va_start.add_argument (carg_map.get (second_last_pos));
1219
ccode.add_declaration ("va_list", new CCodeVariableDeclarator ("_vala_va_list_obj"));
1220
ccode.add_expression (va_start);
1222
vcall.add_argument (new CCodeIdentifier("_vala_va_list_obj"));
1225
ccode.add_return (vcall);
1229
cfile.add_function (vfunc);