girparser: Add common parse_symbol_from_string method
[vala-lang.git] / vala / valastruct.vala
blobcab1b820a54aae8d54150f1de8a04bfce826c5b4
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);
518 public override string? get_type_id () {
519 if (type_id == null) {
520 if (!has_type_id) {
521 if (base_type != null) {
522 var st = base_struct;
523 if (st != null) {
524 return st.get_type_id ();
527 if (is_simple_type ()) {
528 return null;
529 } else {
530 return "G_TYPE_POINTER";
532 } else {
533 type_id = get_upper_case_cname ("TYPE_");
536 return type_id;
539 public void set_type_id (string? name) {
540 this.type_id = name;
543 public override string? get_marshaller_type_name () {
544 if (marshaller_type_name == null) {
545 if (base_type != null) {
546 var st = base_struct;
547 if (st != null) {
548 return st.get_marshaller_type_name ();
551 if (is_simple_type ()) {
552 Report.error (source_reference, "The type `%s` doesn't declare a marshaller type name".printf (get_full_name ()));
553 // set marshaller_type_name to avoid multiple errors
554 marshaller_type_name = "";
555 return "";
556 } else if (has_type_id) {
557 return "BOXED";
558 } else {
559 return "POINTER";
562 return marshaller_type_name;
565 private void set_marshaller_type_name (string? name) {
566 this.marshaller_type_name = name;
569 public override string? get_get_value_function () {
570 if (get_value_function == null) {
571 if (base_type != null) {
572 var st = base_struct;
573 if (st != null) {
574 return st.get_get_value_function ();
577 if (is_simple_type ()) {
578 Report.error (source_reference, "The value type `%s` doesn't declare a GValue get function".printf (get_full_name ()));
579 // set get_value_function to avoid multiple errors
580 get_value_function = "";
581 return "";
582 } else if (has_type_id) {
583 return "g_value_get_boxed";
584 } else {
585 return "g_value_get_pointer";
587 } else {
588 return get_value_function;
592 public override string? get_set_value_function () {
593 if (set_value_function == null) {
594 if (base_type != null) {
595 var st = base_struct;
596 if (st != null) {
597 return st.get_set_value_function ();
600 if (is_simple_type ()) {
601 Report.error (source_reference, "The value type `%s` doesn't declare a GValue set function".printf (get_full_name ()));
602 // set set_value_function to avoid multiple errors
603 set_value_function = "";
604 return "";
605 } else if (has_type_id) {
606 return "g_value_set_boxed";
607 } else {
608 return "g_value_set_pointer";
610 } else {
611 return set_value_function;
615 public override string? get_take_value_function () {
616 if (take_value_function == null) {
617 if (base_type != null) {
618 var st = base_struct;
619 if (st != null) {
620 return st.get_take_value_function ();
623 if (is_simple_type ()) {
624 Report.error (source_reference, "The value type `%s` doesn't declare a GValue take function".printf (get_full_name ()));
625 // set take_value_function to avoid multiple errors
626 take_value_function = "";
627 return "";
628 } else if (has_type_id) {
629 return "g_value_take_boxed";
630 } else {
631 return "g_value_take_pointer";
633 } else {
634 return take_value_function;
638 private void set_get_value_function (string? function) {
639 get_value_function = function;
642 private void set_set_value_function (string? function) {
643 set_value_function = function;
646 private void set_take_value_function (string? function) {
647 take_value_function = function;
650 public override string? get_default_value () {
651 if (default_value != null) {
652 return default_value;
655 // inherit default value from base type
656 if (base_type != null) {
657 var st = base_struct;
658 if (st != null) {
659 return st.get_default_value ();
663 if (CodeContext.get ().profile == Profile.DOVA) {
664 if (boolean_type) {
665 return "false";
666 } else if (integer_type || floating_type) {
667 return "0";
671 return null;
674 private void set_default_value (string? value) {
675 default_value = value;
678 public override int get_type_parameter_index (string name) {
679 int i = 0;
681 foreach (TypeParameter p in type_parameters) {
682 if (p.name == name) {
683 return (i);
685 i++;
688 return -1;
692 * Returns whether this struct is a simple type, i.e. whether
693 * instances are passed by value.
695 public bool is_simple_type () {
696 if (base_type != null) {
697 var st = base_struct;
698 if (st != null && st.is_simple_type ()) {
699 return true;
702 if (get_attribute ("ByRef") != null) {
703 // used by time_t
704 return false;
706 if (CodeContext.get ().profile == Profile.DOVA) {
707 return true;
709 return (boolean_type || integer_type || floating_type
710 || get_attribute ("SimpleType") != null);
714 * Marks this struct as simple type, i.e. instances will be passed by
715 * value.
717 public void set_simple_type (bool simple_type) {
718 attributes.append (new Attribute ("SimpleType"));
721 public override void replace_type (DataType old_type, DataType new_type) {
722 if (base_type == old_type) {
723 base_type = new_type;
727 public override bool is_subtype_of (TypeSymbol t) {
728 if (this == t) {
729 return true;
732 if (base_type != null) {
733 if (base_type.data_type != null && base_type.data_type.is_subtype_of (t)) {
734 return true;
738 return false;
741 public override string? get_dup_function () {
742 // TODO use attribute check instead
743 if (external_package) {
744 return null;
745 } else {
746 return get_lower_case_cprefix () + "dup";
750 public override string? get_free_function () {
751 // TODO use attribute check instead
752 if (external_package) {
753 return null;
754 } else {
755 return get_lower_case_cprefix () + "free";
759 public string get_default_copy_function () {
760 return get_lower_case_cprefix () + "copy";
763 public override string? get_copy_function () {
764 if (copy_function == null) {
765 copy_function = get_default_copy_function ();
767 return copy_function;
770 public void set_copy_function (string name) {
771 this.copy_function = name;
774 public string get_default_destroy_function () {
775 return get_lower_case_cprefix () + "destroy";
778 public override string? get_destroy_function () {
779 if (destroy_function == null) {
780 destroy_function = get_default_destroy_function ();
782 return destroy_function;
785 public void set_destroy_function (string name) {
786 this.destroy_function = name;
789 public bool is_disposable () {
790 if (destroy_function != null) {
791 return true;
794 foreach (Field f in fields) {
795 if (f.binding == MemberBinding.INSTANCE
796 && f.variable_type.is_disposable ()) {
797 return true;
801 return false;
804 bool is_recursive_value_type (DataType type) {
805 var struct_type = type as StructValueType;
806 if (struct_type != null && !struct_type.nullable) {
807 var st = (Struct) struct_type.type_symbol;
808 if (st == this) {
809 return true;
811 foreach (Field f in st.fields) {
812 if (f.binding == MemberBinding.INSTANCE && is_recursive_value_type (f.variable_type)) {
813 return true;
817 return false;
820 public override bool check (CodeContext context) {
821 if (checked) {
822 return !error;
825 checked = true;
827 process_attributes ();
829 var old_source_file = context.analyzer.current_source_file;
830 var old_symbol = context.analyzer.current_symbol;
832 if (source_reference != null) {
833 context.analyzer.current_source_file = source_reference.file;
835 context.analyzer.current_symbol = this;
837 if (base_type != null) {
838 base_type.check (context);
840 if (!(base_type is ValueType)) {
841 error = true;
842 Report.error (source_reference, "The base type `%s` of struct `%s` is not a struct".printf (base_type.to_string (), get_full_name ()));
843 return false;
847 foreach (TypeParameter p in type_parameters) {
848 p.check (context);
851 foreach (Field f in fields) {
852 f.check (context);
854 if (f.binding == MemberBinding.INSTANCE && is_recursive_value_type (f.variable_type)) {
855 error = true;
856 Report.error (f.source_reference, "Recursive value types are not allowed");
857 return false;
860 if (f.binding == MemberBinding.INSTANCE && f.initializer != null) {
861 error = true;
862 Report.error (f.source_reference, "Instance field initializers not supported");
863 return false;
867 foreach (Constant c in constants) {
868 c.check (context);
871 foreach (Method m in methods) {
872 m.check (context);
875 foreach (Property prop in properties) {
876 prop.check (context);
879 if (!external && !external_package) {
880 if (base_type == null && get_fields ().size == 0 && !is_boolean_type () && !is_integer_type () && !is_floating_type ()) {
881 error = true;
882 Report.error (source_reference, "structs cannot be empty: %s".printf(name));
883 } else if (base_type != null) {
884 foreach (Field f in fields) {
885 if (f.binding == MemberBinding.INSTANCE) {
886 error = true;
887 Report.error (source_reference, "derived structs may not have instance fields");
888 break;
894 context.analyzer.current_source_file = old_source_file;
895 context.analyzer.current_symbol = old_symbol;
897 return !error;
901 // vim:sw=8 noet