Fix ellipsis parameter position in generated methods
[vala-lang.git] / codegen / valagobjectmodule.vala
blob238411b29c74903ca5ee0461710a8ecde3b49281
1 /* valagobjectmodule.vala
3 * Copyright (C) 2006-2010 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
26 public class Vala.GObjectModule : GTypeModule {
27 int dynamic_property_id;
28 int signal_wrapper_id;
30 public override void visit_class (Class cl) {
31 base.visit_class (cl);
33 if (!cl.is_subtype_of (gobject_type)) {
34 return;
37 if (class_has_readable_properties (cl) || cl.get_type_parameters ().size > 0) {
38 add_get_property_function (cl);
40 if (class_has_writable_properties (cl) || cl.get_type_parameters ().size > 0) {
41 add_set_property_function (cl);
45 public override void generate_class_init (Class cl, CCodeBlock init_block) {
46 if (!cl.is_subtype_of (gobject_type)) {
47 return;
50 /* set property handlers */
51 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
52 ccall.add_argument (new CCodeIdentifier ("klass"));
53 if (class_has_readable_properties (cl) || cl.get_type_parameters ().size > 0) {
54 init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccall, "get_property"), new CCodeIdentifier ("%s_get_property".printf (cl.get_lower_case_cname (null))))));
56 if (class_has_writable_properties (cl) || cl.get_type_parameters ().size > 0) {
57 init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccall, "set_property"), new CCodeIdentifier ("%s_set_property".printf (cl.get_lower_case_cname (null))))));
60 /* set constructor */
61 if (cl.constructor != null) {
62 var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
63 ccast.add_argument (new CCodeIdentifier ("klass"));
64 init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, "constructor"), new CCodeIdentifier ("%s_constructor".printf (cl.get_lower_case_cname (null))))));
67 /* set finalize function */
68 if (cl.get_fields ().size > 0 || cl.destructor != null) {
69 var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
70 ccast.add_argument (new CCodeIdentifier ("klass"));
71 init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, "finalize"), new CCodeIdentifier ("%s_finalize".printf (cl.get_lower_case_cname (null))))));
74 /* create type, dup_func, and destroy_func properties for generic types */
75 foreach (TypeParameter type_param in cl.get_type_parameters ()) {
76 string func_name, enum_value;
77 CCodeConstant func_name_constant;
78 CCodeFunctionCall cinst, cspec;
80 func_name = "%s_type".printf (type_param.name.down ());
81 func_name_constant = new CCodeConstant ("\"%s-type\"".printf (type_param.name.down ()));
82 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
83 cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
84 cinst.add_argument (ccall);
85 cinst.add_argument (new CCodeConstant (enum_value));
86 cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_gtype"));
87 cspec.add_argument (func_name_constant);
88 cspec.add_argument (new CCodeConstant ("\"type\""));
89 cspec.add_argument (new CCodeConstant ("\"type\""));
90 cspec.add_argument (new CCodeIdentifier ("G_TYPE_NONE"));
91 cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
92 cinst.add_argument (cspec);
93 init_block.add_statement (new CCodeExpressionStatement (cinst));
94 prop_enum.add_value (new CCodeEnumValue (enum_value));
97 func_name = "%s_dup_func".printf (type_param.name.down ());
98 func_name_constant = new CCodeConstant ("\"%s-dup-func\"".printf (type_param.name.down ()));
99 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
100 cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
101 cinst.add_argument (ccall);
102 cinst.add_argument (new CCodeConstant (enum_value));
103 cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_pointer"));
104 cspec.add_argument (func_name_constant);
105 cspec.add_argument (new CCodeConstant ("\"dup func\""));
106 cspec.add_argument (new CCodeConstant ("\"dup func\""));
107 cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
108 cinst.add_argument (cspec);
109 init_block.add_statement (new CCodeExpressionStatement (cinst));
110 prop_enum.add_value (new CCodeEnumValue (enum_value));
113 func_name = "%s_destroy_func".printf (type_param.name.down ());
114 func_name_constant = new CCodeConstant ("\"%s-destroy-func\"".printf (type_param.name.down ()));
115 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
116 cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
117 cinst.add_argument (ccall);
118 cinst.add_argument (new CCodeConstant (enum_value));
119 cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_pointer"));
120 cspec.add_argument (func_name_constant);
121 cspec.add_argument (new CCodeConstant ("\"destroy func\""));
122 cspec.add_argument (new CCodeConstant ("\"destroy func\""));
123 cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
124 cinst.add_argument (cspec);
125 init_block.add_statement (new CCodeExpressionStatement (cinst));
126 prop_enum.add_value (new CCodeEnumValue (enum_value));
129 /* create properties */
130 var props = cl.get_properties ();
131 foreach (Property prop in props) {
132 if (!is_gobject_property (prop)) {
133 continue;
136 if (prop.comment != null) {
137 init_block.add_statement (new CCodeComment (prop.comment.content));
140 if (prop.overrides || prop.base_interface_property != null) {
141 var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_override_property"));
142 cinst.add_argument (ccall);
143 cinst.add_argument (new CCodeConstant (prop.get_upper_case_cname ()));
144 cinst.add_argument (prop.get_canonical_cconstant ());
146 init_block.add_statement (new CCodeExpressionStatement (cinst));
147 } else {
148 var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
149 cinst.add_argument (ccall);
150 cinst.add_argument (new CCodeConstant (prop.get_upper_case_cname ()));
151 cinst.add_argument (get_param_spec (prop));
153 init_block.add_statement (new CCodeExpressionStatement (cinst));
158 private bool class_has_readable_properties (Class cl) {
159 foreach (Property prop in cl.get_properties ()) {
160 if (prop.get_accessor != null) {
161 return true;
164 return false;
167 private bool class_has_writable_properties (Class cl) {
168 foreach (Property prop in cl.get_properties ()) {
169 if (prop.set_accessor != null) {
170 return true;
173 return false;
176 private void add_get_property_function (Class cl) {
177 var get_prop = new CCodeFunction ("%s_get_property".printf (cl.get_lower_case_cname (null)), "void");
178 get_prop.modifiers = CCodeModifiers.STATIC;
179 get_prop.add_parameter (new CCodeFormalParameter ("object", "GObject *"));
180 get_prop.add_parameter (new CCodeFormalParameter ("property_id", "guint"));
181 get_prop.add_parameter (new CCodeFormalParameter ("value", "GValue *"));
182 get_prop.add_parameter (new CCodeFormalParameter ("pspec", "GParamSpec *"));
184 var block = new CCodeBlock ();
186 CCodeFunctionCall ccall = generate_instance_cast (new CCodeIdentifier ("object"), cl);
187 var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
188 cdecl.add_declarator (new CCodeVariableDeclarator ("self", ccall));
189 block.add_statement (cdecl);
191 int boxed_name_id = 0;
192 bool length_declared = false;
194 var cswitch = new CCodeSwitchStatement (new CCodeIdentifier ("property_id"));
195 var props = cl.get_properties ();
196 foreach (Property prop in props) {
197 if (prop.get_accessor == null || prop.is_abstract) {
198 continue;
200 if (!is_gobject_property (prop)) {
201 // don't register private properties
202 continue;
205 string prefix = cl.get_lower_case_cname (null);
206 CCodeExpression cself = new CCodeIdentifier ("self");
207 if (prop.base_property != null) {
208 var base_type = (Class) prop.base_property.parent_symbol;
209 prefix = base_type.get_lower_case_cname (null);
210 cself = transform_expression (cself, new ObjectType (cl), new ObjectType (base_type));
212 generate_property_accessor_declaration (prop.base_property.get_accessor, source_declarations);
213 } else if (prop.base_interface_property != null) {
214 var base_type = (Interface) prop.base_interface_property.parent_symbol;
215 prefix = base_type.get_lower_case_cname (null);
216 cself = transform_expression (cself, new ObjectType (cl), new ObjectType (base_type));
218 generate_property_accessor_declaration (prop.base_interface_property.get_accessor, source_declarations);
221 cswitch.add_statement (new CCodeCaseStatement (new CCodeIdentifier (prop.get_upper_case_cname ())));
222 if (prop.property_type.is_real_struct_type ()) {
223 var st = prop.property_type.data_type as Struct;
224 var boxed = "boxed%d".printf (boxed_name_id++);
226 cdecl = new CCodeDeclaration (st.get_cname ());
227 cdecl.add_declarator (new CCodeVariableDeclarator (boxed));
228 block.add_statement (cdecl);
230 ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_get_%s".printf (prefix, prop.name)));
231 ccall.add_argument (cself);
232 var boxed_addr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (boxed));
233 ccall.add_argument (boxed_addr);
234 cswitch.add_statement (new CCodeExpressionStatement (ccall));
236 var csetcall = new CCodeFunctionCall ();
237 csetcall.call = get_value_setter_function (prop.property_type);
238 csetcall.add_argument (new CCodeIdentifier ("value"));
239 csetcall.add_argument (boxed_addr);
240 cswitch.add_statement (new CCodeExpressionStatement (csetcall));
242 if (requires_destroy (prop.get_accessor.value_type)) {
243 cswitch.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (boxed), prop.get_accessor.value_type, null)));
245 } else {
246 ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_get_%s".printf (prefix, prop.name)));
247 ccall.add_argument (cself);
248 var array_type = prop.property_type as ArrayType;
249 if (array_type != null && array_type.element_type.data_type == string_type.data_type) {
250 // G_TYPE_STRV
251 if (!length_declared) {
252 cdecl = new CCodeDeclaration ("int");
253 cdecl.add_declarator (new CCodeVariableDeclarator ("length"));
254 block.add_statement (cdecl);
255 length_declared = true;
257 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("length")));
259 var csetcall = new CCodeFunctionCall ();
260 if (prop.get_accessor.value_type.value_owned) {
261 csetcall.call = get_value_taker_function (prop.property_type);
262 } else {
263 csetcall.call = get_value_setter_function (prop.property_type);
265 csetcall.add_argument (new CCodeIdentifier ("value"));
266 csetcall.add_argument (ccall);
267 cswitch.add_statement (new CCodeExpressionStatement (csetcall));
269 cswitch.add_statement (new CCodeBreakStatement ());
271 cswitch.add_statement (new CCodeLabel ("default"));
272 cswitch.add_statement (get_invalid_property_id_warn_statement ());
273 cswitch.add_statement (new CCodeBreakStatement ());
275 block.add_statement (cswitch);
277 source_declarations.add_type_member_declaration (get_prop.copy ());
279 get_prop.block = block;
281 source_type_member_definition.append (get_prop);
284 private void add_set_property_function (Class cl) {
285 var set_prop = new CCodeFunction ("%s_set_property".printf (cl.get_lower_case_cname (null)), "void");
286 set_prop.modifiers = CCodeModifiers.STATIC;
287 set_prop.add_parameter (new CCodeFormalParameter ("object", "GObject *"));
288 set_prop.add_parameter (new CCodeFormalParameter ("property_id", "guint"));
289 set_prop.add_parameter (new CCodeFormalParameter ("value", "const GValue *"));
290 set_prop.add_parameter (new CCodeFormalParameter ("pspec", "GParamSpec *"));
292 var block = new CCodeBlock ();
294 CCodeFunctionCall ccall = generate_instance_cast (new CCodeIdentifier ("object"), cl);
295 var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
296 cdecl.add_declarator (new CCodeVariableDeclarator ("self", ccall));
297 block.add_statement (cdecl);
299 var boxed_declared = false;
301 var cswitch = new CCodeSwitchStatement (new CCodeIdentifier ("property_id"));
302 var props = cl.get_properties ();
303 foreach (Property prop in props) {
304 if (prop.set_accessor == null || prop.is_abstract) {
305 continue;
307 if (!is_gobject_property (prop)) {
308 continue;
311 string prefix = cl.get_lower_case_cname (null);
312 CCodeExpression cself = new CCodeIdentifier ("self");
313 if (prop.base_property != null) {
314 var base_type = (Class) prop.base_property.parent_symbol;
315 prefix = base_type.get_lower_case_cname (null);
316 cself = transform_expression (cself, new ObjectType (cl), new ObjectType (base_type));
318 generate_property_accessor_declaration (prop.base_property.set_accessor, source_declarations);
319 } else if (prop.base_interface_property != null) {
320 var base_type = (Interface) prop.base_interface_property.parent_symbol;
321 prefix = base_type.get_lower_case_cname (null);
322 cself = transform_expression (cself, new ObjectType (cl), new ObjectType (base_type));
324 generate_property_accessor_declaration (prop.base_interface_property.set_accessor, source_declarations);
327 cswitch.add_statement (new CCodeCaseStatement (new CCodeIdentifier (prop.get_upper_case_cname ())));
328 ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_set_%s".printf (prefix, prop.name)));
329 ccall.add_argument (cself);
330 if (prop.property_type is ArrayType && ((ArrayType)prop.property_type).element_type.data_type == string_type.data_type) {
331 if (!boxed_declared) {
332 cdecl = new CCodeDeclaration ("gpointer");
333 cdecl.add_declarator (new CCodeVariableDeclarator ("boxed"));
334 block.add_statement (cdecl);
335 boxed_declared = true;
337 var cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_boxed"));
338 cgetcall.add_argument (new CCodeIdentifier ("value"));
339 cswitch.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("boxed"), cgetcall)));
340 ccall.add_argument (new CCodeIdentifier ("boxed"));
342 var cstrvlen = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
343 cstrvlen.add_argument (new CCodeIdentifier ("boxed"));
344 ccall.add_argument (cstrvlen);
345 } else {
346 var cgetcall = new CCodeFunctionCall ();
347 if (prop.property_type.data_type != null) {
348 cgetcall.call = new CCodeIdentifier (prop.property_type.data_type.get_get_value_function ());
349 } else {
350 cgetcall.call = new CCodeIdentifier ("g_value_get_pointer");
352 cgetcall.add_argument (new CCodeIdentifier ("value"));
353 ccall.add_argument (cgetcall);
355 cswitch.add_statement (new CCodeExpressionStatement (ccall));
356 cswitch.add_statement (new CCodeBreakStatement ());
358 cswitch.add_statement (new CCodeLabel ("default"));
359 cswitch.add_statement (get_invalid_property_id_warn_statement ());
360 cswitch.add_statement (new CCodeBreakStatement ());
362 block.add_statement (cswitch);
364 /* type, dup func, and destroy func properties for generic types */
365 foreach (TypeParameter type_param in cl.get_type_parameters ()) {
366 string func_name, enum_value;
367 CCodeMemberAccess cfield;
368 CCodeFunctionCall cgetcall;
370 func_name = "%s_type".printf (type_param.name.down ());
371 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
372 cswitch.add_statement (new CCodeCaseStatement (new CCodeIdentifier (enum_value)));
373 cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
374 cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_gtype"));
375 cgetcall.add_argument (new CCodeIdentifier ("value"));
376 cswitch.add_statement (new CCodeExpressionStatement (new CCodeAssignment (cfield, cgetcall)));
377 cswitch.add_statement (new CCodeBreakStatement ());
379 func_name = "%s_dup_func".printf (type_param.name.down ());
380 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
381 cswitch.add_statement (new CCodeCaseStatement (new CCodeIdentifier (enum_value)));
382 cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
383 cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer"));
384 cgetcall.add_argument (new CCodeIdentifier ("value"));
385 cswitch.add_statement (new CCodeExpressionStatement (new CCodeAssignment (cfield, cgetcall)));
386 cswitch.add_statement (new CCodeBreakStatement ());
388 func_name = "%s_destroy_func".printf (type_param.name.down ());
389 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
390 cswitch.add_statement (new CCodeCaseStatement (new CCodeIdentifier (enum_value)));
391 cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
392 cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer"));
393 cgetcall.add_argument (new CCodeIdentifier ("value"));
394 cswitch.add_statement (new CCodeExpressionStatement (new CCodeAssignment (cfield, cgetcall)));
395 cswitch.add_statement (new CCodeBreakStatement ());
398 source_declarations.add_type_member_declaration (set_prop.copy ());
400 set_prop.block = block;
402 source_type_member_definition.append (set_prop);
405 private CCodeStatement get_invalid_property_id_warn_statement () {
406 // warn on invalid property id
407 var cwarn = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_WARN_INVALID_PROPERTY_ID"));
408 cwarn.add_argument (new CCodeIdentifier ("object"));
409 cwarn.add_argument (new CCodeIdentifier ("property_id"));
410 cwarn.add_argument (new CCodeIdentifier ("pspec"));
411 return new CCodeExpressionStatement (cwarn);
414 public override CCodeExpression get_construct_property_assignment (CCodeConstant canonical_cconstant, DataType property_type, CCodeExpression value) {
415 // this property is used as a construction parameter
416 var cpointer = new CCodeIdentifier ("__params_it");
418 var ccomma = new CCodeCommaExpression ();
419 // set name in array for current parameter
420 var cnamemember = new CCodeMemberAccess.pointer (cpointer, "name");
421 var cnameassign = new CCodeAssignment (cnamemember, canonical_cconstant);
422 ccomma.append_expression (cnameassign);
424 var gvaluearg = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (cpointer, "value"));
426 // initialize GValue in array for current parameter
427 var cvalueinit = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
428 cvalueinit.add_argument (gvaluearg);
429 cvalueinit.add_argument (new CCodeIdentifier (property_type.get_type_id ()));
430 ccomma.append_expression (cvalueinit);
432 // set GValue for current parameter
433 var cvalueset = new CCodeFunctionCall (get_value_setter_function (property_type));
434 cvalueset.add_argument (gvaluearg);
435 if (property_type.is_real_struct_type ()) {
436 cvalueset.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, value));
437 } else {
438 cvalueset.add_argument (value);
440 ccomma.append_expression (cvalueset);
442 // move pointer to next parameter in array
443 ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, cpointer));
445 return ccomma;
448 public override void visit_constructor (Constructor c) {
449 bool old_method_inner_error = current_method_inner_error;
450 current_method_inner_error = false;
452 if (c.binding == MemberBinding.CLASS || c.binding == MemberBinding.STATIC) {
453 in_static_or_class_context = true;
454 } else {
455 in_constructor = true;
457 c.body.emit (this);
458 in_static_or_class_context = false;
460 in_constructor = false;
462 var cl = (Class) c.parent_symbol;
464 if (c.binding == MemberBinding.INSTANCE) {
465 if (!cl.is_subtype_of (gobject_type)) {
466 Report.error (c.source_reference, "construct blocks require GLib.Object");
467 c.error = true;
468 return;
471 function = new CCodeFunction ("%s_constructor".printf (cl.get_lower_case_cname (null)), "GObject *");
472 function.modifiers = CCodeModifiers.STATIC;
474 function.add_parameter (new CCodeFormalParameter ("type", "GType"));
475 function.add_parameter (new CCodeFormalParameter ("n_construct_properties", "guint"));
476 function.add_parameter (new CCodeFormalParameter ("construct_properties", "GObjectConstructParam *"));
478 source_declarations.add_type_member_declaration (function.copy ());
481 var cblock = new CCodeBlock ();
482 var cdecl = new CCodeDeclaration ("GObject *");
483 cdecl.add_declarator (new CCodeVariableDeclarator ("obj"));
484 cblock.add_statement (cdecl);
486 cdecl = new CCodeDeclaration ("GObjectClass *");
487 cdecl.add_declarator (new CCodeVariableDeclarator ("parent_class"));
488 cblock.add_statement (cdecl);
491 var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
492 ccast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (cl.get_lower_case_cname (null))));
493 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("parent_class"), ccast)));
496 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier ("parent_class"), "constructor"));
497 ccall.add_argument (new CCodeIdentifier ("type"));
498 ccall.add_argument (new CCodeIdentifier ("n_construct_properties"));
499 ccall.add_argument (new CCodeIdentifier ("construct_properties"));
500 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("obj"), ccall)));
503 ccall = generate_instance_cast (new CCodeIdentifier ("obj"), cl);
505 cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
506 cdecl.add_declarator (new CCodeVariableDeclarator ("self", ccall));
507 cblock.add_statement (cdecl);
509 if (current_method_inner_error) {
510 /* always separate error parameter and inner_error local variable
511 * as error may be set to NULL but we're always interested in inner errors
513 cdecl = new CCodeDeclaration ("GError *");
514 cdecl.add_declarator (new CCodeVariableDeclarator ("_inner_error_", new CCodeConstant ("NULL")));
515 cblock.add_statement (cdecl);
519 cblock.add_statement (c.body.ccodenode);
521 cblock.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("obj")));
523 function.block = cblock;
525 source_type_member_definition.append (function);
526 } else if (c.binding == MemberBinding.CLASS) {
527 // class constructor
529 if (cl.is_compact) {
530 Report.error (c.source_reference, "class constructors are not supported in compact classes");
531 c.error = true;
532 return;
535 if (current_method_inner_error) {
536 /* always separate error parameter and inner_error local variable
537 * as error may be set to NULL but we're always interested in inner errors
539 var cdecl = new CCodeDeclaration ("GError *");
540 cdecl.add_declarator (new CCodeVariableDeclarator ("_inner_error_", new CCodeConstant ("NULL")));
541 base_init_fragment.append (cdecl);
544 base_init_fragment.append (c.body.ccodenode);
545 } else if (c.binding == MemberBinding.STATIC) {
546 // static class constructor
547 // add to class_init
549 if (cl.is_compact) {
550 Report.error (c.source_reference, "static constructors are not supported in compact classes");
551 c.error = true;
552 return;
555 if (current_method_inner_error) {
556 /* always separate error parameter and inner_error local variable
557 * as error may be set to NULL but we're always interested in inner errors
559 var cdecl = new CCodeDeclaration ("GError *");
560 cdecl.add_declarator (new CCodeVariableDeclarator ("_inner_error_", new CCodeConstant ("NULL")));
561 class_init_fragment.append (cdecl);
564 class_init_fragment.append (c.body.ccodenode);
565 } else {
566 Report.error (c.source_reference, "internal error: constructors must have instance, class, or static binding");
569 current_method_inner_error = old_method_inner_error;
572 public override string get_dynamic_property_getter_cname (DynamicProperty prop) {
573 if (prop.dynamic_type.data_type == null
574 || !prop.dynamic_type.data_type.is_subtype_of (gobject_type)) {
575 return base.get_dynamic_property_getter_cname (prop);
578 string getter_cname = "_dynamic_get_%s%d".printf (prop.name, dynamic_property_id++);
580 var func = new CCodeFunction (getter_cname, prop.property_type.get_cname ());
581 func.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.INLINE;
583 func.add_parameter (new CCodeFormalParameter ("obj", prop.dynamic_type.get_cname ()));
585 var block = new CCodeBlock ();
586 generate_gobject_property_getter_wrapper (prop, block);
588 // append to C source file
589 source_declarations.add_type_member_declaration (func.copy ());
591 func.block = block;
592 source_type_member_definition.append (func);
594 return getter_cname;
597 public override string get_dynamic_property_setter_cname (DynamicProperty prop) {
598 if (prop.dynamic_type.data_type == null
599 || !prop.dynamic_type.data_type.is_subtype_of (gobject_type)) {
600 return base.get_dynamic_property_setter_cname (prop);
603 string setter_cname = "_dynamic_set_%s%d".printf (prop.name, dynamic_property_id++);
605 var func = new CCodeFunction (setter_cname, "void");
606 func.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.INLINE;
608 func.add_parameter (new CCodeFormalParameter ("obj", prop.dynamic_type.get_cname ()));
609 func.add_parameter (new CCodeFormalParameter ("value", prop.property_type.get_cname ()));
611 var block = new CCodeBlock ();
612 generate_gobject_property_setter_wrapper (prop, block);
614 // append to C source file
615 source_declarations.add_type_member_declaration (func.copy ());
617 func.block = block;
618 source_type_member_definition.append (func);
620 return setter_cname;
623 void generate_gobject_property_getter_wrapper (DynamicProperty node, CCodeBlock block) {
624 var cdecl = new CCodeDeclaration (node.property_type.get_cname ());
625 cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
626 block.add_statement (cdecl);
628 var call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
629 call.add_argument (new CCodeIdentifier ("obj"));
630 call.add_argument (node.get_canonical_cconstant ());
631 call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
632 call.add_argument (new CCodeConstant ("NULL"));
634 block.add_statement (new CCodeExpressionStatement (call));
636 block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
639 void generate_gobject_property_setter_wrapper (DynamicProperty node, CCodeBlock block) {
640 var call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_set"));
641 call.add_argument (new CCodeIdentifier ("obj"));
642 call.add_argument (node.get_canonical_cconstant ());
643 call.add_argument (new CCodeIdentifier ("value"));
644 call.add_argument (new CCodeConstant ("NULL"));
646 block.add_statement (new CCodeExpressionStatement (call));
649 public override string get_dynamic_signal_cname (DynamicSignal node) {
650 return "dynamic_%s%d_".printf (node.name, signal_wrapper_id++);
653 public override string get_dynamic_signal_connect_wrapper_name (DynamicSignal sig) {
654 if (sig.dynamic_type.data_type == null
655 || !sig.dynamic_type.data_type.is_subtype_of (gobject_type)) {
656 return base.get_dynamic_signal_connect_wrapper_name (sig);
659 string connect_wrapper_name = "_%sconnect".printf (get_dynamic_signal_cname (sig));
660 var func = new CCodeFunction (connect_wrapper_name, "void");
661 func.add_parameter (new CCodeFormalParameter ("obj", "gpointer"));
662 func.add_parameter (new CCodeFormalParameter ("signal_name", "const char *"));
663 func.add_parameter (new CCodeFormalParameter ("handler", "GCallback"));
664 func.add_parameter (new CCodeFormalParameter ("data", "gpointer"));
665 var block = new CCodeBlock ();
666 generate_gobject_connect_wrapper (sig, block, false);
668 // append to C source file
669 source_declarations.add_type_member_declaration (func.copy ());
671 func.block = block;
672 source_type_member_definition.append (func);
674 return connect_wrapper_name;
677 public override string get_dynamic_signal_connect_after_wrapper_name (DynamicSignal sig) {
678 if (sig.dynamic_type.data_type == null
679 || !sig.dynamic_type.data_type.is_subtype_of (gobject_type)) {
680 return base.get_dynamic_signal_connect_wrapper_name (sig);
683 string connect_wrapper_name = "_%sconnect_after".printf (get_dynamic_signal_cname (sig));
684 var func = new CCodeFunction (connect_wrapper_name, "void");
685 func.add_parameter (new CCodeFormalParameter ("obj", "gpointer"));
686 func.add_parameter (new CCodeFormalParameter ("signal_name", "const char *"));
687 func.add_parameter (new CCodeFormalParameter ("handler", "GCallback"));
688 func.add_parameter (new CCodeFormalParameter ("data", "gpointer"));
689 var block = new CCodeBlock ();
690 generate_gobject_connect_wrapper (sig, block, true);
692 // append to C source file
693 source_declarations.add_type_member_declaration (func.copy ());
695 func.block = block;
696 source_type_member_definition.append (func);
698 return connect_wrapper_name;
701 void generate_gobject_connect_wrapper (DynamicSignal sig, CCodeBlock block, bool after) {
702 var m = (Method) sig.handler.symbol_reference;
704 sig.accept (this);
706 string connect_func = "g_signal_connect_object";
707 if (m.binding != MemberBinding.INSTANCE) {
708 if (!after)
709 connect_func = "g_signal_connect";
710 else
711 connect_func = "g_signal_connect_after";
714 var call = new CCodeFunctionCall (new CCodeIdentifier (connect_func));
715 call.add_argument (new CCodeIdentifier ("obj"));
716 call.add_argument (new CCodeIdentifier ("signal_name"));
717 call.add_argument (new CCodeIdentifier ("handler"));
718 call.add_argument (new CCodeIdentifier ("data"));
720 if (m.binding == MemberBinding.INSTANCE) {
721 if (!after)
722 call.add_argument (new CCodeConstant ("0"));
723 else
724 call.add_argument (new CCodeConstant ("G_CONNECT_AFTER"));
727 block.add_statement (new CCodeExpressionStatement (call));
730 public override void visit_property (Property prop) {
731 base.visit_property (prop);
733 if (is_gobject_property (prop) && prop.parent_symbol is Class) {
734 prop_enum.add_value (new CCodeEnumValue (prop.get_upper_case_cname ()));
738 public override bool is_gobject_property (Property prop) {
739 var type_sym = prop.parent_symbol as ObjectTypeSymbol;
740 if (type_sym == null || !type_sym.is_subtype_of (gobject_type)) {
741 return false;
744 if (prop.binding != MemberBinding.INSTANCE) {
745 return false;
748 if (prop.access == SymbolAccessibility.PRIVATE) {
749 return false;
752 var st = prop.property_type.data_type as Struct;
753 if (st != null && (!st.has_type_id || prop.property_type.nullable)) {
754 return false;
757 if (prop.property_type is ArrayType && ((ArrayType)prop.property_type).element_type.data_type != string_type.data_type) {
758 return false;
761 var d = prop.property_type as DelegateType;
762 if (d != null && d.delegate_symbol.has_target) {
763 return false;
766 if (prop.base_interface_property != null) {
767 var iface = (Interface) prop.base_interface_property.parent_symbol;
768 if (!iface.is_subtype_of (gobject_type)) {
769 // implementing non-GObject property
770 return false;
774 if (!prop.name[0].isalpha ()) {
775 // GObject requires properties to start with a letter
776 return false;
779 return true;
782 public override void visit_method_call (MethodCall expr) {
783 if (expr.call is MemberAccess) {
784 var ma = expr.call as MemberAccess;
785 if (ma.inner != null && ma.inner.symbol_reference == gobject_type &&
786 (ma.member_name == "new" || ma.member_name == "newv")) {
787 // Object.new (...) creation
788 // runtime check to ref_sink the instance if it's a floating type
789 base.visit_method_call (expr);
791 var ccomma = new CCodeCommaExpression ();
792 var temp_var = get_temp_variable (expr.value_type, false, expr, false);
793 temp_vars.add (temp_var);
794 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), (CCodeExpression) expr.ccodenode));
796 var initiallyunowned_ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_INITIALLY_UNOWNED"));
797 initiallyunowned_ccall.add_argument (get_variable_cexpression (temp_var.name));
798 var sink_ref_ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref_sink"));
799 sink_ref_ccall.add_argument (get_variable_cexpression (temp_var.name));
800 ccomma.append_expression (new CCodeConditionalExpression (initiallyunowned_ccall, sink_ref_ccall, get_variable_cexpression (temp_var.name)));
802 expr.ccodenode = ccomma;
803 return;
804 } else if (ma.symbol_reference == gobject_type) {
805 // Object (...) chain up
806 // check it's only used with valid properties
807 foreach (var arg in expr.get_argument_list ()) {
808 var named_argument = arg as NamedArgument;
809 if (named_argument == null) {
810 Report.error (arg.source_reference, "Named argument expected");
811 break;
813 var prop = SemanticAnalyzer.symbol_lookup_inherited (current_class, named_argument.name) as Property;
814 if (prop == null) {
815 Report.error (arg.source_reference, "Property `%s' not found in `%s'".printf (named_argument.name, current_class.get_full_name ()));
816 break;
818 if (!arg.value_type.compatible (prop.property_type)) {
819 Report.error (arg.source_reference, "Cannot convert from `%s' to `%s'".printf (arg.value_type.to_string (), prop.property_type.to_string ()));
820 break;
826 base.visit_method_call (expr);