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;
36 private bool? boolean_type
;
37 private bool? integer_type
;
38 private bool? floating_type
;
39 private bool? decimal_floating_type
;
40 private bool? simple_type
;
43 private bool? _signed
;
44 private bool? _is_immutable
;
47 * Specifies the base type.
49 public DataType? base_type
{
54 value
.parent_node
= this
;
60 * Specifies the base Struct.
62 public Struct? base_struct
{
64 if (_base_type
!= null) {
65 return _base_type
.data_type as Struct
;
72 * Specifies the default construction method.
74 public Method default_construction_method
{ get; set; }
77 * Specifies if 'const' should be emitted for input parameters
80 public bool is_immutable
{
82 if (_is_immutable
== null) {
83 _is_immutable
= get_attribute ("Immutable") != null;
88 _is_immutable
= value
;
89 set_attribute ("Immutable", value
);
96 if (is_integer_type ()) {
97 _width
= get_attribute_integer ("IntegerType", "width", 32);
99 _width
= get_attribute_integer ("FloatingType", "width", 32);
106 if (is_integer_type ()) {
107 set_attribute_integer ("IntegerType", "width", value
);
109 set_attribute_integer ("FloatingType", "width", value
);
116 if (_signed
== null) {
117 _signed
= get_attribute_bool ("IntegerType", "signed", true);
123 set_attribute_bool ("IntegerType", "signed", value
);
128 * Creates a new struct.
130 * @param name type name
131 * @param source_reference reference to source code
132 * @return newly created struct
134 public Struct (string name
, SourceReference? source_reference
= null, Comment? comment
= null) {
135 base (name
, source_reference
, comment
);
139 * Appends the specified parameter to the list of type parameters.
141 * @param p a type parameter
143 public void add_type_parameter (TypeParameter p
) {
144 type_parameters
.add (p
);
145 scope
.add (p
.name
, p
);
149 * Returns a copy of the type parameter list.
151 * @return list of type parameters
153 public List
<TypeParameter
> get_type_parameters () {
154 return type_parameters
;
158 * Adds the specified constant as a member to this struct.
160 * @param c a constant
162 public override void add_constant (Constant c
) {
164 scope
.add (c
.name
, c
);
168 * Adds the specified field as a member to this struct.
172 public override void add_field (Field f
) {
173 f
.access
= SymbolAccessibility
.PUBLIC
;
176 scope
.add (f
.name
, f
);
180 * Returns a copy of the list of fields.
182 * @return list of fields
184 public List
<Field
> get_fields () {
189 * Returns a copy of the list of constants.
191 * @return list of constants
193 public List
<Constant
> get_constants () {
198 * Adds the specified method as a member to this struct.
202 public override void add_method (Method m
) {
203 return_if_fail (m
!= null);
205 if (m
.binding
== MemberBinding
.INSTANCE
|| m is CreationMethod
) {
206 m
.this_parameter
= new
Parameter ("this", SemanticAnalyzer
.get_data_type_for_symbol (this
));
207 m
.scope
.add (m
.this_parameter
.name
, m
.this_parameter
);
209 if (!(m
.return_type is VoidType
) && m
.get_postconditions ().size
> 0) {
210 m
.result_var
= new
LocalVariable (m
.return_type
.copy (), "result", null, source_reference
);
211 m
.result_var
.is_result
= true;
213 if (m is CreationMethod
) {
214 if (m
.name
== null) {
215 default_construction_method
= m
;
219 var cm
= (CreationMethod
) m
;
220 if (cm
.class_name
!= null && cm
.class_name
!= name
) {
221 // type_name is null for constructors generated by GIdlParser
222 Report
.error (m
.source_reference
, "missing return type in method `%s.%s´".printf (get_full_name (), cm
.class_name
));
229 scope
.add (m
.name
, m
);
233 * Returns a copy of the list of methods.
235 * @return list of methods
237 public List
<Method
> get_methods () {
242 * Adds the specified property as a member to this struct.
244 * @param prop a property
246 public override void add_property (Property prop
) {
247 properties
.add (prop
);
248 scope
.add (prop
.name
, prop
);
250 prop
.this_parameter
= new
Parameter ("this", SemanticAnalyzer
.get_data_type_for_symbol (this
));
251 prop
.scope
.add (prop
.this_parameter
.name
, prop
.this_parameter
);
253 if (prop
.field
!= null) {
254 add_field (prop
.field
);
259 * Returns a copy of the list of properties.
261 * @return list of properties
263 public List
<Property
> get_properties () {
267 public override void accept (CodeVisitor visitor
) {
268 visitor
.visit_struct (this
);
271 public override void accept_children (CodeVisitor visitor
) {
272 if (base_type
!= null) {
273 base_type
.accept (visitor
);
276 foreach (TypeParameter p
in type_parameters
) {
280 foreach (Field f
in fields
) {
284 foreach (Constant c
in constants
) {
288 foreach (Method m
in methods
) {
292 foreach (Property prop
in properties
) {
293 prop
.accept (visitor
);
298 * Returns whether this is a boolean type.
300 * @return true if this is a boolean type, false otherwise
302 public bool is_boolean_type () {
303 var st
= base_struct
;
304 if (st
!= null && st
.is_boolean_type ()) {
307 if (boolean_type
== null) {
308 boolean_type
= get_attribute ("BooleanType") != null;
314 * Returns whether this is an integer type.
316 * @return true if this is an integer type, false otherwise
318 public bool is_integer_type () {
319 var st
= base_struct
;
320 if (st
!= null && st
.is_integer_type ()) {
323 if (integer_type
== null) {
324 integer_type
= get_attribute ("IntegerType") != null;
330 * Returns whether this is a floating point type.
332 * @return true if this is a floating point type, false otherwise
334 public bool is_floating_type () {
335 var st
= base_struct
;
336 if (st
!= null && st
.is_floating_type ()) {
339 if (floating_type
== null) {
340 floating_type
= get_attribute ("FloatingType") != null;
342 return floating_type
;
345 public bool is_decimal_floating_type () {
346 var st
= base_struct
;
347 if (st
!= null && st
.is_decimal_floating_type ()) {
350 if (decimal_floating_type
== null) {
351 decimal_floating_type
= get_attribute_bool ("FloatingType", "decimal");
353 return decimal_floating_type
;
357 * Returns the rank of this integer or floating point type.
359 * @return the rank if this is an integer or floating point type
361 public int get_rank () {
363 if (is_integer_type () && has_attribute_argument ("IntegerType", "rank")) {
364 rank
= get_attribute_integer ("IntegerType", "rank");
365 } else if (has_attribute_argument ("FloatingType", "rank")) {
366 rank
= get_attribute_integer ("FloatingType", "rank");
368 var st
= base_struct
;
370 rank
= st
.get_rank ();
372 Report
.error (source_reference
, "internal error: struct has no rank");
381 * Sets the rank of this integer or floating point type.
383 public void set_rank (int rank
) {
385 if (is_integer_type ()) {
386 set_attribute_integer ("IntegerType", "rank", rank
);
388 set_attribute_integer ("FloatingType", "rank", rank
);
392 public override int get_type_parameter_index (string name
) {
395 foreach (TypeParameter p
in type_parameters
) {
396 if (p
.name
== name
) {
406 * Returns whether this struct is a simple type, i.e. whether
407 * instances are passed by value.
409 public bool is_simple_type () {
410 var st
= base_struct
;
411 if (st
!= null && st
.is_simple_type ()) {
414 if (simple_type
== null) {
415 simple_type
= get_attribute ("SimpleType") != null || get_attribute ("BooleanType") != null || get_attribute ("IntegerType") != null || get_attribute ("FloatingType") != null;
421 * Marks this struct as simple type, i.e. instances will be passed by
424 public void set_simple_type (bool simple_type
) {
425 this
.simple_type
= simple_type
;
426 set_attribute ("SimpleType", simple_type
);
429 public override void replace_type (DataType old_type
, DataType new_type
) {
430 if (base_type
== old_type
) {
431 base_type
= new_type
;
435 public override bool is_subtype_of (TypeSymbol t
) {
440 if (base_type
!= null) {
441 if (base_type
.data_type
!= null && base_type
.data_type
.is_subtype_of (t
)) {
449 public bool is_disposable () {
450 if (get_attribute_string ("CCode", "destroy_function") != null) {
454 foreach (Field f
in fields
) {
455 if (f
.binding
== MemberBinding
.INSTANCE
456 && f
.get_attribute_bool ("CCode", "delegate_target", true)
457 && f
.variable_type
.is_disposable ()) {
465 bool is_recursive_value_type (DataType type
) {
466 var struct_type
= type as StructValueType
;
467 if (struct_type
!= null && !struct_type
.nullable
) {
468 var st
= (Struct
) struct_type
.type_symbol
;
472 foreach (Field f
in st
.fields
) {
473 if (f
.binding
== MemberBinding
.INSTANCE
&& is_recursive_value_type (f
.variable_type
)) {
481 public override bool check (CodeContext context
) {
488 var old_source_file
= context
.analyzer
.current_source_file
;
489 var old_symbol
= context
.analyzer
.current_symbol
;
491 if (source_reference
!= null) {
492 context
.analyzer
.current_source_file
= source_reference
.file
;
494 context
.analyzer
.current_symbol
= this
;
496 if (base_type
!= null) {
497 base_type
.check (context
);
499 if (!(base_type is ValueType
)) {
501 Report
.error (source_reference
, "The base type `%s` of struct `%s` is not a struct".printf (base_type
.to_string (), get_full_name ()));
506 foreach (TypeParameter p
in type_parameters
) {
510 foreach (Field f
in fields
) {
513 if (f
.binding
== MemberBinding
.INSTANCE
&& is_recursive_value_type (f
.variable_type
)) {
515 Report
.error (f
.source_reference
, "Recursive value types are not allowed");
519 if (f
.binding
== MemberBinding
.INSTANCE
&& f
.initializer
!= null) {
521 Report
.error (f
.source_reference
, "Instance field initializers not supported");
526 foreach (Constant c
in constants
) {
530 foreach (Method m
in methods
) {
534 foreach (Property prop
in properties
) {
535 prop
.check (context
);
538 if (!external
&& !external_package
) {
539 if (base_type
== null && get_fields ().size
== 0 && !is_boolean_type () && !is_integer_type () && !is_floating_type ()) {
541 Report
.error (source_reference
, "structs cannot be empty: %s".printf(name
));
542 } else if (base_type
!= null) {
543 foreach (Field f
in fields
) {
544 if (f
.binding
== MemberBinding
.INSTANCE
) {
546 Report
.error (source_reference
, "derived structs may not have instance fields");
553 context
.analyzer
.current_source_file
= old_source_file
;
554 context
.analyzer
.current_symbol
= old_symbol
;