D-Bus: Remove extra semicolon to avoid C warning
[vala-lang.git] / vala / valastruct.vala
blobc94bc0f4a5e3a064d857fab1b164f468820a010b
1 /* valastruct.vala
3 * Copyright (C) 2006-2010 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
25 /**
26 * Represents a struct declaration in the source code.
28 public class Vala.Struct : TypeSymbol {
29 private List<TypeParameter> type_parameters = new ArrayList<TypeParameter> ();
30 private List<Constant> constants = new ArrayList<Constant> ();
31 private List<Field> fields = new ArrayList<Field> ();
32 private List<Method> methods = new ArrayList<Method> ();
33 private List<Property> properties = new ArrayList<Property> ();
34 private DataType _base_type = null;
36 private string cname;
37 private string const_cname;
38 private string type_id;
39 private string lower_case_cprefix;
40 private string lower_case_csuffix;
41 private bool boolean_type;
42 private bool integer_type;
43 private bool floating_type;
44 private bool decimal_floating_type;
45 private int rank;
46 private string marshaller_type_name;
47 private string get_value_function;
48 private string set_value_function;
49 private string take_value_function;
50 private string default_value = null;
51 private string copy_function;
52 private string destroy_function;
54 /**
55 * Specifies the base type.
57 public DataType? base_type {
58 get {
59 return _base_type;
61 set {
62 value.parent_node = this;
63 _base_type = value;
67 /**
68 * Specifies the base Struct.
70 public Struct? base_struct {
71 get {
72 if (_base_type != null) {
73 return _base_type.data_type as Struct;
75 return null;
79 /**
80 * Specifies the default construction method.
82 public Method default_construction_method { get; set; }
84 /**
85 * Specifies if 'const' should be emitted for input parameters
86 * of this type.
88 public bool is_immutable { get; set; }
90 /**
91 * Specifies whether this struct has a registered GType.
93 public bool has_type_id { get; set; default = true; }
95 public int width { get; set; default = 32; }
97 public bool signed { get; set; default = true; }
99 public bool has_copy_function { get; set; default = true; }
101 public bool has_destroy_function { get; set; default = true; }
104 * Creates a new struct.
106 * @param name type name
107 * @param source_reference reference to source code
108 * @return newly created struct
110 public Struct (string name, SourceReference? source_reference = null, Comment? comment = null) {
111 base (name, source_reference, comment);
115 * Appends the specified parameter to the list of type parameters.
117 * @param p a type parameter
119 public void add_type_parameter (TypeParameter p) {
120 type_parameters.add (p);
121 scope.add (p.name, p);
125 * Returns a copy of the type parameter list.
127 * @return list of type parameters
129 public List<TypeParameter> get_type_parameters () {
130 return type_parameters;
134 * Adds the specified constant as a member to this struct.
136 * @param c a constant
138 public override void add_constant (Constant c) {
139 constants.add (c);
140 scope.add (c.name, c);
144 * Adds the specified field as a member to this struct.
146 * @param f a field
148 public override void add_field (Field f) {
149 // TODO report error when `private' or `protected' has been specified
150 f.access = SymbolAccessibility.PUBLIC;
152 fields.add (f);
153 scope.add (f.name, f);
157 * Returns a copy of the list of fields.
159 * @return list of fields
161 public List<Field> get_fields () {
162 return fields;
166 * Returns a copy of the list of constants.
168 * @return list of constants
170 public List<Constant> get_constants () {
171 return constants;
175 * Adds the specified method as a member to this struct.
177 * @param m a method
179 public override void add_method (Method m) {
180 return_if_fail (m != null);
182 if (m.binding == MemberBinding.INSTANCE || m is CreationMethod) {
183 m.this_parameter = new Parameter ("this", SemanticAnalyzer.get_data_type_for_symbol (this));
184 m.scope.add (m.this_parameter.name, m.this_parameter);
186 if (!(m.return_type is VoidType) && (CodeContext.get ().profile == Profile.DOVA || m.get_postconditions ().size > 0)) {
187 m.result_var = new LocalVariable (m.return_type.copy (), "result", null, source_reference);
188 m.result_var.is_result = true;
190 if (m is CreationMethod) {
191 if (m.name == null) {
192 default_construction_method = m;
193 m.name = ".new";
196 var cm = (CreationMethod) m;
197 if (cm.class_name != null && cm.class_name != name) {
198 // type_name is null for constructors generated by GIdlParser
199 Report.error (m.source_reference, "missing return type in method `%s.%s´".printf (get_full_name (), cm.class_name));
200 m.error = true;
201 return;
205 methods.add (m);
206 scope.add (m.name, m);
210 * Returns a copy of the list of methods.
212 * @return list of methods
214 public List<Method> get_methods () {
215 return methods;
219 * Adds the specified property as a member to this struct.
221 * @param prop a property
223 public override void add_property (Property prop) {
224 properties.add (prop);
225 scope.add (prop.name, prop);
227 prop.this_parameter = new Parameter ("this", SemanticAnalyzer.get_data_type_for_symbol (this));
228 prop.scope.add (prop.this_parameter.name, prop.this_parameter);
230 if (prop.field != null) {
231 add_field (prop.field);
236 * Returns a copy of the list of properties.
238 * @return list of properties
240 public List<Property> get_properties () {
241 return properties;
244 public override void accept (CodeVisitor visitor) {
245 visitor.visit_struct (this);
248 public override void accept_children (CodeVisitor visitor) {
249 if (base_type != null) {
250 base_type.accept (visitor);
253 foreach (TypeParameter p in type_parameters) {
254 p.accept (visitor);
257 foreach (Field f in fields) {
258 f.accept (visitor);
261 foreach (Constant c in constants) {
262 c.accept (visitor);
265 foreach (Method m in methods) {
266 m.accept (visitor);
269 foreach (Property prop in properties) {
270 prop.accept (visitor);
274 public override string get_cname (bool const_type = false) {
275 if (const_type && const_cname != null) {
276 return const_cname;
279 if (cname == null) {
280 var attr = get_attribute ("CCode");
281 if (attr != null) {
282 cname = attr.get_string ("cname");
284 if (cname == null) {
285 cname = get_default_cname ();
288 return cname;
291 public void set_cname (string cname) {
292 this.cname = cname;
296 * Returns the default name of this struct as it is used in C code.
298 * @return the name to be used in C code by default
300 public string get_default_cname () {
301 // parent_symbol may be null in GIR parser
302 if (parent_symbol != null) {
303 return "%s%s".printf (parent_symbol.get_cprefix (), name);
304 } else {
305 return name;
309 private void set_const_cname (string cname) {
310 this.const_cname = cname;
313 public override string get_lower_case_cprefix () {
314 if (lower_case_cprefix == null) {
315 lower_case_cprefix = "%s_".printf (get_lower_case_cname (null));
317 return lower_case_cprefix;
320 private string get_lower_case_csuffix () {
321 if (lower_case_csuffix == null) {
322 lower_case_csuffix = camel_case_to_lower_case (name);
324 return lower_case_csuffix;
327 public override string? get_lower_case_cname (string? infix) {
328 if (infix == null) {
329 infix = "";
331 return "%s%s%s".printf (parent_symbol.get_lower_case_cprefix (), infix, get_lower_case_csuffix ());
334 public override string? get_upper_case_cname (string? infix) {
335 return get_lower_case_cname (infix).up ();
339 * Returns whether this is a boolean type.
341 * @return true if this is a boolean type, false otherwise
343 public bool is_boolean_type () {
344 if (base_type != null) {
345 var st = base_struct;
346 if (st != null && st.is_boolean_type ()) {
347 return true;
350 return boolean_type;
354 * Returns whether this is an integer type.
356 * @return true if this is an integer type, false otherwise
358 public bool is_integer_type () {
359 if (base_type != null) {
360 var st = base_struct;
361 if (st != null && st.is_integer_type ()) {
362 return true;
365 return integer_type;
369 * Returns whether this is a floating point type.
371 * @return true if this is a floating point type, false otherwise
373 public bool is_floating_type () {
374 if (base_type != null) {
375 var st = base_struct;
376 if (st != null && st.is_floating_type ()) {
377 return true;
380 return floating_type;
383 public bool is_decimal_floating_type () {
384 if (base_type != null) {
385 var st = base_struct;
386 if (st != null && st.is_decimal_floating_type ()) {
387 return true;
390 return decimal_floating_type;
394 * Returns the rank of this integer or floating point type.
396 * @return the rank if this is an integer or floating point type
398 public int get_rank () {
399 return rank;
403 * Sets the rank of this integer or floating point type.
405 * @return the rank if this is an integer or floating point type
407 public void set_rank (int rank) {
408 this.rank = rank;
411 private void process_gir_attribute (Attribute a) {
412 if (a.has_argument ("name")) {
413 gir_name = a.get_string ("name");
417 private void process_ccode_attribute (Attribute a) {
418 if (a.has_argument ("const_cname")) {
419 set_const_cname (a.get_string ("const_cname"));
421 if (a.has_argument ("cprefix")) {
422 lower_case_cprefix = a.get_string ("cprefix");
424 if (a.has_argument ("cheader_filename")) {
425 var val = a.get_string ("cheader_filename");
426 foreach (string filename in val.split (",")) {
427 add_cheader_filename (filename);
430 if (a.has_argument ("has_type_id")) {
431 has_type_id = a.get_bool ("has_type_id");
433 if (a.has_argument ("type_id")) {
434 set_type_id (a.get_string ("type_id"));
436 if (a.has_argument ("marshaller_type_name")) {
437 set_marshaller_type_name (a.get_string ("marshaller_type_name"));
439 if (a.has_argument ("get_value_function")) {
440 set_get_value_function (a.get_string ("get_value_function"));
442 if (a.has_argument ("set_value_function")) {
443 set_set_value_function (a.get_string ("set_value_function"));
445 if (a.has_argument ("take_value_function")) {
446 set_take_value_function (a.get_string ("take_value_function"));
448 if (a.has_argument ("default_value")) {
449 set_default_value (a.get_string ("default_value"));
451 if (a.has_argument ("copy_function")) {
452 set_copy_function (a.get_string ("copy_function"));
454 if (a.has_argument ("has_copy_function")) {
455 has_copy_function = a.get_bool ("has_copy_function");
457 if (a.has_argument ("destroy_function")) {
458 set_destroy_function (a.get_string ("destroy_function"));
460 if (a.has_argument ("has_destroy_function")) {
461 has_destroy_function = a.get_bool ("has_destroy_function");
465 private void process_boolean_type_attribute (Attribute a) {
466 boolean_type = true;
469 private void process_integer_type_attribute (Attribute a) {
470 integer_type = true;
471 if (a.has_argument ("rank")) {
472 rank = a.get_integer ("rank");
474 if (a.has_argument ("width")) {
475 width = a.get_integer ("width");
477 if (a.has_argument ("signed")) {
478 signed = a.get_bool ("signed");
482 private void process_floating_type_attribute (Attribute a) {
483 floating_type = true;
484 if (a.has_argument ("rank")) {
485 rank = a.get_integer ("rank");
487 if (a.has_argument ("decimal")) {
488 decimal_floating_type = a.get_bool ("decimal");
490 if (a.has_argument ("width")) {
491 width = a.get_integer ("width");
496 * Process all associated attributes.
498 public void process_attributes () {
499 foreach (Attribute a in attributes) {
500 if (a.name == "CCode") {
501 process_ccode_attribute (a);
502 } else if (a.name == "BooleanType") {
503 process_boolean_type_attribute (a);
504 } else if (a.name == "IntegerType") {
505 process_integer_type_attribute (a);
506 } else if (a.name == "FloatingType") {
507 process_floating_type_attribute (a);
508 } else if (a.name == "Immutable") {
509 is_immutable = true;
510 } else if (a.name == "Deprecated") {
511 process_deprecated_attribute (a);
512 } else if (a.name == "GIR") {
513 process_gir_attribute (a);
514 } else if (a.name == "Experimental") {
515 process_experimental_attribute (a);
520 public override string? get_type_id () {
521 if (type_id == null) {
522 if (!has_type_id) {
523 if (base_type != null) {
524 var st = base_struct;
525 if (st != null) {
526 return st.get_type_id ();
529 if (is_simple_type ()) {
530 return null;
531 } else {
532 return "G_TYPE_POINTER";
534 } else {
535 type_id = get_upper_case_cname ("TYPE_");
538 return type_id;
541 public void set_type_id (string? name) {
542 this.type_id = name;
545 public override string? get_marshaller_type_name () {
546 if (marshaller_type_name == null) {
547 if (base_type != null) {
548 var st = base_struct;
549 if (st != null) {
550 return st.get_marshaller_type_name ();
553 if (is_simple_type ()) {
554 Report.error (source_reference, "The type `%s` doesn't declare a marshaller type name".printf (get_full_name ()));
555 // set marshaller_type_name to avoid multiple errors
556 marshaller_type_name = "";
557 return "";
558 } else if (has_type_id) {
559 return "BOXED";
560 } else {
561 return "POINTER";
564 return marshaller_type_name;
567 private void set_marshaller_type_name (string? name) {
568 this.marshaller_type_name = name;
571 public override string? get_get_value_function () {
572 if (get_value_function == null) {
573 if (base_type != null) {
574 var st = base_struct;
575 if (st != null) {
576 return st.get_get_value_function ();
579 if (is_simple_type ()) {
580 Report.error (source_reference, "The value type `%s` doesn't declare a GValue get function".printf (get_full_name ()));
581 // set get_value_function to avoid multiple errors
582 get_value_function = "";
583 return "";
584 } else if (has_type_id) {
585 return "g_value_get_boxed";
586 } else {
587 return "g_value_get_pointer";
589 } else {
590 return get_value_function;
594 public override string? get_set_value_function () {
595 if (set_value_function == null) {
596 if (base_type != null) {
597 var st = base_struct;
598 if (st != null) {
599 return st.get_set_value_function ();
602 if (is_simple_type ()) {
603 Report.error (source_reference, "The value type `%s` doesn't declare a GValue set function".printf (get_full_name ()));
604 // set set_value_function to avoid multiple errors
605 set_value_function = "";
606 return "";
607 } else if (has_type_id) {
608 return "g_value_set_boxed";
609 } else {
610 return "g_value_set_pointer";
612 } else {
613 return set_value_function;
617 public override string? get_take_value_function () {
618 if (take_value_function == null) {
619 if (base_type != null) {
620 var st = base_struct;
621 if (st != null) {
622 return st.get_take_value_function ();
625 if (is_simple_type ()) {
626 Report.error (source_reference, "The value type `%s` doesn't declare a GValue take function".printf (get_full_name ()));
627 // set take_value_function to avoid multiple errors
628 take_value_function = "";
629 return "";
630 } else if (has_type_id) {
631 return "g_value_take_boxed";
632 } else {
633 return "g_value_take_pointer";
635 } else {
636 return take_value_function;
640 private void set_get_value_function (string? function) {
641 get_value_function = function;
644 private void set_set_value_function (string? function) {
645 set_value_function = function;
648 private void set_take_value_function (string? function) {
649 take_value_function = function;
652 public override string? get_default_value () {
653 if (default_value != null) {
654 return default_value;
657 // inherit default value from base type
658 if (base_type != null) {
659 var st = base_struct;
660 if (st != null) {
661 return st.get_default_value ();
665 if (CodeContext.get ().profile == Profile.DOVA) {
666 if (boolean_type) {
667 return "false";
668 } else if (integer_type || floating_type) {
669 return "0";
673 return null;
676 private void set_default_value (string? value) {
677 default_value = value;
680 public override int get_type_parameter_index (string name) {
681 int i = 0;
683 foreach (TypeParameter p in type_parameters) {
684 if (p.name == name) {
685 return (i);
687 i++;
690 return -1;
694 * Returns whether this struct is a simple type, i.e. whether
695 * instances are passed by value.
697 public bool is_simple_type () {
698 if (base_type != null) {
699 var st = base_struct;
700 if (st != null && st.is_simple_type ()) {
701 return true;
704 if (get_attribute ("ByRef") != null) {
705 // used by time_t
706 return false;
708 if (CodeContext.get ().profile == Profile.DOVA) {
709 return true;
711 return (boolean_type || integer_type || floating_type
712 || get_attribute ("SimpleType") != null);
716 * Marks this struct as simple type, i.e. instances will be passed by
717 * value.
719 public void set_simple_type (bool simple_type) {
720 attributes.append (new Attribute ("SimpleType"));
723 public override void replace_type (DataType old_type, DataType new_type) {
724 if (base_type == old_type) {
725 base_type = new_type;
729 public override bool is_subtype_of (TypeSymbol t) {
730 if (this == t) {
731 return true;
734 if (base_type != null) {
735 if (base_type.data_type != null && base_type.data_type.is_subtype_of (t)) {
736 return true;
740 return false;
743 public override string? get_dup_function () {
744 // TODO use attribute check instead
745 if (external_package) {
746 return null;
747 } else {
748 return get_lower_case_cprefix () + "dup";
752 public override string? get_free_function () {
753 // TODO use attribute check instead
754 if (external_package) {
755 return null;
756 } else {
757 return get_lower_case_cprefix () + "free";
761 public string get_default_copy_function () {
762 return get_lower_case_cprefix () + "copy";
765 public override string? get_copy_function () {
766 if (copy_function == null) {
767 copy_function = get_default_copy_function ();
769 return copy_function;
772 public void set_copy_function (string name) {
773 this.copy_function = name;
776 public string get_default_destroy_function () {
777 return get_lower_case_cprefix () + "destroy";
780 public override string? get_destroy_function () {
781 if (destroy_function == null) {
782 destroy_function = get_default_destroy_function ();
784 return destroy_function;
787 public void set_destroy_function (string name) {
788 this.destroy_function = name;
791 public bool is_disposable () {
792 if (destroy_function != null) {
793 return true;
796 foreach (Field f in fields) {
797 if (f.binding == MemberBinding.INSTANCE
798 && f.variable_type.is_disposable ()) {
799 return true;
803 return false;
806 bool is_recursive_value_type (DataType type) {
807 var struct_type = type as StructValueType;
808 if (struct_type != null && !struct_type.nullable) {
809 var st = (Struct) struct_type.type_symbol;
810 if (st == this) {
811 return true;
813 foreach (Field f in st.fields) {
814 if (f.binding == MemberBinding.INSTANCE && is_recursive_value_type (f.variable_type)) {
815 return true;
819 return false;
822 public override bool check (CodeContext context) {
823 if (checked) {
824 return !error;
827 checked = true;
829 process_attributes ();
831 var old_source_file = context.analyzer.current_source_file;
832 var old_symbol = context.analyzer.current_symbol;
834 if (source_reference != null) {
835 context.analyzer.current_source_file = source_reference.file;
837 context.analyzer.current_symbol = this;
839 if (base_type != null) {
840 base_type.check (context);
842 if (!(base_type is ValueType)) {
843 error = true;
844 Report.error (source_reference, "The base type `%s` of struct `%s` is not a struct".printf (base_type.to_string (), get_full_name ()));
845 return false;
849 foreach (TypeParameter p in type_parameters) {
850 p.check (context);
853 foreach (Field f in fields) {
854 f.check (context);
856 if (f.binding == MemberBinding.INSTANCE && is_recursive_value_type (f.variable_type)) {
857 error = true;
858 Report.error (f.source_reference, "Recursive value types are not allowed");
859 return false;
862 if (f.binding == MemberBinding.INSTANCE && f.initializer != null) {
863 error = true;
864 Report.error (f.source_reference, "Instance field initializers not supported");
865 return false;
869 foreach (Constant c in constants) {
870 c.check (context);
873 foreach (Method m in methods) {
874 m.check (context);
877 foreach (Property prop in properties) {
878 prop.check (context);
881 if (!external && !external_package) {
882 if (base_type == null && get_fields ().size == 0 && !is_boolean_type () && !is_integer_type () && !is_floating_type ()) {
883 error = true;
884 Report.error (source_reference, "structs cannot be empty: %s".printf(name));
885 } else if (base_type != null) {
886 foreach (Field f in fields) {
887 if (f.binding == MemberBinding.INSTANCE) {
888 error = true;
889 Report.error (source_reference, "derived structs may not have instance fields");
890 break;
896 context.analyzer.current_source_file = old_source_file;
897 context.analyzer.current_symbol = old_symbol;
899 return !error;
903 // vim:sw=8 noet