valastruct.vala 12.9 KB
Newer Older
1 2
/* valastruct.vala
 *
3
 * Copyright (C) 2006-2010  Jürg Billeter
4 5 6 7
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * 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 11 12 13 14 15 16 17 18 19 20 21 22 23 24

 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 *
 * Author:
 * 	Jürg Billeter <j@bitron.ch>
 */

using GLib;

25 26 27
/**
 * Represents a struct declaration in the source code.
 */
28
public class Vala.Struct : TypeSymbol {
29 30 31 32 33
	private List<TypeParameter> type_parameters = new ArrayList<TypeParameter> ();
	private List<Constant> constants = new ArrayList<Constant> ();
	private List<Field> fields = new ArrayList<Field> ();
	private List<Method> methods = new ArrayList<Method> ();
	private List<Property> properties = new ArrayList<Property> ();
34
	private DataType _base_type = null;
35

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;
Luca Bruno's avatar
Luca Bruno committed
42
	private int? _width;
Luca Bruno's avatar
Luca Bruno committed
43
	private bool? _signed;
Luca Bruno's avatar
Luca Bruno committed
44
	private bool? _is_immutable;
45

46
	/**
47
	 * Specifies the base type.
48 49 50 51 52 53 54 55 56 57 58
	 */
	public DataType? base_type {
		get {
			return _base_type;
		}
		set {
			value.parent_node = this;
			_base_type = value;
		}
	}

59 60 61 62 63 64 65 66 67 68 69 70
	/**
	 * Specifies the base Struct.
	 */
	public Struct? base_struct {
		get {
			if (_base_type != null) {
				return _base_type.data_type as Struct;
			}
			return null;
		}
	}

71 72 73 74
	/**
	 * Specifies the default construction method.
	 */
	public Method default_construction_method { get; set; }
75

76 77 78 79
	/**
	 * Specifies if 'const' should be emitted for input parameters
	 * of this type.
	 */
80 81 82 83 84 85 86 87 88 89 90 91
	public bool is_immutable {
		get {
			if (_is_immutable == null) {
				_is_immutable = get_attribute ("Immutable") != null;
			}
			return _is_immutable;
		}
		set {
			_is_immutable = value;
			set_attribute ("Immutable", value);
		}
	}
92

Luca Bruno's avatar
Luca Bruno committed
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
	public int width {
		get {
			if (_width == null) {
				if (is_integer_type ()) {
					_width = get_attribute_integer ("IntegerType", "width", 32);
				} else {
					_width = get_attribute_integer ("FloatingType", "width", 32);
				}
			}
			return _width;
		}
		set {
			_width = value;
			if (is_integer_type ()) {
				set_attribute_integer ("IntegerType", "width", value);
			} else {
				set_attribute_integer ("FloatingType", "width", value);
			}
		}
	}
113

Luca Bruno's avatar
Luca Bruno committed
114 115 116 117 118 119 120 121 122 123 124 125
	public bool signed {
		get {
			if (_signed == null) {
				_signed = get_attribute_bool ("IntegerType", "signed", true);
			}
			return _signed;
		}
		set {
			_signed = value;
			set_attribute_bool ("IntegerType", "signed", value);
		}
	}
126

127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
	/**
	 * Specifies the rank of this integer or floating point type.
	 */
	public int rank {
		get {
			if (_rank == null) {
				if (is_integer_type () && has_attribute_argument ("IntegerType", "rank")) {
					_rank = get_attribute_integer ("IntegerType", "rank");
				} else if (has_attribute_argument ("FloatingType", "rank")) {
					_rank = get_attribute_integer ("FloatingType", "rank");
				} else {
					var st = base_struct;
					if (st != null) {
						_rank = st.rank;
					} else {
						Report.error (source_reference, "internal error: struct has no rank");
143
						return 0;
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
					}
				}
			}
			return _rank;
		}
		set {
			_rank = value;
			if (is_integer_type ()) {
				set_attribute_integer ("IntegerType", "rank", _rank);
			} else {
				set_attribute_integer ("FloatingType", "rank", _rank);
			}
		}
	}

159 160 161
	/**
	 * Creates a new struct.
	 *
162 163 164
	 * @param name             type name
	 * @param source_reference reference to source code
	 * @return                 newly created struct
165
	 */
166 167
	public Struct (string name, SourceReference? source_reference = null, Comment? comment = null) {
		base (name, source_reference, comment);
168
	}
169

170 171 172 173 174
	/**
	 * Appends the specified parameter to the list of type parameters.
	 *
	 * @param p a type parameter
	 */
175
	public void add_type_parameter (TypeParameter p) {
176
		type_parameters.add (p);
177
		scope.add (p.name, p);
178
	}
179

180 181 182 183 184
	/**
	 * Returns a copy of the type parameter list.
	 *
	 * @return list of type parameters
	 */
185
	public List<TypeParameter> get_type_parameters () {
186
		return type_parameters;
187 188
	}

189 190 191 192 193
	/**
	 * Adds the specified constant as a member to this struct.
	 *
	 * @param c a constant
	 */
194
	public override void add_constant (Constant c) {
195
		constants.add (c);
196
		scope.add (c.name, c);
197
	}
198

199 200 201 202 203
	/**
	 * Adds the specified field as a member to this struct.
	 *
	 * @param f a field
	 */
204
	public override void add_field (Field f) {
205 206
		f.access = SymbolAccessibility.PUBLIC;

207
		fields.add (f);
208
		scope.add (f.name, f);
209
	}
210

211 212 213 214 215
	/**
	 * Returns a copy of the list of fields.
	 *
	 * @return list of fields
	 */
216
	public List<Field> get_fields () {
217
		return fields;
218
	}
219 220 221 222 223 224

	/**
	 * Returns a copy of the list of constants.
	 *
	 * @return list of constants
	 */
225
	public List<Constant> get_constants () {
226
		return constants;
227 228
	}

229 230 231 232 233
	/**
	 * Adds the specified method as a member to this struct.
	 *
	 * @param m a method
	 */
234
	public override void add_method (Method m) {
235
		return_if_fail (m != null);
236

237
		if (m.binding == MemberBinding.INSTANCE || m is CreationMethod) {
238
			m.this_parameter = new Parameter ("this", SemanticAnalyzer.get_data_type_for_symbol (this));
239 240
			m.scope.add (m.this_parameter.name, m.this_parameter);
		}
Jürg Billeter's avatar
Jürg Billeter committed
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;
244
		}
245 246 247
		if (m is CreationMethod) {
			if (m.name == null) {
				default_construction_method = m;
248
				m.name = ".new";
249
			}
250 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 256 257
				m.error = true;
				return;
			}
258 259
		}

260
		methods.add (m);
261
		scope.add (m.name, m);
262
	}
263

264 265 266 267 268
	/**
	 * Returns a copy of the list of methods.
	 *
	 * @return list of methods
	 */
269
	public List<Method> get_methods () {
270
		return methods;
271
	}
272

273 274 275 276 277
	/**
	 * Adds the specified property as a member to this struct.
	 *
	 * @param prop a property
	 */
278
	public override void add_property (Property prop) {
279 280 281
		properties.add (prop);
		scope.add (prop.name, prop);

282
		prop.this_parameter = new Parameter ("this", SemanticAnalyzer.get_data_type_for_symbol (this));
283 284 285 286 287 288 289 290 291 292 293 294
		prop.scope.add (prop.this_parameter.name, prop.this_parameter);

		if (prop.field != null) {
			add_field (prop.field);
		}
	}

	/**
	 * Returns a copy of the list of properties.
	 *
	 * @return list of properties
	 */
295
	public List<Property> get_properties () {
296
		return properties;
297 298
	}

299
	public override void accept (CodeVisitor visitor) {
300 301 302
		visitor.visit_struct (this);
	}

303
	public override void accept_children (CodeVisitor visitor) {
304 305
		if (base_type != null) {
			base_type.accept (visitor);
306 307
		}

308 309
		foreach (TypeParameter p in type_parameters) {
			p.accept (visitor);
310
		}
311

312 313
		foreach (Field f in fields) {
			f.accept (visitor);
314
		}
315

316 317
		foreach (Constant c in constants) {
			c.accept (visitor);
318
		}
319

320 321
		foreach (Method m in methods) {
			m.accept (visitor);
322
		}
323 324 325 326

		foreach (Property prop in properties) {
			prop.accept (visitor);
		}
327
	}
328

329 330 331 332 333 334
	/**
	 * Returns whether this is a boolean type.
	 *
	 * @return true if this is a boolean type, false otherwise
	 */
	public bool is_boolean_type () {
335 336 337 338 339 340
		var st = base_struct;
		if (st != null && st.is_boolean_type ()) {
			return true;
		}
		if (boolean_type == null) {
			boolean_type = get_attribute ("BooleanType") != null;
341 342 343 344
		}
		return boolean_type;
	}

345 346 347 348 349 350
	/**
	 * Returns whether this is an integer type.
	 *
	 * @return true if this is an integer type, false otherwise
	 */
	public bool is_integer_type () {
351 352 353 354 355 356
		var st = base_struct;
		if (st != null && st.is_integer_type ()) {
			return true;
		}
		if (integer_type == null) {
			integer_type = get_attribute ("IntegerType") != null;
357
		}
358 359
		return integer_type;
	}
360

361 362 363 364 365 366
	/**
	 * Returns whether this is a floating point type.
	 *
	 * @return true if this is a floating point type, false otherwise
	 */
	public bool is_floating_type () {
367 368 369 370 371 372
		var st = base_struct;
		if (st != null && st.is_floating_type ()) {
			return true;
		}
		if (floating_type == null) {
			floating_type = get_attribute ("FloatingType") != null;
373
		}
374 375
		return floating_type;
	}
376 377

	public bool is_decimal_floating_type () {
378 379 380 381 382 383
		var st = base_struct;
		if (st != null && st.is_decimal_floating_type ()) {
			return true;
		}
		if (decimal_floating_type == null) {
			decimal_floating_type = get_attribute_bool ("FloatingType", "decimal");
384 385 386 387
		}
		return decimal_floating_type;
	}

388
	public override int get_type_parameter_index (string name) {
389
		int i = 0;
390

391 392 393 394 395 396
		foreach (TypeParameter p in type_parameters) {
			if (p.name == name) {
				return (i);
			}
			i++;
		}
397

398 399
		return -1;
	}
400 401 402 403 404 405

	/**
	 * Returns whether this struct is a simple type, i.e. whether
	 * instances are passed by value.
	 */
	public bool is_simple_type () {
406 407 408 409 410 411 412 413
		var st = base_struct;
		if (st != null && st.is_simple_type ()) {
			return true;
		}
		if (simple_type == null) {
			simple_type = get_attribute ("SimpleType") != null || get_attribute ("BooleanType") != null || get_attribute ("IntegerType") != null || get_attribute ("FloatingType") != null;
		}
		return simple_type;
414
	}
415

416 417 418 419 420
	/**
	 * Marks this struct as simple type, i.e. instances will be passed by
	 * value.
	 */
	public void set_simple_type (bool simple_type) {
421 422
		this.simple_type = simple_type;
		set_attribute ("SimpleType", simple_type);
423 424
	}

425
	public override void replace_type (DataType old_type, DataType new_type) {
426 427
		if (base_type == old_type) {
			base_type = new_type;
428 429
		}
	}
430 431 432 433 434 435

	public override bool is_subtype_of (TypeSymbol t) {
		if (this == t) {
			return true;
		}

436
		if (base_type != null) {
437 438 439 440
			if (base_type.data_type != null && base_type.data_type.is_subtype_of (t)) {
				return true;
			}
		}
441

442 443
		return false;
	}
444 445

	public bool is_disposable () {
446
		if (get_attribute_string ("CCode", "destroy_function") != null) {
447 448 449 450 451
			return true;
		}

		foreach (Field f in fields) {
			if (f.binding == MemberBinding.INSTANCE
452
			    && f.get_attribute_bool ("CCode", "delegate_target", true)
Jürg Billeter's avatar
Jürg Billeter committed
453
			    && f.variable_type.is_disposable ()) {
454 455 456 457 458 459
				return true;
			}
		}

		return false;
	}
460

461 462
	bool is_recursive_value_type (DataType type) {
		var struct_type = type as StructValueType;
463
		if (struct_type != null && !struct_type.nullable) {
464 465 466 467 468
			var st = (Struct) struct_type.type_symbol;
			if (st == this) {
				return true;
			}
			foreach (Field f in st.fields) {
Jürg Billeter's avatar
Jürg Billeter committed
469
				if (f.binding == MemberBinding.INSTANCE && is_recursive_value_type (f.variable_type)) {
470 471 472 473 474 475 476
					return true;
				}
			}
		}
		return false;
	}

477
	public override bool check (CodeContext context) {
478 479 480 481 482 483
		if (checked) {
			return !error;
		}

		checked = true;

484 485
		var old_source_file = context.analyzer.current_source_file;
		var old_symbol = context.analyzer.current_symbol;
486 487

		if (source_reference != null) {
488
			context.analyzer.current_source_file = source_reference.file;
489
		}
490
		context.analyzer.current_symbol = this;
491

492
		if (base_type != null) {
493
			base_type.check (context);
494

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 499
				return false;
			}
500 501 502
		}

		foreach (TypeParameter p in type_parameters) {
503
			p.check (context);
504
		}
505

506
		foreach (Field f in fields) {
507
			f.check (context);
508

Jürg Billeter's avatar
Jürg Billeter committed
509
			if (f.binding == MemberBinding.INSTANCE && is_recursive_value_type (f.variable_type)) {
510 511 512 513
				error = true;
				Report.error (f.source_reference, "Recursive value types are not allowed");
				return false;
			}
514 515 516 517 518 519

			if (f.binding == MemberBinding.INSTANCE && f.initializer != null) {
				error = true;
				Report.error (f.source_reference, "Instance field initializers not supported");
				return false;
			}
520
		}
521

522
		foreach (Constant c in constants) {
523
			c.check (context);
524
		}
525

526
		foreach (Method m in methods) {
527
			m.check (context);
528
		}
529

530
		foreach (Property prop in properties) {
531
			prop.check (context);
532 533
		}

534 535 536 537 538 539 540 541 542 543 544 545 546
		if (!external && !external_package) {
			if (base_type == null && get_fields ().size == 0 && !is_boolean_type () && !is_integer_type () && !is_floating_type ()) {
				error = true;
				Report.error (source_reference, "structs cannot be empty: %s".printf(name));
			} else if (base_type != null) {
				foreach (Field f in fields) {
					if (f.binding == MemberBinding.INSTANCE) {
						error = true;
						Report.error (source_reference, "derived structs may not have instance fields");
						break;
					}
				}
			}
547 548
		}

549 550
		context.analyzer.current_source_file = old_source_file;
		context.analyzer.current_symbol = old_symbol;
551 552 553

		return !error;
	}
554
}
555 556

// vim:sw=8 noet