3 * Copyright (C) 2006-2008 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
20 * Jürg Billeter <j@bitron.ch>
27 * Represents a class declaration in the source code.
29 public class Vala
.Interface
: ObjectTypeSymbol
{
30 private Gee
.List
<DataType
> prerequisites
= new ArrayList
<DataType
> ();
32 private Gee
.List
<Method
> methods
= new ArrayList
<Method
> ();
33 private Gee
.List
<Field
> fields
= new ArrayList
<Field
> ();
34 private Gee
.List
<Property
> properties
= new ArrayList
<Property
> ();
35 private Gee
.List
<Signal
> signals
= new ArrayList
<Signal
> ();
38 private Gee
.List
<Class
> classes
= new ArrayList
<Class
> ();
39 private Gee
.List
<Struct
> structs
= new ArrayList
<Struct
> ();
40 private Gee
.List
<Enum
> enums
= new ArrayList
<Enum
> ();
41 private Gee
.List
<Delegate
> delegates
= new ArrayList
<Delegate
> ();
44 private string lower_case_csuffix
;
45 private string type_cname
;
46 private string type_id
;
49 * Returns a copy of the list of classes.
51 * @return list of classes
53 public Gee
.List
<Class
> get_classes () {
54 return new ReadOnlyList
<Class
> (classes
);
58 * Returns a copy of the list of structs.
60 * @return list of structs
62 public Gee
.List
<Struct
> get_structs () {
63 return new ReadOnlyList
<Struct
> (structs
);
67 * Returns a copy of the list of enums.
69 * @return list of enums
71 public Gee
.List
<Enum
> get_enums () {
72 return new ReadOnlyList
<Enum
> (enums
);
76 * Returns a copy of the list of delegates.
78 * @return list of delegates
80 public Gee
.List
<Delegate
> get_delegates () {
81 return new ReadOnlyList
<Delegate
> (delegates
);
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) {
92 base (name
, source_reference
);
96 * Adds the specified interface or class to the list of prerequisites of
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 Gee
.List
<DataType
> get_prerequisites () {
122 return new ReadOnlyList
<DataType
> (prerequisites
);
126 * Adds the specified method as a member to this interface.
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");
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
.scope
.add (m
.result_var
.name
, m
.result_var
);
147 scope
.add (m
.name
, m
);
151 * Returns a copy of the list of methods.
153 * @return list of methods
155 public override Gee
.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.
165 public void add_field (Field f
) {
167 scope
.add (f
.name
, f
);
171 * Returns a copy of the list of fields.
173 * @return list of fields
175 public Gee
.List
<Field
> get_fields () {
176 return new ReadOnlyList
<Field
> (fields
);
180 * Adds the specified property as a member to this interface.
182 * @param prop a property
184 public void add_property (Property prop
) {
185 properties
.add (prop
);
186 scope
.add (prop
.name
, prop
);
188 prop
.this_parameter
= new
FormalParameter ("this", new
ObjectType (this
));
189 prop
.scope
.add (prop
.this_parameter
.name
, prop
.this_parameter
);
193 * Returns a copy of the list of properties.
195 * @return list of properties
197 public override Gee
.List
<Property
> get_properties () {
198 return new ReadOnlyList
<Property
> (properties
);
202 * Adds the specified signal as a member to this interface.
204 * @param sig a signal
206 public void add_signal (Signal sig
) {
208 scope
.add (sig
.name
, sig
);
212 * Returns a copy of the list of signals.
214 * @return list of signals
216 public override Gee
.List
<Signal
> get_signals () {
217 return new ReadOnlyList
<Signal
> (signals
);
221 * Adds the specified class as an inner class.
225 public void add_class (Class cl
) {
227 scope
.add (cl
.name
, cl
);
231 * Adds the specified struct as an inner struct.
235 public void add_struct (Struct st
) {
237 scope
.add (st
.name
, st
);
241 * Adds the specified enum as an inner enum.
245 public void add_enum (Enum en
) {
247 scope
.add (en
.name
, en
);
251 * Adds the specified delegate as an inner delegate.
253 * @param d a delegate
255 public void add_delegate (Delegate d
) {
257 scope
.add (d
.name
, d
);
260 public override string get_cname (bool const_type
= false) {
262 cname
= "%s%s".printf (parent_symbol
.get_cprefix (), name
);
268 * Returns the string to be prepended to the name of members of this
269 * interface when used in C code.
271 * @return the suffix to be used in C code
273 public string get_lower_case_csuffix () {
274 if (lower_case_csuffix
== null) {
275 lower_case_csuffix
= get_default_lower_case_csuffix ();
277 return lower_case_csuffix
;
281 * Returns default string to be prepended to the name of members of this
282 * interface when used in C code.
284 * @return the suffix to be used in C code
286 public string get_default_lower_case_csuffix () {
287 string result
= camel_case_to_lower_case (name
);
289 // remove underscores in some cases to avoid conflicts of type macros
290 if (result
.has_prefix ("type_")) {
291 result
= "type" + result
.offset ("type_".len ());
292 } else if (result
.has_prefix ("is_")) {
293 result
= "is" + result
.offset ("is_".len ());
295 if (result
.has_suffix ("_class")) {
296 result
= result
.substring (0, result
.len () - "_class".len ()) + "class";
303 * Sets the string to be prepended to the name of members of this
304 * interface when used in C code.
306 * @param csuffix the suffix to be used in C code
308 public void set_lower_case_csuffix (string csuffix
) {
309 this
.lower_case_csuffix
= csuffix
;
312 public override string?
get_lower_case_cname (string? infix
) {
316 return "%s%s%s".printf (parent_symbol
.get_lower_case_cprefix (), infix
, get_lower_case_csuffix ());
319 public override string get_lower_case_cprefix () {
320 return "%s_".printf (get_lower_case_cname (null));
323 public override string?
get_upper_case_cname (string? infix
) {
324 return get_lower_case_cname (infix
).up ();
327 public override void accept (CodeVisitor visitor
) {
328 visitor
.visit_interface (this
);
331 public override void accept_children (CodeVisitor visitor
) {
332 foreach (DataType type
in prerequisites
) {
333 type
.accept (visitor
);
336 foreach (TypeParameter p
in get_type_parameters ()) {
340 /* process enums first to avoid order problems in C code */
341 foreach (Enum en
in enums
) {
345 foreach (Method m
in methods
) {
349 foreach (Field f
in fields
) {
353 foreach (Property prop
in properties
) {
354 prop
.accept (visitor
);
357 foreach (Signal sig
in signals
) {
358 sig
.accept (visitor
);
361 foreach (Class cl
in classes
) {
365 foreach (Struct st
in structs
) {
369 foreach (Delegate d
in delegates
) {
374 public override bool is_reference_type () {
378 public override bool is_reference_counting () {
382 public override string?
get_ref_function () {
383 foreach (DataType prerequisite
in prerequisites
) {
384 string ref_func
= prerequisite
.data_type
.get_ref_function ();
385 if (ref_func
!= null) {
392 public override string?
get_unref_function () {
393 foreach (DataType prerequisite
in prerequisites
) {
394 string unref_func
= prerequisite
.data_type
.get_unref_function ();
395 if (unref_func
!= null) {
402 public override bool is_subtype_of (TypeSymbol t
) {
407 foreach (DataType prerequisite
in prerequisites
) {
408 if (prerequisite
.data_type
!= null && prerequisite
.data_type
.is_subtype_of (t
)) {
416 private void process_ccode_attribute (Attribute a
) {
417 if (a
.has_argument ("type_cname")) {
418 set_type_cname (a
.get_string ("type_cname"));
420 if (a
.has_argument ("cheader_filename")) {
421 var val
= a
.get_string ("cheader_filename");
422 foreach (string filename
in val
.split (",")) {
423 add_cheader_filename (filename
);
426 if (a
.has_argument ("lower_case_csuffix")) {
427 lower_case_csuffix
= a
.get_string ("lower_case_csuffix");
432 * Process all associated attributes.
434 public void process_attributes () {
435 foreach (Attribute a
in attributes
) {
436 if (a
.name
== "CCode") {
437 process_ccode_attribute (a
);
443 * Returns the name of the type struct as it is used in C code.
445 * @return the type struct name to be used in C code
447 public string get_type_cname () {
448 if (type_cname
== null) {
449 type_cname
= "%sIface".printf (get_cname ());
455 * Sets the name of the type struct as it is used in C code.
457 * @param type_cname the type struct name to be used in C code
459 public void set_type_cname (string type_cname
) {
460 this
.type_cname
= type_cname
;
463 public override string?
get_marshaller_type_name () {
467 public override string?
get_get_value_function () {
468 return "g_value_get_object";
471 public override string?
get_set_value_function () {
472 return "g_value_set_object";
475 public override string?
get_type_id () {
476 if (type_id
== null) {
477 type_id
= get_upper_case_cname ("TYPE_");
483 public override void replace_type (DataType old_type
, DataType new_type
) {
484 for (int i
= 0; i
< prerequisites
.size
; i
++) {
485 if (prerequisites
[i
] == old_type
) {
486 prerequisites
[i
] = new_type
;
492 public override string?
get_param_spec_function () {
493 foreach (DataType prerequisite
in prerequisites
) {
494 var prereq
= prerequisite as ObjectType
;
495 var cl
= prereq
.type_symbol as Class
;
497 return cl
.get_param_spec_function ();
499 var interf
= prereq
.type_symbol as Interface
;
500 if (interf
!= null) {
501 var param_spec_function
= interf
.get_param_spec_function ();
502 if (param_spec_function
!= null) {
503 return param_spec_function
;
511 public override bool check (SemanticAnalyzer analyzer
) {
518 process_attributes ();
520 var old_source_file
= analyzer
.current_source_file
;
521 var old_symbol
= analyzer
.current_symbol
;
523 if (source_reference
!= null) {
524 analyzer
.current_source_file
= source_reference
.file
;
526 analyzer
.current_symbol
= this
;
528 foreach (DataType prerequisite_reference
in get_prerequisites ()) {
529 // check whether prerequisite is at least as accessible as the interface
530 if (!analyzer
.is_type_accessible (this
, prerequisite_reference
)) {
532 Report
.error (source_reference
, "prerequisite `%s` is less accessible than interface `%s`".printf (prerequisite_reference
.to_string (), get_full_name ()));
536 analyzer
.current_source_file
.add_type_dependency (prerequisite_reference
, SourceFileDependencyType
.HEADER_FULL
);
539 /* check prerequisites */
540 Class prereq_class
= null;
541 foreach (DataType prereq
in get_prerequisites ()) {
542 TypeSymbol class_or_interface
= prereq
.data_type
;
543 /* skip on previous errors */
544 if (class_or_interface
== null) {
549 if (!(class_or_interface is ObjectTypeSymbol
)) {
551 Report
.error (source_reference
, "Prerequisite `%s` of interface `%s` is not a class or interface".printf (get_full_name (), class_or_interface
.to_string ()));
555 /* interfaces are not allowed to have multiple instantiable prerequisites */
556 if (class_or_interface is Class
) {
557 if (prereq_class
!= null) {
559 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 ()));
563 prereq_class
= (Class
) class_or_interface
;
567 foreach (DataType type
in prerequisites
) {
568 type
.check (analyzer
);
571 foreach (TypeParameter p
in get_type_parameters ()) {
575 foreach (Enum en
in enums
) {
579 foreach (Method m
in methods
) {
583 foreach (Field f
in fields
) {
587 foreach (Property prop
in properties
) {
588 prop
.check (analyzer
);
591 foreach (Signal sig
in signals
) {
592 sig
.check (analyzer
);
595 foreach (Class cl
in classes
) {
599 foreach (Struct st
in structs
) {
603 foreach (Delegate d
in delegates
) {
607 analyzer
.current_source_file
= old_source_file
;
608 analyzer
.current_symbol
= old_symbol
;