gtk+-4.0: Update to 3.93.0+f4c1a404
[vala-gnome.git] / vala / valastruct.vala
bloba6c56c6822b904098aaca2027088be8ec37fea79
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 bool? boolean_type;
37 private bool? integer_type;
38 private bool? floating_type;
39 private bool? decimal_floating_type;
40 private bool? simple_type;
41 private int? rank;
42 private int? _width;
43 private bool? _signed;
44 private bool? _is_immutable;
46 /**
47 * Specifies the base type.
49 public DataType? base_type {
50 get {
51 return _base_type;
53 set {
54 value.parent_node = this;
55 _base_type = value;
59 /**
60 * Specifies the base Struct.
62 public Struct? base_struct {
63 get {
64 if (_base_type != null) {
65 return _base_type.data_type as Struct;
67 return null;
71 /**
72 * Specifies the default construction method.
74 public Method default_construction_method { get; set; }
76 /**
77 * Specifies if 'const' should be emitted for input parameters
78 * of this type.
80 public bool is_immutable {
81 get {
82 if (_is_immutable == null) {
83 _is_immutable = get_attribute ("Immutable") != null;
85 return _is_immutable;
87 set {
88 _is_immutable = value;
89 set_attribute ("Immutable", value);
93 public int width {
94 get {
95 if (_width == null) {
96 if (is_integer_type ()) {
97 _width = get_attribute_integer ("IntegerType", "width", 32);
98 } else {
99 _width = get_attribute_integer ("FloatingType", "width", 32);
102 return _width;
104 set {
105 _width = value;
106 if (is_integer_type ()) {
107 set_attribute_integer ("IntegerType", "width", value);
108 } else {
109 set_attribute_integer ("FloatingType", "width", value);
114 public bool signed {
115 get {
116 if (_signed == null) {
117 _signed = get_attribute_bool ("IntegerType", "signed", true);
119 return _signed;
121 set {
122 _signed = value;
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) {
163 constants.add (c);
164 scope.add (c.name, c);
168 * Adds the specified field as a member to this struct.
170 * @param f a field
172 public override void add_field (Field f) {
173 f.access = SymbolAccessibility.PUBLIC;
175 fields.add (f);
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 () {
185 return fields;
189 * Returns a copy of the list of constants.
191 * @return list of constants
193 public List<Constant> get_constants () {
194 return constants;
198 * Adds the specified method as a member to this struct.
200 * @param m a method
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;
216 m.name = ".new";
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));
223 m.error = true;
224 return;
228 methods.add (m);
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 () {
238 return 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 () {
264 return 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) {
277 p.accept (visitor);
280 foreach (Field f in fields) {
281 f.accept (visitor);
284 foreach (Constant c in constants) {
285 c.accept (visitor);
288 foreach (Method m in methods) {
289 m.accept (visitor);
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 ()) {
305 return true;
307 if (boolean_type == null) {
308 boolean_type = get_attribute ("BooleanType") != null;
310 return boolean_type;
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 ()) {
321 return true;
323 if (integer_type == null) {
324 integer_type = get_attribute ("IntegerType") != null;
326 return integer_type;
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 ()) {
337 return true;
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 ()) {
348 return true;
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 () {
362 if (rank == null) {
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");
367 } else {
368 var st = base_struct;
369 if (st != null) {
370 rank = st.get_rank ();
371 } else {
372 Report.error (source_reference, "internal error: struct has no rank");
373 return 0;
377 return rank;
381 * Sets the rank of this integer or floating point type.
383 public void set_rank (int rank) {
384 this.rank = rank;
385 if (is_integer_type ()) {
386 set_attribute_integer ("IntegerType", "rank", rank);
387 } else {
388 set_attribute_integer ("FloatingType", "rank", rank);
392 public override int get_type_parameter_index (string name) {
393 int i = 0;
395 foreach (TypeParameter p in type_parameters) {
396 if (p.name == name) {
397 return (i);
399 i++;
402 return -1;
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 ()) {
412 return true;
414 if (simple_type == null) {
415 simple_type = get_attribute ("SimpleType") != null || get_attribute ("BooleanType") != null || get_attribute ("IntegerType") != null || get_attribute ("FloatingType") != null;
417 return simple_type;
421 * Marks this struct as simple type, i.e. instances will be passed by
422 * value.
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) {
436 if (this == t) {
437 return true;
440 if (base_type != null) {
441 if (base_type.data_type != null && base_type.data_type.is_subtype_of (t)) {
442 return true;
446 return false;
449 public bool is_disposable () {
450 if (get_attribute_string ("CCode", "destroy_function") != null) {
451 return true;
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 ()) {
458 return true;
462 return false;
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;
469 if (st == this) {
470 return true;
472 foreach (Field f in st.fields) {
473 if (f.binding == MemberBinding.INSTANCE && is_recursive_value_type (f.variable_type)) {
474 return true;
478 return false;
481 public override bool check (CodeContext context) {
482 if (checked) {
483 return !error;
486 checked = true;
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)) {
500 error = true;
501 Report.error (source_reference, "The base type `%s` of struct `%s` is not a struct".printf (base_type.to_string (), get_full_name ()));
502 return false;
506 foreach (TypeParameter p in type_parameters) {
507 p.check (context);
510 foreach (Field f in fields) {
511 f.check (context);
513 if (f.binding == MemberBinding.INSTANCE && is_recursive_value_type (f.variable_type)) {
514 error = true;
515 Report.error (f.source_reference, "Recursive value types are not allowed");
516 return false;
519 if (f.binding == MemberBinding.INSTANCE && f.initializer != null) {
520 error = true;
521 Report.error (f.source_reference, "Instance field initializers not supported");
522 return false;
526 foreach (Constant c in constants) {
527 c.check (context);
530 foreach (Method m in methods) {
531 m.check (context);
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 ()) {
540 error = true;
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) {
545 error = true;
546 Report.error (source_reference, "derived structs may not have instance fields");
547 break;
553 context.analyzer.current_source_file = old_source_file;
554 context.analyzer.current_symbol = old_symbol;
556 return !error;
560 // vim:sw=8 noet