valainterface.vala 9.68 KB
Newer Older
1 2
/* valainterface.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 class declaration in the source code.
 */
28
public class Vala.Interface : ObjectTypeSymbol {
29
	private List<DataType> prerequisites = new ArrayList<DataType> ();
30

31
	private List<Symbol> virtuals = new ArrayList<Symbol> ();
32

33 34 35
	/**
	 * Creates a new interface.
	 *
36 37 38
	 * @param name              type name
	 * @param source_reference  reference to source code
	 * @return                  newly created interface
39
	 */
40 41
	public Interface (string name, SourceReference? source_reference = null, Comment? comment = null) {
		base (name, source_reference, comment);
42
	}
43

44
	/**
45 46
	 * Adds the specified interface or class to the list of prerequisites of
	 * this interface.
47
	 *
48
	 * @param type an interface or class reference
49
	 */
50
	public void add_prerequisite (DataType type) {
51 52
		prerequisites.add (type);
		type.parent_node = this;
53
	}
54 55 56 57 58 59

	/**
	 * Returns a copy of the base type list.
	 *
	 * @return list of base types
	 */
60
	public List<DataType> get_prerequisites () {
61
		return prerequisites;
62
	}
63

64 65 66 67 68
	/**
	 * Adds the specified method as a member to this interface.
	 *
	 * @param m a method
	 */
69
	public override void add_method (Method m) {
70 71
		if (m is CreationMethod) {
			Report.error (m.source_reference, "construction methods may only be declared within classes and structs");
72

73 74 75
			m.error = true;
			return;
		}
76
		if (m.binding == MemberBinding.INSTANCE) {
77
			m.this_parameter = new Parameter ("this", get_this_type ());
78 79
			m.scope.add (m.this_parameter.name, m.this_parameter);
		}
Jürg Billeter's avatar
Jürg Billeter committed
80
		if (!(m.return_type is VoidType) && m.get_postconditions ().size > 0) {
81
			m.result_var = new LocalVariable (m.return_type.copy (), "result", null, source_reference);
82
			m.result_var.is_result = true;
83
		}
84

85
		base.add_method (m);
86 87
	}

88 89 90 91 92
	/**
	 * Adds the specified property as a member to this interface.
	 *
	 * @param prop a property
	 */
93
	public override void add_property (Property prop) {
94 95 96 97 98 99 100
		if (prop.field != null) {
			Report.error (prop.source_reference, "automatic properties are not allowed in interfaces");

			prop.error = true;
			return;
		}

101
		base.add_property (prop);
102

103
		prop.this_parameter = new Parameter ("this", new ObjectType (this));
104
		prop.scope.add (prop.this_parameter.name, prop.this_parameter);
105
	}
106

107 108 109 110
	public virtual List<Symbol> get_virtuals () {
		return virtuals;
	}

111
	public override void accept (CodeVisitor visitor) {
112 113 114
		visitor.visit_interface (this);
	}

115
	public override void accept_children (CodeVisitor visitor) {
116
		foreach (DataType type in prerequisites) {
117
			type.accept (visitor);
118
		}
119

120
		foreach (TypeParameter p in get_type_parameters ()) {
121
			p.accept (visitor);
122
		}
123 124

		/* process enums first to avoid order problems in C code */
125
		foreach (Enum en in get_enums ()) {
126 127 128
			en.accept (visitor);
		}

129
		foreach (Method m in get_methods ()) {
130
			m.accept (visitor);
131
		}
132

133
		foreach (Field f in get_fields ()) {
134 135
			f.accept (visitor);
		}
136

137
		foreach (Constant c in get_constants ()) {
138 139 140
			c.accept (visitor);
		}

141
		foreach (Property prop in get_properties ()) {
142
			prop.accept (visitor);
143
		}
144

145
		foreach (Signal sig in get_signals ()) {
146 147
			sig.accept (visitor);
		}
148

149
		foreach (Class cl in get_classes ()) {
150 151
			cl.accept (visitor);
		}
152

153
		foreach (Struct st in get_structs ()) {
154 155 156
			st.accept (visitor);
		}

157
		foreach (Delegate d in get_delegates ()) {
Jürg Billeter's avatar
Jürg Billeter committed
158 159
			d.accept (visitor);
		}
160
	}
161

162 163 164
	public override bool is_reference_type () {
		return true;
	}
165

166
	public override bool is_subtype_of (TypeSymbol t) {
167 168 169 170
		if (this == t) {
			return true;
		}

171
		foreach (DataType prerequisite in prerequisites) {
Jürg Billeter's avatar
Jürg Billeter committed
172
			if (prerequisite.data_type != null && prerequisite.data_type.is_subtype_of (t)) {
173 174 175
				return true;
			}
		}
176

177 178
		return false;
	}
179

180
	public override void replace_type (DataType old_type, DataType new_type) {
181 182 183
		for (int i = 0; i < prerequisites.size; i++) {
			if (prerequisites[i] == old_type) {
				prerequisites[i] = new_type;
184
				new_type.parent_node = this;
185 186 187 188
				return;
			}
		}
	}
189

190
	public override bool check (CodeContext context) {
191 192 193 194 195 196
		if (checked) {
			return !error;
		}

		checked = true;

197 198
		var old_source_file = context.analyzer.current_source_file;
		var old_symbol = context.analyzer.current_symbol;
199 200

		if (source_reference != null) {
201
			context.analyzer.current_source_file = source_reference.file;
202
		}
203
		context.analyzer.current_symbol = this;
204 205 206

		foreach (DataType prerequisite_reference in get_prerequisites ()) {
			// check whether prerequisite is at least as accessible as the interface
207
			if (!context.analyzer.is_type_accessible (this, prerequisite_reference)) {
208 209 210 211 212 213 214
				error = true;
				Report.error (source_reference, "prerequisite `%s` is less accessible than interface `%s`".printf (prerequisite_reference.to_string (), get_full_name ()));
				return false;
			}
		}

		/* check prerequisites */
215
		Class prereq_class = null;
216 217 218 219 220 221 222
		foreach (DataType prereq in get_prerequisites ()) {
			TypeSymbol class_or_interface = prereq.data_type;
			/* skip on previous errors */
			if (class_or_interface == null) {
				error = true;
				continue;
			}
223 224 225 226 227 228 229

			if (!(class_or_interface is ObjectTypeSymbol)) {
				error = true;
				Report.error (source_reference, "Prerequisite `%s` of interface `%s` is not a class or interface".printf (get_full_name (), class_or_interface.to_string ()));
				return false;
			}

230 231 232 233 234 235 236 237 238 239 240 241
			/* interfaces are not allowed to have multiple instantiable prerequisites */
			if (class_or_interface is Class) {
				if (prereq_class != null) {
					error = true;
					Report.error (source_reference, "%s: Interfaces cannot have multiple instantiable prerequisites (`%s' and `%s')".printf (get_full_name (), class_or_interface.get_full_name (), prereq_class.get_full_name ()));
					return false;
				}

				prereq_class = (Class) class_or_interface;
			}
		}

242
		foreach (DataType type in prerequisites) {
243
			type.check (context);
244 245
		}

246
		foreach (TypeParameter p in get_type_parameters ()) {
247
			p.check (context);
248 249
		}

250
		foreach (Enum en in get_enums ()) {
251
			en.check (context);
252 253
		}

254
		foreach (Field f in get_fields ()) {
255
			f.check (context);
256
		}
257

258
		foreach (Constant c in get_constants ()) {
259
			c.check (context);
260 261
		}

262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
		if (context.abi_stability) {
			foreach (Symbol s in get_members ()) {
				if (s is Method) {
					var m = (Method) s;
					m.check (context);
					if (m.is_virtual || m.is_abstract) {
						virtuals.add (m);
					}
				} else if (s is Signal) {
					var sig = (Signal) s;
					sig.check (context);
					if (sig.is_virtual) {
						virtuals.add (sig);
					}
				} else if (s is Property) {
					var prop = (Property) s;
					prop.check (context);
					if (prop.is_virtual || prop.is_abstract) {
						virtuals.add (prop);
					}
				}
			}
		} else {
			foreach (Method m in get_methods ()) {
				m.check (context);
				if (m.is_virtual || m.is_abstract) {
					virtuals.add (m);
				}
290 291
			}

292 293 294 295 296 297 298 299 300 301 302 303
			foreach (Signal sig in get_signals ()) {
				sig.check (context);
				if (sig.is_virtual) {
					virtuals.add (sig);
				}
			}

			foreach (Property prop in get_properties ()) {
				prop.check (context);
				if (prop.is_virtual || prop.is_abstract) {
					virtuals.add (prop);
				}
304 305 306
			}
		}

307
		foreach (Class cl in get_classes ()) {
308
			cl.check (context);
309
		}
310

311
		foreach (Struct st in get_structs ()) {
312
			st.check (context);
313 314
		}

315
		foreach (Delegate d in get_delegates ()) {
316
			d.check (context);
317
		}
318

319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
		Map<int, Symbol>? positions = new HashMap<int, Symbol> ();
		bool ordered_seen = false;
		bool unordered_seen = false;
		foreach (Symbol sym in virtuals) {
			int ordering = sym.get_attribute_integer ("CCode", "ordering", -1);
			if (ordering < -1) {
				Report.error (sym.source_reference, "%s: Invalid ordering".printf (sym.get_full_name ()));
				// Mark state as invalid
				error = true;
				ordered_seen = true;
				unordered_seen = true;
				continue;
			}
			bool ordered = ordering != -1;
			if (ordered && unordered_seen && !ordered_seen) {
				Report.error (sym.source_reference, "%s: Cannot mix ordered and unordered virtuals".printf (sym.get_full_name ()));
				error = true;
			}
			ordered_seen = ordered_seen || ordered;
			if (!ordered && !unordered_seen && ordered_seen) {
				Report.error (sym.source_reference, "%s: Cannot mix ordered and unordered virtuals".printf (sym.get_full_name ()));
				error = true;
			}
			unordered_seen = unordered_seen || !ordered;
			if (!ordered_seen || !unordered_seen) {
				if (ordered) {
					Symbol? prev = positions[ordering];
					if (prev != null) {
						Report.error (sym.source_reference, "%s: Duplicate ordering (previous virtual with the same position is %s)".printf (sym.get_full_name (), prev.name));
						error = true;
					}
					positions[ordering] = sym;
				}
			}
		}
		if (ordered_seen) {
			for (int i = 0; i < virtuals.size; i++) {
				Symbol? sym = positions[i];
				if (sym == null) {
					Report.error (source_reference, "%s: Gap in ordering in position %d".printf (get_full_name (), i));
					error = true;
				}
				if (!error) {
					virtuals[i] = sym;
				}
			}
		}

367 368
		context.analyzer.current_source_file = old_source_file;
		context.analyzer.current_symbol = old_symbol;
369 370 371

		return !error;
	}
372
}