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
20 * Jürg Billeter <j@bitron.ch>
26 * Represents a function callback type.
28 public class Vala
.Delegate
: TypeSymbol
{
30 * The return type of this callback.
32 public DataType return_type
{
33 get { return _return_type
; }
36 _return_type
.parent_node
= this
;
41 * Specifies whether callback supports calling instance methods.
42 * The reference to the object instance will be appended to the end of
43 * the argument list in the generated C code.
45 public bool has_target
{ get; set; }
47 public DataType? sender_type
{ get; set; }
50 * Specifies the position of the instance parameter in the C function.
52 public double cinstance_parameter_position
{ get; set; }
55 * Specifies the position of the array length out parameter in the C
58 public double carray_length_parameter_position
{ get; set; }
61 * Specifies the position of the delegate target out parameter in the C
64 public double cdelegate_target_parameter_position
{ get; set; }
67 * Specifies whether the array length should be returned implicitly
68 * if the return type is an array.
70 public bool no_array_length
{ get; set; }
73 * Specifies whether the array is null terminated.
75 public bool array_null_terminated
{ get; set; }
77 private List
<TypeParameter
> type_parameters
= new ArrayList
<TypeParameter
> ();
79 private List
<Parameter
> parameters
= new ArrayList
<Parameter
> ();
82 private DataType _return_type
;
85 * Creates a new delegate.
87 * @param name delegate type name
88 * @param return_type return type
89 * @param source reference to source code
90 * @return newly created delegate
92 public Delegate (string? name
, DataType return_type
, SourceReference? source_reference
= null, Comment? comment
= null) {
93 base (name
, source_reference
, comment
);
94 this
.return_type
= return_type
;
96 // error is -1 (right of user_data)
97 cinstance_parameter_position
= -2;
98 carray_length_parameter_position
= -3;
99 cdelegate_target_parameter_position
= -3;
103 * Appends the specified parameter to the list of type parameters.
105 * @param p a type parameter
107 public void add_type_parameter (TypeParameter p
) {
108 type_parameters
.add (p
);
109 scope
.add (p
.name
, p
);
112 public List
<TypeParameter
> get_type_parameters () {
113 return type_parameters
;
116 public override int get_type_parameter_index (string name
) {
118 foreach (TypeParameter parameter
in type_parameters
) {
119 if (parameter
.name
== name
) {
128 * Appends paramater to this callback function.
130 * @param param a formal parameter
132 public void add_parameter (Parameter param
) {
133 // default C parameter position
134 param
.cparameter_position
= parameters
.size
+ 1;
135 param
.carray_length_parameter_position
= param
.cparameter_position
+ 0.1;
136 param
.cdelegate_target_parameter_position
= param
.cparameter_position
+ 0.1;
137 param
.cdestroy_notify_parameter_position
= param
.cparameter_position
+ 0.1;
139 parameters
.add (param
);
140 scope
.add (param
.name
, param
);
144 * Return copy of parameter list.
146 * @return parameter list
148 public List
<Parameter
> get_parameters () {
153 * Checks whether the arguments and return type of the specified method
154 * matches this callback.
157 * @return true if the specified method is compatible to this callback
159 public bool matches_method (Method m
, DataType dt
) {
160 if (m
.coroutine
&& !(parent_symbol is Signal
)) {
161 // async delegates are not yet supported
165 // method is allowed to ensure stricter return type (stronger postcondition)
166 if (!m
.return_type
.stricter (return_type
.get_actual_type (dt
, null, this
))) {
170 var method_params
= m
.get_parameters ();
171 Iterator
<Parameter
> method_params_it
= method_params
.iterator ();
173 if (sender_type
!= null && method_params
.size
== parameters
.size
+ 1) {
174 // method has sender parameter
175 method_params_it
.next ();
177 // method is allowed to accept arguments of looser types (weaker precondition)
178 var method_param
= method_params_it
.get ();
179 if (!sender_type
.stricter (method_param
.variable_type
)) {
185 foreach (Parameter param
in parameters
) {
186 /* use first callback parameter as instance parameter if
187 * an instance method is being compared to a static
190 if (first
&& m
.binding
== MemberBinding
.INSTANCE
&& !has_target
) {
195 /* method is allowed to accept less arguments */
196 if (!method_params_it
.next ()) {
200 // method is allowed to accept arguments of looser types (weaker precondition)
201 var method_param
= method_params_it
.get ();
202 if (!param
.variable_type
.get_actual_type (dt
, null, this
).stricter (method_param
.variable_type
)) {
207 /* method may not expect more arguments */
208 if (method_params_it
.next ()) {
212 // method may throw less but not more errors than the delegate
213 foreach (DataType method_error_type
in m
.get_error_types ()) {
215 foreach (DataType delegate_error_type
in get_error_types ()) {
216 if (method_error_type
.compatible (delegate_error_type
)) {
230 public override void accept (CodeVisitor visitor
) {
231 visitor
.visit_delegate (this
);
234 public override void accept_children (CodeVisitor visitor
) {
235 foreach (TypeParameter p
in type_parameters
) {
239 return_type
.accept (visitor
);
241 foreach (Parameter param
in parameters
) {
242 param
.accept (visitor
);
245 foreach (DataType error_type
in get_error_types ()) {
246 error_type
.accept (visitor
);
250 public override string get_cname (bool const_type
= false) {
252 cname
= "%s%s".printf (parent_symbol
.get_cprefix (), name
);
258 * Sets the name of this callback as it is used in C code.
260 * @param cname the name to be used in C code
262 public void set_cname (string cname
) {
266 public override string?
get_lower_case_cname (string? infix
) {
270 return "%s%s%s".printf (parent_symbol
.get_lower_case_cprefix (), infix
, camel_case_to_lower_case (name
));
273 public override string?
get_upper_case_cname (string? infix
) {
274 return get_lower_case_cname (infix
).up ();
277 private void process_ccode_attribute (Attribute a
) {
278 if (a
.has_argument ("cname")) {
279 set_cname (a
.get_string ("cname"));
281 if (a
.has_argument ("has_target")) {
282 has_target
= a
.get_bool ("has_target");
284 if (a
.has_argument ("instance_pos")) {
285 cinstance_parameter_position
= a
.get_double ("instance_pos");
287 if (a
.has_argument ("array_length")) {
288 no_array_length
= !a
.get_bool ("array_length");
290 if (a
.has_argument ("array_null_terminated")) {
291 array_null_terminated
= a
.get_bool ("array_null_terminated");
293 if (a
.has_argument ("array_length_pos")) {
294 carray_length_parameter_position
= a
.get_double ("array_length_pos");
296 if (a
.has_argument ("delegate_target_pos")) {
297 cdelegate_target_parameter_position
= a
.get_double ("delegate_target_pos");
299 if (a
.has_argument ("cheader_filename")) {
300 var val
= a
.get_string ("cheader_filename");
301 foreach (string filename
in val
.split (",")) {
302 add_cheader_filename (filename
);
308 * Process all associated attributes.
310 public void process_attributes () {
311 foreach (Attribute a
in attributes
) {
312 if (a
.name
== "CCode") {
313 process_ccode_attribute (a
);
314 } else if (a
.name
== "Deprecated") {
315 process_deprecated_attribute (a
);
316 } else if (a
.name
== "Experimental") {
317 process_experimental_attribute (a
);
322 public override bool is_reference_type () {
326 public override string?
get_type_id () {
327 return "G_TYPE_POINTER";
330 public override string?
get_marshaller_type_name () {
334 public override string?
get_get_value_function () {
335 return "g_value_get_pointer";
338 public override string?
get_set_value_function () {
339 return "g_value_set_pointer";
342 public override void replace_type (DataType old_type
, DataType new_type
) {
343 if (return_type
== old_type
) {
344 return_type
= new_type
;
347 var error_types
= get_error_types ();
348 for (int i
= 0; i
< error_types
.size
; i
++) {
349 if (error_types
[i
] == old_type
) {
350 error_types
[i
] = new_type
;
356 public string get_prototype_string (string name
) {
357 return "%s %s %s".printf (get_return_type_string (), name
, get_parameters_string ());
360 string get_return_type_string () {
362 if (!return_type
.value_owned
&& return_type is ReferenceType
) {
365 str
+= return_type
.to_string ();
370 string get_parameters_string () {
374 foreach (Parameter param
in parameters
) {
379 if (param
.direction
== ParameterDirection
.IN
) {
380 if (param
.variable_type
.value_owned
) {
384 if (param
.direction
== ParameterDirection
.REF
) {
386 } else if (param
.direction
== ParameterDirection
.OUT
) {
389 if (!param
.variable_type
.value_owned
&& param
.variable_type is ReferenceType
) {
394 str
+= param
.variable_type
.to_string ();
404 public override bool check (CodeContext context
) {
411 process_attributes ();
413 var old_source_file
= context
.analyzer
.current_source_file
;
415 if (source_reference
!= null) {
416 context
.analyzer
.current_source_file
= source_reference
.file
;
419 foreach (TypeParameter p
in type_parameters
) {
423 return_type
.check (context
);
425 foreach (Parameter param
in parameters
) {
426 param
.check (context
);
429 foreach (DataType error_type
in get_error_types ()) {
430 error_type
.check (context
);
433 context
.analyzer
.current_source_file
= old_source_file
;