Line data Source code
1 : /* valastruct.vala
2 : *
3 : * Copyright (C) 2006-2010 Jürg Billeter
4 : *
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.
9 :
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.
14 :
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
18 : *
19 : * Author:
20 : * Jürg Billeter <j@bitron.ch>
21 : */
22 :
23 : using GLib;
24 :
25 : /**
26 : * Represents a struct declaration in the source code.
27 : */
28 289734 : public class Vala.Struct : TypeSymbol, GenericSymbol {
29 286658 : private List<TypeParameter> type_parameters = new ArrayList<TypeParameter> ();
30 286658 : private List<Constant> constants = new ArrayList<Constant> ();
31 286658 : private List<Field> fields = new ArrayList<Field> ();
32 286658 : private List<Method> methods = new ArrayList<Method> ();
33 286658 : private List<Property> properties = new ArrayList<Property> ();
34 286658 : private Set<weak Field> property_fields = new HashSet<weak Field> ();
35 143329 : private DataType _base_type = null;
36 :
37 143329 : private bool? boolean_type;
38 143329 : private bool? integer_type;
39 143329 : private bool? floating_type;
40 143329 : private bool? decimal_floating_type;
41 143329 : private bool? simple_type;
42 143329 : private int? _rank;
43 143329 : private int? _width;
44 143329 : private bool? _signed;
45 143329 : private bool? _is_immutable;
46 :
47 : /**
48 : * Specifies the base type.
49 : */
50 : public DataType? base_type {
51 10707670 : get {
52 10707670 : return _base_type;
53 : }
54 21757 : set {
55 21757 : value.parent_node = this;
56 210306 : _base_type = value;
57 : }
58 : }
59 :
60 : /**
61 : * Specifies the base Struct.
62 : */
63 : public Struct? base_struct {
64 9070933 : get {
65 9070933 : if (_base_type != null) {
66 1624877 : return _base_type.type_symbol as Struct;
67 : }
68 9070933 : return null;
69 : }
70 : }
71 :
72 : /**
73 : * Specifies the default construction method.
74 : */
75 196024 : public CreationMethod? default_construction_method { get; private set; }
76 :
77 : /**
78 : * Specifies if 'const' should be emitted for input parameters
79 : * of this type.
80 : */
81 : public bool is_immutable {
82 205 : get {
83 205 : if (_is_immutable == null) {
84 109004 : _is_immutable = has_attribute ("Immutable");
85 : }
86 205 : return _is_immutable;
87 : }
88 0 : set {
89 0 : _is_immutable = value;
90 0 : set_attribute ("Immutable", value);
91 : }
92 : }
93 :
94 : public int width {
95 14 : get {
96 14 : if (_width == null) {
97 7 : if (is_integer_type ()) {
98 25752 : _width = get_attribute_integer ("IntegerType", "width", 32);
99 : } else {
100 2 : _width = get_attribute_integer ("FloatingType", "width", 32);
101 : }
102 : }
103 14 : return _width;
104 : }
105 0 : set {
106 0 : _width = value;
107 0 : if (is_integer_type ()) {
108 0 : set_attribute_integer ("IntegerType", "width", value);
109 : } else {
110 0 : set_attribute_integer ("FloatingType", "width", value);
111 : }
112 : }
113 : }
114 :
115 : public bool signed {
116 10 : get {
117 10 : if (_signed == null) {
118 5 : _signed = get_attribute_bool ("IntegerType", "signed", true);
119 : }
120 10 : return _signed;
121 : }
122 0 : set {
123 0 : _signed = value;
124 0 : set_attribute_bool ("IntegerType", "signed", value);
125 : }
126 : }
127 :
128 : /**
129 : * Specifies the rank of this integer or floating point type.
130 : */
131 : public int rank {
132 356514 : get {
133 356514 : if (_rank == null) {
134 12869 : if (is_integer_type () && has_attribute_argument ("IntegerType", "rank")) {
135 11407 : _rank = get_attribute_integer ("IntegerType", "rank");
136 1462 : } else if (has_attribute_argument ("FloatingType", "rank")) {
137 1441 : _rank = get_attribute_integer ("FloatingType", "rank");
138 : } else {
139 21 : var st = base_struct;
140 21 : if (st != null) {
141 21 : _rank = st.rank;
142 : } else {
143 0 : Report.error (source_reference, "internal error: struct has no rank");
144 0 : return 0;
145 : }
146 : }
147 : }
148 356514 : return _rank;
149 : }
150 0 : set {
151 0 : _rank = value;
152 0 : if (is_integer_type ()) {
153 0 : set_attribute_integer ("IntegerType", "rank", _rank);
154 : } else {
155 0 : set_attribute_integer ("FloatingType", "rank", _rank);
156 : }
157 : }
158 : }
159 :
160 : /**
161 : * Creates a new struct.
162 : *
163 : * @param name type name
164 : * @param source_reference reference to source code
165 : * @return newly created struct
166 : */
167 429987 : public Struct (string name, SourceReference? source_reference = null, Comment? comment = null) {
168 143329 : base (name, source_reference, comment);
169 : }
170 :
171 : /**
172 : * Appends the specified parameter to the list of type parameters.
173 : *
174 : * @param p a type parameter
175 : */
176 9178 : public void add_type_parameter (TypeParameter p) {
177 9178 : type_parameters.add (p);
178 9178 : scope.add (p.name, p);
179 : }
180 :
181 : /**
182 : * Returns the type parameter list.
183 : *
184 : * @return list of type parameters
185 : */
186 13726948 : public unowned List<TypeParameter> get_type_parameters () {
187 13726948 : return type_parameters;
188 : }
189 :
190 0 : public bool has_type_parameters () {
191 0 : return (type_parameters != null && type_parameters.size > 0);
192 : }
193 :
194 : /**
195 : * Adds the specified constant as a member to this struct.
196 : *
197 : * @param c a constant
198 : */
199 177430 : public override void add_constant (Constant c) {
200 177430 : constants.add (c);
201 177430 : scope.add (c.name, c);
202 : }
203 :
204 : /**
205 : * Adds the specified field as a member to this struct.
206 : *
207 : * @param f a field
208 : */
209 254165 : public override void add_field (Field f) {
210 254165 : f.access = SymbolAccessibility.PUBLIC;
211 :
212 254165 : fields.add (f);
213 254165 : scope.add (f.name, f);
214 : }
215 :
216 : /**
217 : * Returns the list of fields.
218 : *
219 : * @return list of fields
220 : */
221 8079 : public unowned List<Field> get_fields () {
222 8079 : return fields;
223 : }
224 :
225 : /**
226 : * Returns the list of constants.
227 : *
228 : * @return list of constants
229 : */
230 87 : public unowned List<Constant> get_constants () {
231 87 : return constants;
232 : }
233 :
234 : /**
235 : * Adds the specified method as a member to this struct.
236 : *
237 : * @param m a method
238 : */
239 819035 : public override void add_method (Method m) {
240 819035 : if (m.binding == MemberBinding.INSTANCE || m is CreationMethod) {
241 587861 : m.this_parameter = new Parameter ("this", SemanticAnalyzer.get_this_type (m, this), m.source_reference);
242 587861 : m.scope.add (m.this_parameter.name, m.this_parameter);
243 : }
244 819035 : if (!(m.return_type is VoidType) && m.get_postconditions ().size > 0) {
245 1 : m.result_var = new LocalVariable (m.return_type.copy (), "result", null, m.source_reference);
246 1 : m.result_var.is_result = true;
247 : }
248 848345 : if (m is CreationMethod) {
249 29311 : if (m.name == null) {
250 26185 : default_construction_method = (CreationMethod) m;
251 26185 : m.name = ".new";
252 : }
253 :
254 29311 : var cm = (CreationMethod) m;
255 29311 : if (cm.class_name != null && cm.class_name != name) {
256 : // type_name is null for constructors generated by GIdlParser
257 1 : Report.error (m.source_reference, "missing return type in method `%s.%s´", get_full_name (), cm.class_name);
258 1 : m.error = true;
259 1 : return;
260 : }
261 : }
262 :
263 819034 : methods.add (m);
264 819034 : scope.add (m.name, m);
265 : }
266 :
267 : /**
268 : * Returns the list of methods.
269 : *
270 : * @return list of methods
271 : */
272 87 : public unowned List<Method> get_methods () {
273 87 : return methods;
274 : }
275 :
276 : /**
277 : * Adds the specified property as a member to this struct.
278 : *
279 : * @param prop a property
280 : */
281 16 : public override void add_property (Property prop) {
282 16 : properties.add (prop);
283 16 : scope.add (prop.name, prop);
284 :
285 16 : if (prop.binding == MemberBinding.INSTANCE) {
286 11 : prop.this_parameter = new Parameter ("this", SemanticAnalyzer.get_this_type (prop, this), prop.source_reference);
287 11 : prop.scope.add (prop.this_parameter.name, prop.this_parameter);
288 : }
289 :
290 16 : if (prop.field != null) {
291 9 : add_field (prop.field);
292 9 : property_fields.add (prop.field);
293 : }
294 : }
295 :
296 : /**
297 : * Returns the list of properties.
298 : *
299 : * @return list of properties
300 : */
301 87 : public unowned List<Property> get_properties () {
302 87 : return properties;
303 : }
304 :
305 327139 : public override void accept (CodeVisitor visitor) {
306 327139 : visitor.visit_struct (this);
307 : }
308 :
309 316180 : public override void accept_children (CodeVisitor visitor) {
310 316180 : if (base_type != null) {
311 24869 : base_type.accept (visitor);
312 : }
313 :
314 356208 : foreach (TypeParameter p in type_parameters) {
315 20014 : p.accept (visitor);
316 : }
317 :
318 1452590 : foreach (Field f in fields) {
319 568205 : f.accept (visitor);
320 : }
321 :
322 1090068 : foreach (Constant c in constants) {
323 386944 : c.accept (visitor);
324 : }
325 :
326 3894906 : foreach (Method m in methods) {
327 1789363 : m.accept (visitor);
328 : }
329 :
330 316272 : foreach (Property prop in properties) {
331 46 : prop.accept (visitor);
332 : }
333 : }
334 :
335 : /**
336 : * Returns whether this is a boolean type.
337 : *
338 : * @return true if this is a boolean type, false otherwise
339 : */
340 17650 : public bool is_boolean_type () {
341 17650 : unowned Struct? st = base_struct;
342 17650 : if (st != null && st.is_boolean_type ()) {
343 17650 : return true;
344 : }
345 17645 : if (boolean_type == null) {
346 6063 : boolean_type = has_attribute ("BooleanType");
347 : }
348 17645 : return boolean_type;
349 : }
350 :
351 : /**
352 : * Returns whether this is an integer type.
353 : *
354 : * @return true if this is an integer type, false otherwise
355 : */
356 616979 : public bool is_integer_type () {
357 616979 : unowned Struct? st = base_struct;
358 616979 : if (st != null && st.is_integer_type ()) {
359 616979 : return true;
360 : }
361 616721 : if (integer_type == null) {
362 17484 : integer_type = has_attribute ("IntegerType");
363 : }
364 616721 : return integer_type;
365 : }
366 :
367 : /**
368 : * Returns whether this is a floating point type.
369 : *
370 : * @return true if this is a floating point type, false otherwise
371 : */
372 555421 : public bool is_floating_type () {
373 555421 : unowned Struct? st = base_struct;
374 555421 : if (st != null && st.is_floating_type ()) {
375 555421 : return true;
376 : }
377 555411 : if (floating_type == null) {
378 16015 : floating_type = has_attribute ("FloatingType");
379 : }
380 555411 : return floating_type;
381 : }
382 :
383 0 : public bool is_decimal_floating_type () {
384 0 : unowned Struct? st = base_struct;
385 0 : if (st != null && st.is_decimal_floating_type ()) {
386 0 : return true;
387 : }
388 0 : if (decimal_floating_type == null) {
389 0 : decimal_floating_type = get_attribute_bool ("FloatingType", "decimal");
390 : }
391 0 : return decimal_floating_type;
392 : }
393 :
394 2840 : public override int get_type_parameter_index (string name) {
395 2840 : int i = 0;
396 :
397 5670 : foreach (TypeParameter p in type_parameters) {
398 4255 : if (p.name == name) {
399 2840 : return (i);
400 : }
401 1415 : i++;
402 : }
403 :
404 2840 : return -1;
405 : }
406 :
407 : /**
408 : * Returns whether this struct is a simple type, i.e. whether
409 : * instances are passed by value.
410 : */
411 316656 : public bool is_simple_type () {
412 316656 : unowned Struct? st = base_struct;
413 316656 : if (st != null && st.is_simple_type ()) {
414 316656 : return true;
415 : }
416 310119 : if (simple_type == null) {
417 14897 : simple_type = has_attribute ("SimpleType") || has_attribute ("BooleanType") || has_attribute ("IntegerType") || has_attribute ("FloatingType");
418 : }
419 310119 : return simple_type;
420 : }
421 :
422 : /**
423 : * Marks this struct as simple type, i.e. instances will be passed by
424 : * value.
425 : */
426 2 : public void set_simple_type (bool simple_type) {
427 2 : this.simple_type = simple_type;
428 2 : set_attribute ("SimpleType", simple_type);
429 : }
430 :
431 10500 : public override void replace_type (DataType old_type, DataType new_type) {
432 10500 : if (base_type == old_type) {
433 10500 : base_type = new_type;
434 : }
435 : }
436 :
437 2464166 : public override bool is_subtype_of (TypeSymbol t) {
438 2464166 : if (this == t) {
439 : return true;
440 : }
441 :
442 1735049 : if (base_type != null) {
443 6285 : if (base_type.type_symbol != null && base_type.type_symbol.is_subtype_of (t)) {
444 : return true;
445 : }
446 : }
447 :
448 : return false;
449 : }
450 :
451 442704 : public bool is_disposable () {
452 442704 : if (has_attribute_argument ("CCode", "destroy_function")) {
453 21860 : return true;
454 : }
455 :
456 424816 : if (base_struct != null) {
457 20632 : return base_struct.is_disposable ();
458 : }
459 :
460 979420 : foreach (Field f in fields) {
461 856308 : if (f.binding == MemberBinding.INSTANCE
462 291533 : && f.get_attribute_bool ("CCode", "delegate_target", true)
463 273185 : && f.variable_type.is_disposable ()) {
464 3972 : if (is_simple_type ()) {
465 1 : error = true;
466 1 : Report.error (f.source_reference, "[SimpleType] struct `%s' cannot have owned heap-allocated fields", get_full_name ());
467 : }
468 3972 : return true;
469 : }
470 : }
471 :
472 422072 : return false;
473 : }
474 :
475 242270 : bool is_recursive_value_type (CodeContext context, DataType type) {
476 242270 : unowned StructValueType? struct_type = type as StructValueType;
477 5932 : if (struct_type != null && !struct_type.nullable) {
478 3094 : unowned Struct st = (Struct) struct_type.type_symbol;
479 3094 : if (st == this) {
480 3 : return true;
481 : }
482 3091 : if (!st.check (context)) {
483 242267 : return false;
484 : }
485 19478 : foreach (Field f in st.fields) {
486 8194 : if (f.binding == MemberBinding.INSTANCE && is_recursive_value_type (context, f.variable_type)) {
487 0 : return true;
488 : }
489 : }
490 : }
491 242270 : return false;
492 : }
493 :
494 12866072 : public override bool check (CodeContext context) {
495 12866072 : if (checked) {
496 12733040 : return !error;
497 : }
498 :
499 133032 : checked = true;
500 :
501 133032 : var old_source_file = context.analyzer.current_source_file;
502 133032 : var old_symbol = context.analyzer.current_symbol;
503 :
504 133032 : if (source_reference != null) {
505 133032 : context.analyzer.current_source_file = source_reference.file;
506 : }
507 133032 : context.analyzer.current_symbol = this;
508 :
509 133032 : if (base_type != null) {
510 10456 : base_type.check (context);
511 :
512 10456 : if (!(base_type is ValueType)) {
513 1 : error = true;
514 1 : Report.error (source_reference, "The base type `%s' of struct `%s' is not a struct", base_type.to_string (), get_full_name ());
515 1 : return false;
516 : }
517 :
518 : // check whether base type is at least as accessible as the struct
519 10455 : if (!base_type.is_accessible (this)) {
520 1 : error = true;
521 1 : Report.error (source_reference, "base type `%s' is less accessible than struct `%s'", base_type.to_string (), get_full_name ());
522 : }
523 : }
524 :
525 150019 : foreach (TypeParameter p in get_type_parameters ()) {
526 8494 : if (!p.check (context)) {
527 0 : error = true;
528 : }
529 : }
530 :
531 606913 : foreach (Field f in fields) {
532 236945 : f.check (context);
533 :
534 236945 : if (f.binding == MemberBinding.INSTANCE && is_recursive_value_type (context, f.variable_type)) {
535 3 : error = true;
536 3 : Report.error (f.source_reference, "Recursive value types are not allowed");
537 3 : return false;
538 : }
539 :
540 236942 : if (f.binding == MemberBinding.INSTANCE && f.initializer != null) {
541 1 : error = true;
542 1 : Report.error (f.source_reference, "Instance field initializers not supported");
543 1 : return false;
544 : }
545 :
546 236941 : if (f.binding == MemberBinding.STATIC && f.initializer != null) {
547 : // for backing property fields a dedicated error will be reported later
548 4 : if (!(f in property_fields) && !(f.initializer.value_type is NullType) && f.variable_type.is_disposable () && f.variable_type.value_owned) {
549 1 : error = true;
550 1 : Report.error (f.initializer.source_reference, "Owned static struct fields can only be initialized in a function or method");
551 : }
552 : }
553 : }
554 :
555 461439 : foreach (Constant c in constants) {
556 164206 : c.check (context);
557 : }
558 :
559 1649799 : foreach (Method m in methods) {
560 758386 : m.check (context);
561 : }
562 :
563 133059 : foreach (Property prop in properties) {
564 16 : prop.check (context);
565 :
566 16 : if (prop.binding == MemberBinding.STATIC) {
567 5 : unowned Field? field = prop.field;
568 5 : if (field != null && field.initializer != null && !(field.initializer.value_type is NullType) && field.variable_type.is_disposable () && field.variable_type.value_owned) {
569 1 : error = true;
570 1 : Report.error (field.initializer.source_reference, "Owned static struct properties can only be initialized in a function or method");
571 : }
572 : }
573 : }
574 :
575 : // FIXME Perform this [SimpleType] check in a better way
576 133027 : is_disposable ();
577 :
578 133027 : if (!external && !external_package) {
579 230 : bool has_instance_field = false;
580 236 : foreach (Field f in fields) {
581 184 : if (f.binding == MemberBinding.INSTANCE) {
582 181 : has_instance_field = true;
583 181 : break;
584 : }
585 : }
586 230 : if (base_type == null && !has_instance_field && !is_boolean_type () && !is_integer_type () && !is_floating_type ()) {
587 4 : error = true;
588 4 : Report.error (source_reference, "struct `%s' cannot be empty", get_full_name ());
589 226 : } else if (base_type != null && has_instance_field) {
590 1 : error = true;
591 1 : Report.error (source_reference, "derived struct `%s' may not have instance fields", get_full_name ());
592 : }
593 : }
594 :
595 133027 : context.analyzer.current_source_file = old_source_file;
596 133027 : context.analyzer.current_symbol = old_symbol;
597 :
598 133027 : return !error;
599 : }
600 : }
601 :
602 : // vim:sw=8 noet
|