codegen: Use temporary variable for string concatenation
[vala-lang.git] / vala / valadelegate.vala
blobb56744bc7bad899ea3fb81bf052b8db0c3d8db0e
1 /* valadelegate.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 function callback type.
28 public class Vala.Delegate : TypeSymbol {
29 /**
30 * The return type of this callback.
32 public DataType return_type {
33 get { return _return_type; }
34 set {
35 _return_type = value;
36 _return_type.parent_node = this;
40 /**
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; }
49 /**
50 * Specifies the position of the instance parameter in the C function.
52 public double cinstance_parameter_position { get; set; }
54 /**
55 * Specifies the position of the array length out parameter in the C
56 * function.
58 public double carray_length_parameter_position { get; set; }
60 /**
61 * Specifies the position of the delegate target out parameter in the C
62 * function.
64 public double cdelegate_target_parameter_position { get; set; }
66 /**
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; }
72 /**
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> ();
80 private string cname;
82 private DataType _return_type;
84 /**
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) {
117 int i = 0;
118 foreach (TypeParameter parameter in type_parameters) {
119 if (parameter.name == name) {
120 return i;
122 i++;
124 return -1;
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 () {
149 return parameters;
153 * Checks whether the arguments and return type of the specified method
154 * matches this callback.
156 * @param m a method
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) {
161 // async delegates are not yet supported
162 return false;
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))) {
167 return false;
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)) {
180 return false;
184 bool first = true;
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
188 * callback
190 if (first && m.binding == MemberBinding.INSTANCE && !has_target) {
191 first = false;
192 continue;
195 /* method is allowed to accept less arguments */
196 if (!method_params_it.next ()) {
197 break;
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)) {
203 return false;
207 /* method may not expect more arguments */
208 if (method_params_it.next ()) {
209 return false;
212 // method may throw less but not more errors than the delegate
213 foreach (DataType method_error_type in m.get_error_types ()) {
214 bool match = false;
215 foreach (DataType delegate_error_type in get_error_types ()) {
216 if (method_error_type.compatible (delegate_error_type)) {
217 match = true;
218 break;
222 if (!match) {
223 return false;
227 return true;
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) {
236 p.accept (visitor);
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) {
251 if (cname == null) {
252 cname = "%s%s".printf (parent_symbol.get_cprefix (), name);
254 return cname;
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) {
263 this.cname = cname;
266 public override string? get_lower_case_cname (string? infix) {
267 if (infix == null) {
268 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);
320 public override bool is_reference_type () {
321 return false;
324 public override string? get_type_id () {
325 return "G_TYPE_POINTER";
328 public override string? get_marshaller_type_name () {
329 return "POINTER";
332 public override string? get_get_value_function () {
333 return "g_value_get_pointer";
336 public override string? get_set_value_function () {
337 return "g_value_set_pointer";
340 public override void replace_type (DataType old_type, DataType new_type) {
341 if (return_type == old_type) {
342 return_type = new_type;
343 return;
345 var error_types = get_error_types ();
346 for (int i = 0; i < error_types.size; i++) {
347 if (error_types[i] == old_type) {
348 error_types[i] = new_type;
349 return;
354 public string get_prototype_string (string name) {
355 return "%s %s %s".printf (get_return_type_string (), name, get_parameters_string ());
358 string get_return_type_string () {
359 string str = "";
360 if (!return_type.value_owned && return_type is ReferenceType) {
361 str = "weak ";
363 str += return_type.to_string ();
365 return str;
368 string get_parameters_string () {
369 string str = "(";
371 int i = 1;
372 foreach (Parameter param in parameters) {
373 if (i > 1) {
374 str += ", ";
377 if (param.direction == ParameterDirection.IN) {
378 if (param.variable_type.value_owned) {
379 str += "owned ";
381 } else {
382 if (param.direction == ParameterDirection.REF) {
383 str += "ref ";
384 } else if (param.direction == ParameterDirection.OUT) {
385 str += "out ";
387 if (!param.variable_type.value_owned && param.variable_type is ReferenceType) {
388 str += "weak ";
392 str += param.variable_type.to_string ();
394 i++;
397 str += ")";
399 return str;
402 public override bool check (CodeContext context) {
403 if (checked) {
404 return !error;
407 checked = true;
409 process_attributes ();
411 var old_source_file = context.analyzer.current_source_file;
413 if (source_reference != null) {
414 context.analyzer.current_source_file = source_reference.file;
417 foreach (TypeParameter p in type_parameters) {
418 p.check (context);
421 return_type.check (context);
423 foreach (Parameter param in parameters) {
424 param.check (context);
427 foreach (DataType error_type in get_error_types ()) {
428 error_type.check (context);
431 context.analyzer.current_source_file = old_source_file;
433 return !error;