vapigen: Support owned_get metadata attribute for properties
[vala-lang.git] / vala / valastruct.vala
blob26763228747f17dd11c2d09712df3ceec775086f
1 /* valastruct.vala
3 * Copyright (C) 2006-2009 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
24 using Gee;
26 /**
27 * Represents a struct declaration in the source code.
29 public class Vala.Struct : TypeSymbol {
30 private Gee.List<TypeParameter> type_parameters = new ArrayList<TypeParameter> ();
31 private Gee.List<Constant> constants = new ArrayList<Constant> ();
32 private Gee.List<Field> fields = new ArrayList<Field> ();
33 private Gee.List<Method> methods = new ArrayList<Method> ();
34 private Gee.List<Property> properties = new ArrayList<Property> ();
35 private DataType _base_type = null;
37 private string cname;
38 private string const_cname;
39 private string type_id;
40 private string lower_case_cprefix;
41 private string lower_case_csuffix;
42 private bool boolean_type;
43 private bool integer_type;
44 private bool 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 default_value = null;
50 private string? type_signature;
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 use_const { get; set; default = true; }
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 Gee.List<TypeParameter> get_type_parameters () {
130 return new ReadOnlyList<TypeParameter> (type_parameters);
134 * Adds the specified constant as a member to this struct.
136 * @param c a constant
138 public 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 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 Gee.List<Field> get_fields () {
162 return new ReadOnlyList<Field> (fields);
166 * Returns a copy of the list of constants.
168 * @return list of constants
170 public Gee.List<Constant> get_constants () {
171 return new ReadOnlyList<Constant> (constants);
175 * Adds the specified method as a member to this struct.
177 * @param m a method
179 public 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 FormalParameter ("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) && m.get_postconditions ().size > 0) {
187 m.result_var = new LocalVariable (m.return_type.copy (), "result");
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 Gee.List<Method> get_methods () {
215 return new ReadOnlyList<Method> (methods);
219 * Adds the specified property as a member to this struct.
221 * @param prop a property
223 public void add_property (Property prop) {
224 properties.add (prop);
225 scope.add (prop.name, prop);
227 prop.this_parameter = new FormalParameter ("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 Gee.List<Property> get_properties () {
241 return new ReadOnlyList<Property> (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 return "%s%s".printf (parent_symbol.get_cprefix (), name);
304 private void set_const_cname (string cname) {
305 this.const_cname = cname;
308 public override string get_lower_case_cprefix () {
309 if (lower_case_cprefix == null) {
310 lower_case_cprefix = "%s_".printf (get_lower_case_cname (null));
312 return lower_case_cprefix;
315 private string get_lower_case_csuffix () {
316 if (lower_case_csuffix == null) {
317 lower_case_csuffix = camel_case_to_lower_case (name);
319 return lower_case_csuffix;
322 public override string? get_lower_case_cname (string? infix) {
323 if (infix == null) {
324 infix = "";
326 return "%s%s%s".printf (parent_symbol.get_lower_case_cprefix (), infix, get_lower_case_csuffix ());
329 public override string? get_upper_case_cname (string? infix) {
330 return get_lower_case_cname (infix).up ();
333 public override string? get_type_signature () {
334 if (type_signature == null) {
335 var str = new StringBuilder ();
336 str.append_c ('(');
337 foreach (Field f in fields) {
338 if (f.binding == MemberBinding.INSTANCE) {
339 str.append (f.field_type.get_type_signature ());
342 str.append_c (')');
343 return str.str;
345 return type_signature;
349 * Returns whether this is a boolean type.
351 * @return true if this is a boolean type, false otherwise
353 public bool is_boolean_type () {
354 if (base_type != null) {
355 var st = base_struct;
356 if (st != null && st.is_boolean_type ()) {
357 return true;
360 return boolean_type;
364 * Returns whether this is an integer type.
366 * @return true if this is an integer type, false otherwise
368 public bool is_integer_type () {
369 if (base_type != null) {
370 var st = base_struct;
371 if (st != null && st.is_integer_type ()) {
372 return true;
375 return integer_type;
379 * Returns whether this is a floating point type.
381 * @return true if this is a floating point type, false otherwise
383 public bool is_floating_type () {
384 if (base_type != null) {
385 var st = base_struct;
386 if (st != null && st.is_floating_type ()) {
387 return true;
390 return 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;
402 private void process_ccode_attribute (Attribute a) {
403 if (a.has_argument ("const_cname")) {
404 set_const_cname (a.get_string ("const_cname"));
406 if (a.has_argument ("cprefix")) {
407 lower_case_cprefix = a.get_string ("cprefix");
409 if (a.has_argument ("cheader_filename")) {
410 var val = a.get_string ("cheader_filename");
411 foreach (string filename in val.split (",")) {
412 add_cheader_filename (filename);
415 if (a.has_argument ("has_type_id")) {
416 has_type_id = a.get_bool ("has_type_id");
418 if (a.has_argument ("type_id")) {
419 set_type_id (a.get_string ("type_id"));
421 if (a.has_argument ("marshaller_type_name")) {
422 set_marshaller_type_name (a.get_string ("marshaller_type_name"));
424 if (a.has_argument ("get_value_function")) {
425 set_get_value_function (a.get_string ("get_value_function"));
427 if (a.has_argument ("set_value_function")) {
428 set_set_value_function (a.get_string ("set_value_function"));
430 if (a.has_argument ("default_value")) {
431 set_default_value (a.get_string ("default_value"));
433 if (a.has_argument ("type_signature")) {
434 type_signature = a.get_string ("type_signature");
436 if (a.has_argument ("copy_function")) {
437 set_copy_function (a.get_string ("copy_function"));
439 if (a.has_argument ("has_copy_function")) {
440 has_copy_function = a.get_bool ("has_copy_function");
442 if (a.has_argument ("destroy_function")) {
443 set_destroy_function (a.get_string ("destroy_function"));
445 if (a.has_argument ("has_destroy_function")) {
446 has_destroy_function = a.get_bool ("has_destroy_function");
448 if (a.has_argument ("use_const")) {
449 use_const = a.get_bool ("use_const");
453 private void process_boolean_type_attribute (Attribute a) {
454 boolean_type = true;
457 private void process_integer_type_attribute (Attribute a) {
458 integer_type = true;
459 if (a.has_argument ("rank")) {
460 rank = a.get_integer ("rank");
462 if (a.has_argument ("width")) {
463 width = a.get_integer ("width");
465 if (a.has_argument ("signed")) {
466 signed = a.get_bool ("signed");
470 private void process_floating_type_attribute (Attribute a) {
471 floating_type = true;
472 if (a.has_argument ("rank")) {
473 rank = a.get_integer ("rank");
475 if (a.has_argument ("width")) {
476 width = a.get_integer ("width");
481 * Process all associated attributes.
483 public void process_attributes () {
484 foreach (Attribute a in attributes) {
485 if (a.name == "CCode") {
486 process_ccode_attribute (a);
487 } else if (a.name == "BooleanType") {
488 process_boolean_type_attribute (a);
489 } else if (a.name == "IntegerType") {
490 process_integer_type_attribute (a);
491 } else if (a.name == "FloatingType") {
492 process_floating_type_attribute (a);
497 public override string? get_type_id () {
498 if (type_id == null) {
499 if (!has_type_id) {
500 if (base_type != null) {
501 var st = base_struct;
502 if (st != null) {
503 return st.get_type_id ();
506 if (is_simple_type ()) {
507 return null;
508 } else {
509 return "G_TYPE_POINTER";
511 } else {
512 type_id = get_upper_case_cname ("TYPE_");
515 return type_id;
518 public void set_type_id (string? name) {
519 this.type_id = name;
522 public override string? get_marshaller_type_name () {
523 if (marshaller_type_name == null) {
524 if (base_type != null) {
525 var st = base_struct;
526 if (st != null) {
527 return st.get_marshaller_type_name ();
530 if (is_simple_type ()) {
531 Report.error (source_reference, "The type `%s` doesn't declare a marshaller type name".printf (get_full_name ()));
532 } else if (has_type_id) {
533 return "BOXED";
534 } else {
535 return "POINTER";
538 return marshaller_type_name;
541 private void set_marshaller_type_name (string? name) {
542 this.marshaller_type_name = name;
545 public override string? get_get_value_function () {
546 if (get_value_function == null) {
547 if (base_type != null) {
548 var st = base_struct;
549 if (st != null) {
550 return st.get_get_value_function ();
553 if (is_simple_type ()) {
554 Report.error (source_reference, "The value type `%s` doesn't declare a GValue get function".printf (get_full_name ()));
555 return null;
556 } else if (has_type_id) {
557 return "g_value_get_boxed";
558 } else {
559 return "g_value_get_pointer";
561 } else {
562 return get_value_function;
566 public override string? get_set_value_function () {
567 if (set_value_function == null) {
568 if (base_type != null) {
569 var st = base_struct;
570 if (st != null) {
571 return st.get_set_value_function ();
574 if (is_simple_type ()) {
575 Report.error (source_reference, "The value type `%s` doesn't declare a GValue set function".printf (get_full_name ()));
576 return null;
577 } else if (has_type_id) {
578 return "g_value_set_boxed";
579 } else {
580 return "g_value_set_pointer";
582 } else {
583 return set_value_function;
587 private void set_get_value_function (string? function) {
588 get_value_function = function;
591 private void set_set_value_function (string? function) {
592 set_value_function = function;
595 public override string? get_default_value () {
596 if (default_value != null) {
597 return default_value;
600 // inherit default value from base type
601 if (base_type != null) {
602 var st = base_struct;
603 if (st != null) {
604 return st.get_default_value ();
607 return null;
610 private void set_default_value (string? value) {
611 default_value = value;
614 public override int get_type_parameter_index (string name) {
615 int i = 0;
617 foreach (TypeParameter p in type_parameters) {
618 if (p.name == name) {
619 return (i);
621 i++;
624 return -1;
628 * Returns whether this struct is a simple type, i.e. whether
629 * instances are passed by value.
631 public bool is_simple_type () {
632 if (base_type != null) {
633 var st = base_struct;
634 if (st != null && st.is_simple_type ()) {
635 return true;
638 if (get_attribute ("ByRef") != null) {
639 // used by time_t
640 return false;
642 return (boolean_type || integer_type || floating_type
643 || get_attribute ("SimpleType") != null);
647 * Marks this struct as simple type, i.e. instances will be passed by
648 * value.
650 public void set_simple_type (bool simple_type) {
651 attributes.append (new Attribute ("SimpleType"));
654 public override void replace_type (DataType old_type, DataType new_type) {
655 if (base_type == old_type) {
656 base_type = new_type;
660 public override bool is_subtype_of (TypeSymbol t) {
661 if (this == t) {
662 return true;
665 if (base_type != null) {
666 if (base_type.data_type != null && base_type.data_type.is_subtype_of (t)) {
667 return true;
671 return false;
674 public override string? get_dup_function () {
675 // TODO use attribute check instead
676 if (external_package) {
677 return null;
678 } else {
679 return get_lower_case_cprefix () + "dup";
683 public override string? get_free_function () {
684 // TODO use attribute check instead
685 if (external_package) {
686 return null;
687 } else {
688 return get_lower_case_cprefix () + "free";
692 public string get_default_copy_function () {
693 return get_lower_case_cprefix () + "copy";
696 public override string? get_copy_function () {
697 if (copy_function == null) {
698 copy_function = get_default_copy_function ();
700 return copy_function;
703 public void set_copy_function (string name) {
704 this.copy_function = name;
707 public string get_default_destroy_function () {
708 return get_lower_case_cprefix () + "destroy";
711 public override string? get_destroy_function () {
712 if (destroy_function == null) {
713 destroy_function = get_default_destroy_function ();
715 return destroy_function;
718 public void set_destroy_function (string name) {
719 this.destroy_function = name;
722 public bool is_disposable () {
723 if (destroy_function != null) {
724 return true;
727 foreach (Field f in fields) {
728 if (f.binding == MemberBinding.INSTANCE
729 && f.field_type.is_disposable ()) {
730 return true;
734 return false;
737 bool is_recursive_value_type (DataType type) {
738 var struct_type = type as StructValueType;
739 if (struct_type != null) {
740 var st = (Struct) struct_type.type_symbol;
741 if (st == this) {
742 return true;
744 foreach (Field f in st.fields) {
745 if (f.binding == MemberBinding.INSTANCE && is_recursive_value_type (f.field_type)) {
746 return true;
750 return false;
753 public override bool check (SemanticAnalyzer analyzer) {
754 if (checked) {
755 return !error;
758 checked = true;
760 process_attributes ();
762 var old_source_file = analyzer.current_source_file;
763 var old_symbol = analyzer.current_symbol;
765 if (source_reference != null) {
766 analyzer.current_source_file = source_reference.file;
768 analyzer.current_symbol = this;
770 if (base_type != null) {
771 base_type.check (analyzer);
773 if (!(base_type is ValueType)) {
774 error = true;
775 Report.error (source_reference, "The base type `%s` of struct `%s` is not a struct".printf (base_type.to_string (), get_full_name ()));
776 return false;
780 foreach (TypeParameter p in type_parameters) {
781 p.check (analyzer);
784 foreach (Field f in fields) {
785 f.check (analyzer);
787 if (f.binding == MemberBinding.INSTANCE && is_recursive_value_type (f.field_type)) {
788 error = true;
789 Report.error (f.source_reference, "Recursive value types are not allowed");
790 return false;
794 foreach (Constant c in constants) {
795 c.check (analyzer);
798 foreach (Method m in methods) {
799 m.check (analyzer);
802 foreach (Property prop in properties) {
803 prop.check (analyzer);
806 if (!external && !external_package && base_type == null && get_fields ().size == 0
807 && !is_boolean_type () && !is_integer_type () && !is_floating_type ()) {
808 error = true;
809 Report.error (source_reference, "structs cannot be empty: %s".printf(name));
812 analyzer.current_source_file = old_source_file;
813 analyzer.current_symbol = old_symbol;
815 return !error;
819 // vim:sw=8 noet