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
20 * Jürg Billeter <j@bitron.ch>
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;
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
;
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
;
55 * Specifies the base type.
57 public DataType? base_type
{
62 value
.parent_node
= this
;
68 * Specifies the base Struct.
70 public Struct? base_struct
{
72 if (_base_type
!= null) {
73 return _base_type
.data_type as Struct
;
80 * Specifies the default construction method.
82 public Method default_construction_method
{ get; set; }
85 * Specifies if 'const' should be emitted for input parameters
88 public bool is_immutable
{ get; set; }
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
) {
140 scope
.add (c
.name
, c
);
144 * Adds the specified field as a member to this struct.
148 public override void add_field (Field f
) {
149 // TODO report error when `private' or `protected' has been specified
150 f
.access
= SymbolAccessibility
.PUBLIC
;
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 () {
166 * Returns a copy of the list of constants.
168 * @return list of constants
170 public List
<Constant
> get_constants () {
175 * Adds the specified method as a member to this struct.
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
;
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
));
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 () {
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 () {
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
) {
257 foreach (Field f
in fields
) {
261 foreach (Constant c
in constants
) {
265 foreach (Method m
in methods
) {
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) {
280 var attr
= get_attribute ("CCode");
282 cname
= attr
.get_string ("cname");
285 cname
= get_default_cname ();
291 public void set_cname (string 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
);
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
) {
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 ()) {
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 ()) {
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 ()) {
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 ()) {
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 () {
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
) {
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
) {
469 private void process_integer_type_attribute (Attribute a
) {
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") {
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) {
523 if (base_type
!= null) {
524 var st
= base_struct
;
526 return st
.get_type_id ();
529 if (is_simple_type ()) {
532 return "G_TYPE_POINTER";
535 type_id
= get_upper_case_cname ("TYPE_");
541 public void set_type_id (string? 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
;
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
= "";
558 } else if (has_type_id
) {
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
;
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
= "";
584 } else if (has_type_id
) {
585 return "g_value_get_boxed";
587 return "g_value_get_pointer";
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
;
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
= "";
607 } else if (has_type_id
) {
608 return "g_value_set_boxed";
610 return "g_value_set_pointer";
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
;
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
= "";
630 } else if (has_type_id
) {
631 return "g_value_take_boxed";
633 return "g_value_take_pointer";
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
;
661 return st
.get_default_value ();
665 if (CodeContext
.get ().profile
== Profile
.DOVA
) {
668 } else if (integer_type
|| floating_type
) {
676 private void set_default_value (string? value
) {
677 default_value
= value
;
680 public override int get_type_parameter_index (string name
) {
683 foreach (TypeParameter p
in type_parameters
) {
684 if (p
.name
== name
) {
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 ()) {
704 if (get_attribute ("ByRef") != null) {
708 if (CodeContext
.get ().profile
== Profile
.DOVA
) {
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
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
) {
734 if (base_type
!= null) {
735 if (base_type
.data_type
!= null && base_type
.data_type
.is_subtype_of (t
)) {
743 public override string?
get_dup_function () {
744 // TODO use attribute check instead
745 if (external_package
) {
748 return get_lower_case_cprefix () + "dup";
752 public override string?
get_free_function () {
753 // TODO use attribute check instead
754 if (external_package
) {
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) {
796 foreach (Field f
in fields
) {
797 if (f
.binding
== MemberBinding
.INSTANCE
798 && f
.variable_type
.is_disposable ()) {
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
;
813 foreach (Field f
in st
.fields
) {
814 if (f
.binding
== MemberBinding
.INSTANCE
&& is_recursive_value_type (f
.variable_type
)) {
822 public override bool check (CodeContext context
) {
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
)) {
844 Report
.error (source_reference
, "The base type `%s` of struct `%s` is not a struct".printf (base_type
.to_string (), get_full_name ()));
849 foreach (TypeParameter p
in type_parameters
) {
853 foreach (Field f
in fields
) {
856 if (f
.binding
== MemberBinding
.INSTANCE
&& is_recursive_value_type (f
.variable_type
)) {
858 Report
.error (f
.source_reference
, "Recursive value types are not allowed");
862 if (f
.binding
== MemberBinding
.INSTANCE
&& f
.initializer
!= null) {
864 Report
.error (f
.source_reference
, "Instance field initializers not supported");
869 foreach (Constant c
in constants
) {
873 foreach (Method m
in methods
) {
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 ()) {
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
) {
889 Report
.error (source_reference
, "derived structs may not have instance fields");
896 context
.analyzer
.current_source_file
= old_source_file
;
897 context
.analyzer
.current_symbol
= old_symbol
;