valac: Always use the given "pkg-config" and respect PKG_CONFIG envar
[vala-gnome.git] / vala / valastruct.vala
blob21985d7af3420a72be8a49c1b9cf2210db3ac2fa
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 ();
374 return rank;
378 * Sets the rank of this integer or floating point type.
380 public void set_rank (int rank) {
381 this.rank = rank;
382 if (is_integer_type ()) {
383 set_attribute_integer ("IntegerType", "rank", rank);
384 } else {
385 set_attribute_integer ("FloatingType", "rank", rank);
389 public override int get_type_parameter_index (string name) {
390 int i = 0;
392 foreach (TypeParameter p in type_parameters) {
393 if (p.name == name) {
394 return (i);
396 i++;
399 return -1;
403 * Returns whether this struct is a simple type, i.e. whether
404 * instances are passed by value.
406 public bool is_simple_type () {
407 var st = base_struct;
408 if (st != null && st.is_simple_type ()) {
409 return true;
411 if (simple_type == null) {
412 simple_type = get_attribute ("SimpleType") != null || get_attribute ("BooleanType") != null || get_attribute ("IntegerType") != null || get_attribute ("FloatingType") != null;
414 return simple_type;
418 * Marks this struct as simple type, i.e. instances will be passed by
419 * value.
421 public void set_simple_type (bool simple_type) {
422 this.simple_type = simple_type;
423 set_attribute ("SimpleType", simple_type);
426 public override void replace_type (DataType old_type, DataType new_type) {
427 if (base_type == old_type) {
428 base_type = new_type;
432 public override bool is_subtype_of (TypeSymbol t) {
433 if (this == t) {
434 return true;
437 if (base_type != null) {
438 if (base_type.data_type != null && base_type.data_type.is_subtype_of (t)) {
439 return true;
443 return false;
446 public bool is_disposable () {
447 if (get_attribute_string ("CCode", "destroy_function") != null) {
448 return true;
451 foreach (Field f in fields) {
452 if (f.binding == MemberBinding.INSTANCE
453 && f.variable_type.is_disposable ()) {
454 return true;
458 return false;
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;
465 if (st == this) {
466 return true;
468 foreach (Field f in st.fields) {
469 if (f.binding == MemberBinding.INSTANCE && is_recursive_value_type (f.variable_type)) {
470 return true;
474 return false;
477 public override bool check (CodeContext context) {
478 if (checked) {
479 return !error;
482 checked = true;
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)) {
496 error = true;
497 Report.error (source_reference, "The base type `%s` of struct `%s` is not a struct".printf (base_type.to_string (), get_full_name ()));
498 return false;
502 foreach (TypeParameter p in type_parameters) {
503 p.check (context);
506 foreach (Field f in fields) {
507 f.check (context);
509 if (f.binding == MemberBinding.INSTANCE && is_recursive_value_type (f.variable_type)) {
510 error = true;
511 Report.error (f.source_reference, "Recursive value types are not allowed");
512 return false;
515 if (f.binding == MemberBinding.INSTANCE && f.initializer != null) {
516 error = true;
517 Report.error (f.source_reference, "Instance field initializers not supported");
518 return false;
522 foreach (Constant c in constants) {
523 c.check (context);
526 foreach (Method m in methods) {
527 m.check (context);
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 ()) {
536 error = true;
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) {
541 error = true;
542 Report.error (source_reference, "derived structs may not have instance fields");
543 break;
549 context.analyzer.current_source_file = old_source_file;
550 context.analyzer.current_symbol = old_symbol;
552 return !error;
556 // vim:sw=8 noet