Support constructor chain up to GObject using Object (...)
[vala-lang.git] / vala / valainterface.vala
blob15387365eaa8572518c66b791ca6b1e2bc3d10a0
1 /* valainterface.vala
3 * Copyright (C) 2006-2009 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> ();
37 // inner types
38 private List<Class> classes = new ArrayList<Class> ();
39 private List<Struct> structs = new ArrayList<Struct> ();
40 private List<Enum> enums = new ArrayList<Enum> ();
41 private List<Delegate> delegates = new ArrayList<Delegate> ();
43 private string cname;
44 private string lower_case_csuffix;
45 private string type_cname;
46 private string type_id;
48 /**
49 * Returns a copy of the list of classes.
51 * @return list of classes
53 public List<Class> get_classes () {
54 return new ReadOnlyList<Class> (classes);
57 /**
58 * Returns a copy of the list of structs.
60 * @return list of structs
62 public List<Struct> get_structs () {
63 return new ReadOnlyList<Struct> (structs);
66 /**
67 * Returns a copy of the list of enums.
69 * @return list of enums
71 public List<Enum> get_enums () {
72 return new ReadOnlyList<Enum> (enums);
75 /**
76 * Returns a copy of the list of delegates.
78 * @return list of delegates
80 public List<Delegate> get_delegates () {
81 return new ReadOnlyList<Delegate> (delegates);
84 /**
85 * Creates a new interface.
87 * @param name type name
88 * @param source reference to source code
89 * @return newly created interface
91 public Interface (string name, SourceReference? source_reference = null, Comment? comment = null) {
92 base (name, source_reference, comment);
95 /**
96 * Adds the specified interface or class to the list of prerequisites of
97 * this interface.
99 * @param type an interface or class reference
101 public void add_prerequisite (DataType type) {
102 prerequisites.add (type);
103 type.parent_node = this;
107 * Prepends the specified interface or class to the list of
108 * prerequisites of this interface.
110 * @param type an interface or class reference
112 public void prepend_prerequisite (DataType type) {
113 prerequisites.insert (0, type);
117 * Returns a copy of the base type list.
119 * @return list of base types
121 public List<DataType> get_prerequisites () {
122 return new ReadOnlyList<DataType> (prerequisites);
126 * Adds the specified method as a member to this interface.
128 * @param m a method
130 public void add_method (Method m) {
131 if (m is CreationMethod) {
132 Report.error (m.source_reference, "construction methods may only be declared within classes and structs");
134 m.error = true;
135 return;
137 if (m.binding == MemberBinding.INSTANCE) {
138 m.this_parameter = new FormalParameter ("this", new ObjectType (this));
139 m.scope.add (m.this_parameter.name, m.this_parameter);
141 if (!(m.return_type is VoidType) && m.get_postconditions ().size > 0) {
142 m.result_var = new LocalVariable (m.return_type.copy (), "result");
143 m.result_var.is_result = true;
146 methods.add (m);
147 scope.add (m.name, m);
151 * Returns a copy of the list of methods.
153 * @return list of methods
155 public override List<Method> get_methods () {
156 return new ReadOnlyList<Method> (methods);
160 * Adds the specified field as a member to this interface. The field
161 * must be private and static.
163 * @param f a field
165 public void add_field (Field f) {
166 fields.add (f);
167 scope.add (f.name, f);
171 * Returns a copy of the list of fields.
173 * @return list of fields
175 public List<Field> get_fields () {
176 return new ReadOnlyList<Field> (fields);
180 * Adds the specified constant as a member to this interface.
182 * @param c a constant
184 public void add_constant (Constant c) {
185 constants.add (c);
186 scope.add (c.name, c);
190 * Returns a copy of the list of constants.
192 * @return list of constants
194 public List<Constant> get_constants () {
195 return new ReadOnlyList<Constant> (constants);
199 * Adds the specified property as a member to this interface.
201 * @param prop a property
203 public void add_property (Property prop) {
204 properties.add (prop);
205 scope.add (prop.name, prop);
207 prop.this_parameter = new FormalParameter ("this", new ObjectType (this));
208 prop.scope.add (prop.this_parameter.name, prop.this_parameter);
212 * Returns a copy of the list of properties.
214 * @return list of properties
216 public override List<Property> get_properties () {
217 return new ReadOnlyList<Property> (properties);
221 * Adds the specified signal as a member to this interface.
223 * @param sig a signal
225 public void add_signal (Signal sig) {
226 signals.add (sig);
227 scope.add (sig.name, sig);
231 * Returns a copy of the list of signals.
233 * @return list of signals
235 public override List<Signal> get_signals () {
236 return new ReadOnlyList<Signal> (signals);
240 * Adds the specified class as an inner class.
242 * @param cl a class
244 public void add_class (Class cl) {
245 classes.add (cl);
246 scope.add (cl.name, cl);
250 * Adds the specified struct as an inner struct.
252 * @param st a struct
254 public void add_struct (Struct st) {
255 structs.add (st);
256 scope.add (st.name, st);
260 * Adds the specified enum as an inner enum.
262 * @param en an enum
264 public void add_enum (Enum en) {
265 enums.add (en);
266 scope.add (en.name, en);
270 * Adds the specified delegate as an inner delegate.
272 * @param d a delegate
274 public void add_delegate (Delegate d) {
275 delegates.add (d);
276 scope.add (d.name, d);
279 public override string get_cprefix () {
280 return get_cname ();
283 public override string get_cname (bool const_type = false) {
284 if (cname == null) {
285 var attr = get_attribute ("CCode");
286 if (attr != null) {
287 cname = attr.get_string ("cname");
289 if (cname == null) {
290 cname = "%s%s".printf (parent_symbol.get_cprefix (), name);
293 return cname;
296 public void set_cname (string cname) {
297 this.cname = cname;
301 * Returns the string to be prepended to the name of members of this
302 * interface when used in C code.
304 * @return the suffix to be used in C code
306 public string get_lower_case_csuffix () {
307 if (lower_case_csuffix == null) {
308 lower_case_csuffix = get_default_lower_case_csuffix ();
310 return lower_case_csuffix;
314 * Returns default string to be prepended to the name of members of this
315 * interface when used in C code.
317 * @return the suffix to be used in C code
319 public string get_default_lower_case_csuffix () {
320 string result = camel_case_to_lower_case (name);
322 // remove underscores in some cases to avoid conflicts of type macros
323 if (result.has_prefix ("type_")) {
324 result = "type" + result.offset ("type_".len ());
325 } else if (result.has_prefix ("is_")) {
326 result = "is" + result.offset ("is_".len ());
328 if (result.has_suffix ("_class")) {
329 result = result.substring (0, result.len () - "_class".len ()) + "class";
332 return result;
336 * Sets the string to be prepended to the name of members of this
337 * interface when used in C code.
339 * @param csuffix the suffix to be used in C code
341 public void set_lower_case_csuffix (string csuffix) {
342 this.lower_case_csuffix = csuffix;
345 public override string? get_lower_case_cname (string? infix) {
346 if (infix == null) {
347 infix = "";
349 return "%s%s%s".printf (parent_symbol.get_lower_case_cprefix (), infix, get_lower_case_csuffix ());
352 public override string get_lower_case_cprefix () {
353 return "%s_".printf (get_lower_case_cname (null));
356 public override string? get_upper_case_cname (string? infix) {
357 return get_lower_case_cname (infix).up ();
360 public override void accept (CodeVisitor visitor) {
361 visitor.visit_interface (this);
364 public override void accept_children (CodeVisitor visitor) {
365 foreach (DataType type in prerequisites) {
366 type.accept (visitor);
369 foreach (TypeParameter p in get_type_parameters ()) {
370 p.accept (visitor);
373 /* process enums first to avoid order problems in C code */
374 foreach (Enum en in enums) {
375 en.accept (visitor);
378 foreach (Method m in methods) {
379 m.accept (visitor);
382 foreach (Field f in fields) {
383 f.accept (visitor);
386 foreach (Constant c in constants) {
387 c.accept (visitor);
390 foreach (Property prop in properties) {
391 prop.accept (visitor);
394 foreach (Signal sig in signals) {
395 sig.accept (visitor);
398 foreach (Class cl in classes) {
399 cl.accept (visitor);
402 foreach (Struct st in structs) {
403 st.accept (visitor);
406 foreach (Delegate d in delegates) {
407 d.accept (visitor);
411 public override bool is_reference_type () {
412 return true;
415 public override bool is_reference_counting () {
416 return true;
419 public override string? get_ref_function () {
420 foreach (DataType prerequisite in prerequisites) {
421 string ref_func = prerequisite.data_type.get_ref_function ();
422 if (ref_func != null) {
423 return ref_func;
426 return null;
429 public override string? get_unref_function () {
430 foreach (DataType prerequisite in prerequisites) {
431 string unref_func = prerequisite.data_type.get_unref_function ();
432 if (unref_func != null) {
433 return unref_func;
436 return null;
439 public override string? get_ref_sink_function () {
440 foreach (DataType prerequisite in prerequisites) {
441 string ref_sink_func = prerequisite.data_type.get_ref_sink_function ();
442 if (ref_sink_func != null) {
443 return ref_sink_func;
446 return null;
449 public override bool is_subtype_of (TypeSymbol t) {
450 if (this == t) {
451 return true;
454 foreach (DataType prerequisite in prerequisites) {
455 if (prerequisite.data_type != null && prerequisite.data_type.is_subtype_of (t)) {
456 return true;
460 return false;
463 private void process_ccode_attribute (Attribute a) {
464 if (a.has_argument ("type_cname")) {
465 set_type_cname (a.get_string ("type_cname"));
467 if (a.has_argument ("cheader_filename")) {
468 var val = a.get_string ("cheader_filename");
469 foreach (string filename in val.split (",")) {
470 add_cheader_filename (filename);
473 if (a.has_argument ("lower_case_csuffix")) {
474 lower_case_csuffix = a.get_string ("lower_case_csuffix");
479 * Process all associated attributes.
481 public void process_attributes () {
482 foreach (Attribute a in attributes) {
483 if (a.name == "CCode") {
484 process_ccode_attribute (a);
490 * Returns the name of the type struct as it is used in C code.
492 * @return the type struct name to be used in C code
494 public string get_type_cname () {
495 if (type_cname == null) {
496 type_cname = "%sIface".printf (get_cname ());
498 return type_cname;
502 * Sets the name of the type struct as it is used in C code.
504 * @param type_cname the type struct name to be used in C code
506 public void set_type_cname (string type_cname) {
507 this.type_cname = type_cname;
510 public override string? get_marshaller_type_name () {
511 return "OBJECT";
514 public override string? get_get_value_function () {
515 return "g_value_get_object";
518 public override string? get_set_value_function () {
519 return "g_value_set_object";
522 public override string? get_type_id () {
523 if (type_id == null) {
524 type_id = get_upper_case_cname ("TYPE_");
527 return type_id;
530 public override void replace_type (DataType old_type, DataType new_type) {
531 for (int i = 0; i < prerequisites.size; i++) {
532 if (prerequisites[i] == old_type) {
533 prerequisites[i] = new_type;
534 return;
539 public override string? get_param_spec_function () {
540 foreach (DataType prerequisite in prerequisites) {
541 var prereq = prerequisite as ObjectType;
542 var cl = prereq.type_symbol as Class;
543 if (cl != null) {
544 return cl.get_param_spec_function ();
546 var interf = prereq.type_symbol as Interface;
547 if (interf != null) {
548 var param_spec_function = interf.get_param_spec_function ();
549 if (param_spec_function != null) {
550 return param_spec_function;
555 return null;
558 public override bool check (SemanticAnalyzer analyzer) {
559 if (checked) {
560 return !error;
563 checked = true;
565 process_attributes ();
567 var old_source_file = analyzer.current_source_file;
568 var old_symbol = analyzer.current_symbol;
570 if (source_reference != null) {
571 analyzer.current_source_file = source_reference.file;
573 analyzer.current_symbol = this;
575 foreach (DataType prerequisite_reference in get_prerequisites ()) {
576 // check whether prerequisite is at least as accessible as the interface
577 if (!analyzer.is_type_accessible (this, prerequisite_reference)) {
578 error = true;
579 Report.error (source_reference, "prerequisite `%s` is less accessible than interface `%s`".printf (prerequisite_reference.to_string (), get_full_name ()));
580 return false;
584 /* check prerequisites */
585 Class prereq_class = null;
586 foreach (DataType prereq in get_prerequisites ()) {
587 TypeSymbol class_or_interface = prereq.data_type;
588 /* skip on previous errors */
589 if (class_or_interface == null) {
590 error = true;
591 continue;
594 if (!(class_or_interface is ObjectTypeSymbol)) {
595 error = true;
596 Report.error (source_reference, "Prerequisite `%s` of interface `%s` is not a class or interface".printf (get_full_name (), class_or_interface.to_string ()));
597 return false;
600 /* interfaces are not allowed to have multiple instantiable prerequisites */
601 if (class_or_interface is Class) {
602 if (prereq_class != null) {
603 error = true;
604 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 ()));
605 return false;
608 prereq_class = (Class) class_or_interface;
612 foreach (DataType type in prerequisites) {
613 type.check (analyzer);
616 foreach (TypeParameter p in get_type_parameters ()) {
617 p.check (analyzer);
620 foreach (Enum en in enums) {
621 en.check (analyzer);
624 foreach (Method m in methods) {
625 m.check (analyzer);
628 foreach (Field f in fields) {
629 f.check (analyzer);
632 foreach (Constant c in constants) {
633 c.check (analyzer);
636 foreach (Property prop in properties) {
637 prop.check (analyzer);
640 foreach (Signal sig in signals) {
641 sig.check (analyzer);
644 foreach (Class cl in classes) {
645 cl.check (analyzer);
648 foreach (Struct st in structs) {
649 st.check (analyzer);
652 foreach (Delegate d in delegates) {
653 d.check (analyzer);
656 analyzer.current_source_file = old_source_file;
657 analyzer.current_symbol = old_symbol;
659 return !error;