valac: Always use the given "pkg-config" and respect PKG_CONFIG envar
[vala-gnome.git] / vala / valainterface.vala
blob621c6e8ce16c050f5193f3ba475d54a7a2b3f1f8
1 /* valainterface.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 class declaration in the source code.
28 public class Vala.Interface : ObjectTypeSymbol {
29 private List<DataType> prerequisites = new ArrayList<DataType> ();
31 private List<Method> methods = new ArrayList<Method> ();
32 private List<Field> fields = new ArrayList<Field> ();
33 private List<Constant> constants = new ArrayList<Constant> ();
34 private List<Property> properties = new ArrayList<Property> ();
35 private List<Signal> signals = new ArrayList<Signal> ();
36 private List<Symbol> virtuals = new ArrayList<Symbol> ();
38 // inner types
39 private List<Class> classes = new ArrayList<Class> ();
40 private List<Struct> structs = new ArrayList<Struct> ();
41 private List<Enum> enums = new ArrayList<Enum> ();
42 private List<Delegate> delegates = new ArrayList<Delegate> ();
44 /**
45 * Returns a copy of the list of classes.
47 * @return list of classes
49 public List<Class> get_classes () {
50 return classes;
53 /**
54 * Returns a copy of the list of structs.
56 * @return list of structs
58 public List<Struct> get_structs () {
59 return structs;
62 /**
63 * Returns a copy of the list of enums.
65 * @return list of enums
67 public List<Enum> get_enums () {
68 return enums;
71 /**
72 * Returns a copy of the list of delegates.
74 * @return list of delegates
76 public List<Delegate> get_delegates () {
77 return delegates;
80 /**
81 * Creates a new interface.
83 * @param name type name
84 * @param source_reference reference to source code
85 * @return newly created interface
87 public Interface (string name, SourceReference? source_reference = null, Comment? comment = null) {
88 base (name, source_reference, comment);
91 /**
92 * Adds the specified interface or class to the list of prerequisites of
93 * this interface.
95 * @param type an interface or class reference
97 public void add_prerequisite (DataType type) {
98 prerequisites.add (type);
99 type.parent_node = this;
103 * Prepends the specified interface or class to the list of
104 * prerequisites of this interface.
106 * @param type an interface or class reference
108 public void prepend_prerequisite (DataType type) {
109 prerequisites.insert (0, type);
113 * Returns a copy of the base type list.
115 * @return list of base types
117 public List<DataType> get_prerequisites () {
118 return prerequisites;
122 * Adds the specified method as a member to this interface.
124 * @param m a method
126 public override void add_method (Method m) {
127 if (m is CreationMethod) {
128 Report.error (m.source_reference, "construction methods may only be declared within classes and structs");
130 m.error = true;
131 return;
133 if (m.binding == MemberBinding.INSTANCE) {
134 m.this_parameter = new Parameter ("this", get_this_type ());
135 m.scope.add (m.this_parameter.name, m.this_parameter);
137 if (!(m.return_type is VoidType) && m.get_postconditions ().size > 0) {
138 m.result_var = new LocalVariable (m.return_type.copy (), "result", null, source_reference);
139 m.result_var.is_result = true;
142 methods.add (m);
143 scope.add (m.name, m);
147 * Returns a copy of the list of methods.
149 * @return list of methods
151 public override List<Method> get_methods () {
152 return methods;
156 * Adds the specified field as a member to this interface. The field
157 * must be private and static.
159 * @param f a field
161 public override void add_field (Field f) {
162 fields.add (f);
163 scope.add (f.name, f);
167 * Returns a copy of the list of fields.
169 * @return list of fields
171 public List<Field> get_fields () {
172 return fields;
176 * Adds the specified constant as a member to this interface.
178 * @param c a constant
180 public override void add_constant (Constant c) {
181 constants.add (c);
182 scope.add (c.name, c);
186 * Returns a copy of the list of constants.
188 * @return list of constants
190 public List<Constant> get_constants () {
191 return constants;
195 * Adds the specified property as a member to this interface.
197 * @param prop a property
199 public override void add_property (Property prop) {
200 if (prop.field != null) {
201 Report.error (prop.source_reference, "automatic properties are not allowed in interfaces");
203 prop.error = true;
204 return;
207 properties.add (prop);
208 scope.add (prop.name, prop);
210 prop.this_parameter = new Parameter ("this", new ObjectType (this));
211 prop.scope.add (prop.this_parameter.name, prop.this_parameter);
215 * Returns a copy of the list of properties.
217 * @return list of properties
219 public override List<Property> get_properties () {
220 return properties;
224 * Adds the specified signal as a member to this interface.
226 * @param sig a signal
228 public override void add_signal (Signal sig) {
229 signals.add (sig);
230 scope.add (sig.name, sig);
234 * Returns a copy of the list of signals.
236 * @return list of signals
238 public override List<Signal> get_signals () {
239 return signals;
242 public virtual List<Symbol> get_virtuals () {
243 return virtuals;
247 * Adds the specified class as an inner class.
249 * @param cl a class
251 public override void add_class (Class cl) {
252 classes.add (cl);
253 scope.add (cl.name, cl);
257 * Adds the specified struct as an inner struct.
259 * @param st a struct
261 public override void add_struct (Struct st) {
262 structs.add (st);
263 scope.add (st.name, st);
267 * Adds the specified enum as an inner enum.
269 * @param en an enum
271 public override void add_enum (Enum en) {
272 enums.add (en);
273 scope.add (en.name, en);
277 * Adds the specified delegate as an inner delegate.
279 * @param d a delegate
281 public override void add_delegate (Delegate d) {
282 delegates.add (d);
283 scope.add (d.name, d);
286 public override void accept (CodeVisitor visitor) {
287 visitor.visit_interface (this);
290 public override void accept_children (CodeVisitor visitor) {
291 foreach (DataType type in prerequisites) {
292 type.accept (visitor);
295 foreach (TypeParameter p in get_type_parameters ()) {
296 p.accept (visitor);
299 /* process enums first to avoid order problems in C code */
300 foreach (Enum en in enums) {
301 en.accept (visitor);
304 foreach (Method m in methods) {
305 m.accept (visitor);
308 foreach (Field f in fields) {
309 f.accept (visitor);
312 foreach (Constant c in constants) {
313 c.accept (visitor);
316 foreach (Property prop in properties) {
317 prop.accept (visitor);
320 foreach (Signal sig in signals) {
321 sig.accept (visitor);
324 foreach (Class cl in classes) {
325 cl.accept (visitor);
328 foreach (Struct st in structs) {
329 st.accept (visitor);
332 foreach (Delegate d in delegates) {
333 d.accept (visitor);
337 public override bool is_reference_type () {
338 return true;
341 public override bool is_subtype_of (TypeSymbol t) {
342 if (this == t) {
343 return true;
346 foreach (DataType prerequisite in prerequisites) {
347 if (prerequisite.data_type != null && prerequisite.data_type.is_subtype_of (t)) {
348 return true;
352 return false;
355 public override void replace_type (DataType old_type, DataType new_type) {
356 for (int i = 0; i < prerequisites.size; i++) {
357 if (prerequisites[i] == old_type) {
358 prerequisites[i] = new_type;
359 new_type.parent_node = this;
360 return;
365 public override bool check (CodeContext context) {
366 if (checked) {
367 return !error;
370 checked = true;
372 var old_source_file = context.analyzer.current_source_file;
373 var old_symbol = context.analyzer.current_symbol;
375 if (source_reference != null) {
376 context.analyzer.current_source_file = source_reference.file;
378 context.analyzer.current_symbol = this;
380 foreach (DataType prerequisite_reference in get_prerequisites ()) {
381 // check whether prerequisite is at least as accessible as the interface
382 if (!context.analyzer.is_type_accessible (this, prerequisite_reference)) {
383 error = true;
384 Report.error (source_reference, "prerequisite `%s` is less accessible than interface `%s`".printf (prerequisite_reference.to_string (), get_full_name ()));
385 return false;
389 /* check prerequisites */
390 Class prereq_class = null;
391 foreach (DataType prereq in get_prerequisites ()) {
392 TypeSymbol class_or_interface = prereq.data_type;
393 /* skip on previous errors */
394 if (class_or_interface == null) {
395 error = true;
396 continue;
399 if (!(class_or_interface is ObjectTypeSymbol)) {
400 error = true;
401 Report.error (source_reference, "Prerequisite `%s` of interface `%s` is not a class or interface".printf (get_full_name (), class_or_interface.to_string ()));
402 return false;
405 /* interfaces are not allowed to have multiple instantiable prerequisites */
406 if (class_or_interface is Class) {
407 if (prereq_class != null) {
408 error = true;
409 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 ()));
410 return false;
413 prereq_class = (Class) class_or_interface;
417 foreach (DataType type in prerequisites) {
418 type.check (context);
421 foreach (TypeParameter p in get_type_parameters ()) {
422 p.check (context);
425 foreach (Enum en in enums) {
426 en.check (context);
429 foreach (Method m in methods) {
430 m.check (context);
431 if (m.is_virtual || m.is_abstract) {
432 virtuals.add (m);
436 foreach (Field f in fields) {
437 f.check (context);
440 foreach (Constant c in constants) {
441 c.check (context);
444 foreach (Signal sig in signals) {
445 sig.check (context);
446 if (sig.is_virtual) {
447 virtuals.add (sig);
451 foreach (Property prop in properties) {
452 prop.check (context);
453 if (prop.is_virtual || prop.is_abstract) {
454 virtuals.add (prop);
458 foreach (Class cl in classes) {
459 cl.check (context);
462 foreach (Struct st in structs) {
463 st.check (context);
466 foreach (Delegate d in delegates) {
467 d.check (context);
470 Map<int, Symbol>? positions = new HashMap<int, Symbol> ();
471 bool ordered_seen = false;
472 bool unordered_seen = false;
473 foreach (Symbol sym in virtuals) {
474 int ordering = sym.get_attribute_integer ("CCode", "ordering", -1);
475 if (ordering < -1) {
476 Report.error (sym.source_reference, "%s: Invalid ordering".printf (sym.get_full_name ()));
477 // Mark state as invalid
478 error = true;
479 ordered_seen = true;
480 unordered_seen = true;
481 continue;
483 bool ordered = ordering != -1;
484 if (ordered && unordered_seen && !ordered_seen) {
485 Report.error (sym.source_reference, "%s: Cannot mix ordered and unordered virtuals".printf (sym.get_full_name ()));
486 error = true;
488 ordered_seen = ordered_seen || ordered;
489 if (!ordered && !unordered_seen && ordered_seen) {
490 Report.error (sym.source_reference, "%s: Cannot mix ordered and unordered virtuals".printf (sym.get_full_name ()));
491 error = true;
493 unordered_seen = unordered_seen || !ordered;
494 if (!ordered_seen || !unordered_seen) {
495 if (ordered) {
496 Symbol? prev = positions[ordering];
497 if (prev != null) {
498 Report.error (sym.source_reference, "%s: Duplicate ordering (previous virtual with the same position is %s)".printf (sym.get_full_name (), prev.name));
499 error = true;
501 positions[ordering] = sym;
505 if (ordered_seen) {
506 for (int i = 0; i < virtuals.size; i++) {
507 Symbol? sym = positions[i];
508 if (sym == null) {
509 Report.error (source_reference, "%s: Gap in ordering in position %d".printf (get_full_name (), i));
510 error = true;
512 if (!error) {
513 virtuals[i] = sym;
518 context.analyzer.current_source_file = old_source_file;
519 context.analyzer.current_symbol = old_symbol;
521 return !error;