gio-unix-2.0: Add DesktopAppInfo.launch_uris_as_manager_with_fds()
[vala-gnome.git] / vala / valastruct.vala
blob1c4ba768cfd15af14dc02aa9933930f66325d8c0
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 * Specifies the rank of this integer or floating point type.
130 public int rank {
131 get {
132 if (_rank == null) {
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");
137 } else {
138 var st = base_struct;
139 if (st != null) {
140 _rank = st.rank;
141 } else {
142 Report.error (source_reference, "internal error: struct has no rank");
143 return 0;
147 return _rank;
149 set {
150 _rank = value;
151 if (is_integer_type ()) {
152 set_attribute_integer ("IntegerType", "rank", _rank);
153 } else {
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) {
195 constants.add (c);
196 scope.add (c.name, c);
200 * Adds the specified field as a member to this struct.
202 * @param f a field
204 public override void add_field (Field f) {
205 f.access = SymbolAccessibility.PUBLIC;
207 fields.add (f);
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 () {
217 return fields;
221 * Returns a copy of the list of constants.
223 * @return list of constants
225 public List<Constant> get_constants () {
226 return constants;
230 * Adds the specified method as a member to this struct.
232 * @param m a method
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;
248 m.name = ".new";
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));
255 m.error = true;
256 return;
260 methods.add (m);
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 () {
270 return 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 () {
296 return 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) {
309 p.accept (visitor);
312 foreach (Field f in fields) {
313 f.accept (visitor);
316 foreach (Constant c in constants) {
317 c.accept (visitor);
320 foreach (Method m in methods) {
321 m.accept (visitor);
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 ()) {
337 return true;
339 if (boolean_type == null) {
340 boolean_type = get_attribute ("BooleanType") != null;
342 return boolean_type;
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 ()) {
353 return true;
355 if (integer_type == null) {
356 integer_type = get_attribute ("IntegerType") != null;
358 return integer_type;
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 ()) {
369 return true;
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 ()) {
380 return true;
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) {
389 int i = 0;
391 foreach (TypeParameter p in type_parameters) {
392 if (p.name == name) {
393 return (i);
395 i++;
398 return -1;
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 ()) {
408 return true;
410 if (simple_type == null) {
411 simple_type = get_attribute ("SimpleType") != null || get_attribute ("BooleanType") != null || get_attribute ("IntegerType") != null || get_attribute ("FloatingType") != null;
413 return simple_type;
417 * Marks this struct as simple type, i.e. instances will be passed by
418 * value.
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) {
432 if (this == t) {
433 return true;
436 if (base_type != null) {
437 if (base_type.data_type != null && base_type.data_type.is_subtype_of (t)) {
438 return true;
442 return false;
445 public bool is_disposable () {
446 if (get_attribute_string ("CCode", "destroy_function") != null) {
447 return true;
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 ()) {
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