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 * Specifies the rank of this integer or floating point type.
133 if (is_integer_type () && has_attribute_argument ("IntegerType", "rank")) {
134 _rank
= get_attribute_integer ("IntegerType", "rank");
135 } else if (has_attribute_argument ("FloatingType", "rank")) {
136 _rank
= get_attribute_integer ("FloatingType", "rank");
138 var st
= base_struct
;
142 Report
.error (source_reference
, "internal error: struct has no rank");
151 if (is_integer_type ()) {
152 set_attribute_integer ("IntegerType", "rank", _rank
);
154 set_attribute_integer ("FloatingType", "rank", _rank
);
160 * Creates a new struct.
162 * @param name type name
163 * @param source_reference reference to source code
164 * @return newly created struct
166 public Struct (string name
, SourceReference? source_reference
= null, Comment? comment
= null) {
167 base (name
, source_reference
, comment
);
171 * Appends the specified parameter to the list of type parameters.
173 * @param p a type parameter
175 public void add_type_parameter (TypeParameter p
) {
176 type_parameters
.add (p
);
177 scope
.add (p
.name
, p
);
181 * Returns a copy of the type parameter list.
183 * @return list of type parameters
185 public List
<TypeParameter
> get_type_parameters () {
186 return type_parameters
;
190 * Adds the specified constant as a member to this struct.
192 * @param c a constant
194 public override void add_constant (Constant c
) {
196 scope
.add (c
.name
, c
);
200 * Adds the specified field as a member to this struct.
204 public override void add_field (Field f
) {
205 f
.access
= SymbolAccessibility
.PUBLIC
;
208 scope
.add (f
.name
, f
);
212 * Returns a copy of the list of fields.
214 * @return list of fields
216 public List
<Field
> get_fields () {
221 * Returns a copy of the list of constants.
223 * @return list of constants
225 public List
<Constant
> get_constants () {
230 * Adds the specified method as a member to this struct.
234 public override void add_method (Method m
) {
235 return_if_fail (m
!= null);
237 if (m
.binding
== MemberBinding
.INSTANCE
|| m is CreationMethod
) {
238 m
.this_parameter
= new
Parameter ("this", SemanticAnalyzer
.get_data_type_for_symbol (this
));
239 m
.scope
.add (m
.this_parameter
.name
, m
.this_parameter
);
241 if (!(m
.return_type is VoidType
) && m
.get_postconditions ().size
> 0) {
242 m
.result_var
= new
LocalVariable (m
.return_type
.copy (), "result", null, source_reference
);
243 m
.result_var
.is_result
= true;
245 if (m is CreationMethod
) {
246 if (m
.name
== null) {
247 default_construction_method
= m
;
251 var cm
= (CreationMethod
) m
;
252 if (cm
.class_name
!= null && cm
.class_name
!= name
) {
253 // type_name is null for constructors generated by GIdlParser
254 Report
.error (m
.source_reference
, "missing return type in method `%s.%s´".printf (get_full_name (), cm
.class_name
));
261 scope
.add (m
.name
, m
);
265 * Returns a copy of the list of methods.
267 * @return list of methods
269 public List
<Method
> get_methods () {
274 * Adds the specified property as a member to this struct.
276 * @param prop a property
278 public override void add_property (Property prop
) {
279 properties
.add (prop
);
280 scope
.add (prop
.name
, prop
);
282 prop
.this_parameter
= new
Parameter ("this", SemanticAnalyzer
.get_data_type_for_symbol (this
));
283 prop
.scope
.add (prop
.this_parameter
.name
, prop
.this_parameter
);
285 if (prop
.field
!= null) {
286 add_field (prop
.field
);
291 * Returns a copy of the list of properties.
293 * @return list of properties
295 public List
<Property
> get_properties () {
299 public override void accept (CodeVisitor visitor
) {
300 visitor
.visit_struct (this
);
303 public override void accept_children (CodeVisitor visitor
) {
304 if (base_type
!= null) {
305 base_type
.accept (visitor
);
308 foreach (TypeParameter p
in type_parameters
) {
312 foreach (Field f
in fields
) {
316 foreach (Constant c
in constants
) {
320 foreach (Method m
in methods
) {
324 foreach (Property prop
in properties
) {
325 prop
.accept (visitor
);
330 * Returns whether this is a boolean type.
332 * @return true if this is a boolean type, false otherwise
334 public bool is_boolean_type () {
335 var st
= base_struct
;
336 if (st
!= null && st
.is_boolean_type ()) {
339 if (boolean_type
== null) {
340 boolean_type
= get_attribute ("BooleanType") != null;
346 * Returns whether this is an integer type.
348 * @return true if this is an integer type, false otherwise
350 public bool is_integer_type () {
351 var st
= base_struct
;
352 if (st
!= null && st
.is_integer_type ()) {
355 if (integer_type
== null) {
356 integer_type
= get_attribute ("IntegerType") != null;
362 * Returns whether this is a floating point type.
364 * @return true if this is a floating point type, false otherwise
366 public bool is_floating_type () {
367 var st
= base_struct
;
368 if (st
!= null && st
.is_floating_type ()) {
371 if (floating_type
== null) {
372 floating_type
= get_attribute ("FloatingType") != null;
374 return floating_type
;
377 public bool is_decimal_floating_type () {
378 var st
= base_struct
;
379 if (st
!= null && st
.is_decimal_floating_type ()) {
382 if (decimal_floating_type
== null) {
383 decimal_floating_type
= get_attribute_bool ("FloatingType", "decimal");
385 return decimal_floating_type
;
388 public override int get_type_parameter_index (string name
) {
391 foreach (TypeParameter p
in type_parameters
) {
392 if (p
.name
== name
) {
402 * Returns whether this struct is a simple type, i.e. whether
403 * instances are passed by value.
405 public bool is_simple_type () {
406 var st
= base_struct
;
407 if (st
!= null && st
.is_simple_type ()) {
410 if (simple_type
== null) {
411 simple_type
= get_attribute ("SimpleType") != null || get_attribute ("BooleanType") != null || get_attribute ("IntegerType") != null || get_attribute ("FloatingType") != null;
417 * Marks this struct as simple type, i.e. instances will be passed by
420 public void set_simple_type (bool simple_type
) {
421 this
.simple_type
= simple_type
;
422 set_attribute ("SimpleType", simple_type
);
425 public override void replace_type (DataType old_type
, DataType new_type
) {
426 if (base_type
== old_type
) {
427 base_type
= new_type
;
431 public override bool is_subtype_of (TypeSymbol t
) {
436 if (base_type
!= null) {
437 if (base_type
.data_type
!= null && base_type
.data_type
.is_subtype_of (t
)) {
445 public bool is_disposable () {
446 if (get_attribute_string ("CCode", "destroy_function") != null) {
450 foreach (Field f
in fields
) {
451 if (f
.binding
== MemberBinding
.INSTANCE
452 && f
.get_attribute_bool ("CCode", "delegate_target", true)
453 && f
.variable_type
.is_disposable ()) {
461 bool is_recursive_value_type (DataType type
) {
462 var struct_type
= type as StructValueType
;
463 if (struct_type
!= null && !struct_type
.nullable
) {
464 var st
= (Struct
) struct_type
.type_symbol
;
468 foreach (Field f
in st
.fields
) {
469 if (f
.binding
== MemberBinding
.INSTANCE
&& is_recursive_value_type (f
.variable_type
)) {
477 public override bool check (CodeContext context
) {
484 var old_source_file
= context
.analyzer
.current_source_file
;
485 var old_symbol
= context
.analyzer
.current_symbol
;
487 if (source_reference
!= null) {
488 context
.analyzer
.current_source_file
= source_reference
.file
;
490 context
.analyzer
.current_symbol
= this
;
492 if (base_type
!= null) {
493 base_type
.check (context
);
495 if (!(base_type is ValueType
)) {
497 Report
.error (source_reference
, "The base type `%s` of struct `%s` is not a struct".printf (base_type
.to_string (), get_full_name ()));
502 foreach (TypeParameter p
in type_parameters
) {
506 foreach (Field f
in fields
) {
509 if (f
.binding
== MemberBinding
.INSTANCE
&& is_recursive_value_type (f
.variable_type
)) {
511 Report
.error (f
.source_reference
, "Recursive value types are not allowed");
515 if (f
.binding
== MemberBinding
.INSTANCE
&& f
.initializer
!= null) {
517 Report
.error (f
.source_reference
, "Instance field initializers not supported");
522 foreach (Constant c
in constants
) {
526 foreach (Method m
in methods
) {
530 foreach (Property prop
in properties
) {
531 prop
.check (context
);
534 if (!external
&& !external_package
) {
535 if (base_type
== null && get_fields ().size
== 0 && !is_boolean_type () && !is_integer_type () && !is_floating_type ()) {
537 Report
.error (source_reference
, "structs cannot be empty: %s".printf(name
));
538 } else if (base_type
!= null) {
539 foreach (Field f
in fields
) {
540 if (f
.binding
== MemberBinding
.INSTANCE
) {
542 Report
.error (source_reference
, "derived structs may not have instance fields");
549 context
.analyzer
.current_source_file
= old_source_file
;
550 context
.analyzer
.current_symbol
= old_symbol
;