Use strict non-null types with --enable-experimental-non-null
[vala-lang.git] / vala / valadelegate.vala
bloba882d3a2a3bbfd124214ac86a4fd2100b37f3e6c
1 /* valadelegate.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 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<FormalParameter> parameters = new ArrayList<FormalParameter> ();
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);
113 * Appends paramater to this callback function.
115 * @param param a formal parameter
117 public void add_parameter (FormalParameter param) {
118 // default C parameter position
119 param.cparameter_position = parameters.size + 1;
120 param.carray_length_parameter_position = param.cparameter_position + 0.1;
121 param.cdelegate_target_parameter_position = param.cparameter_position + 0.1;
123 parameters.add (param);
124 scope.add (param.name, param);
128 * Return copy of parameter list.
130 * @return parameter list
132 public List<FormalParameter> get_parameters () {
133 return new ReadOnlyList<FormalParameter> (parameters);
137 * Checks whether the arguments and return type of the specified method
138 * matches this callback.
140 * @param m a method
141 * @return true if the specified method is compatible to this callback
143 public bool matches_method (Method m) {
144 // method is allowed to ensure stricter return type (stronger postcondition)
145 if (!m.return_type.stricter (return_type)) {
146 return false;
149 var method_params = m.get_parameters ();
150 Iterator<FormalParameter> method_params_it = method_params.iterator ();
152 if (sender_type != null && method_params.size == parameters.size + 1) {
153 // method has sender parameter
154 method_params_it.next ();
156 // method is allowed to accept arguments of looser types (weaker precondition)
157 var method_param = method_params_it.get ();
158 if (!sender_type.stricter (method_param.parameter_type)) {
159 return false;
163 bool first = true;
164 foreach (FormalParameter param in parameters) {
165 /* use first callback parameter as instance parameter if
166 * an instance method is being compared to a static
167 * callback
169 if (first && m.binding == MemberBinding.INSTANCE && !has_target) {
170 first = false;
171 continue;
174 /* method is allowed to accept less arguments */
175 if (!method_params_it.next ()) {
176 break;
179 // method is allowed to accept arguments of looser types (weaker precondition)
180 var method_param = method_params_it.get ();
181 if (!param.parameter_type.stricter (method_param.parameter_type)) {
182 return false;
186 /* method may not expect more arguments */
187 if (method_params_it.next ()) {
188 return false;
191 return true;
194 public override void accept (CodeVisitor visitor) {
195 visitor.visit_delegate (this);
198 public override void accept_children (CodeVisitor visitor) {
199 foreach (TypeParameter p in type_parameters) {
200 p.accept (visitor);
203 return_type.accept (visitor);
205 foreach (FormalParameter param in parameters) {
206 param.accept (visitor);
209 foreach (DataType error_type in get_error_types ()) {
210 error_type.accept (visitor);
214 public override string get_cname (bool const_type = false) {
215 if (cname == null) {
216 cname = "%s%s".printf (parent_symbol.get_cprefix (), name);
218 return cname;
222 * Sets the name of this callback as it is used in C code.
224 * @param cname the name to be used in C code
226 public void set_cname (string cname) {
227 this.cname = cname;
230 private void process_ccode_attribute (Attribute a) {
231 if (a.has_argument ("cname")) {
232 set_cname (a.get_string ("cname"));
234 if (a.has_argument ("has_target")) {
235 has_target = a.get_bool ("has_target");
237 if (a.has_argument ("instance_pos")) {
238 cinstance_parameter_position = a.get_double ("instance_pos");
240 if (a.has_argument ("array_length")) {
241 no_array_length = !a.get_bool ("array_length");
243 if (a.has_argument ("array_null_terminated")) {
244 array_null_terminated = a.get_bool ("array_null_terminated");
246 if (a.has_argument ("array_length_pos")) {
247 carray_length_parameter_position = a.get_double ("array_length_pos");
249 if (a.has_argument ("delegate_target_pos")) {
250 cdelegate_target_parameter_position = a.get_double ("delegate_target_pos");
252 if (a.has_argument ("cheader_filename")) {
253 var val = a.get_string ("cheader_filename");
254 foreach (string filename in val.split (",")) {
255 add_cheader_filename (filename);
261 * Process all associated attributes.
263 public void process_attributes () {
264 foreach (Attribute a in attributes) {
265 if (a.name == "CCode") {
266 process_ccode_attribute (a);
271 public override bool is_reference_type () {
272 return false;
275 public override string? get_type_id () {
276 return "G_TYPE_POINTER";
279 public override string? get_marshaller_type_name () {
280 return "POINTER";
283 public override string? get_get_value_function () {
284 return "g_value_get_pointer";
287 public override string? get_set_value_function () {
288 return "g_value_set_pointer";
291 public override void replace_type (DataType old_type, DataType new_type) {
292 if (return_type == old_type) {
293 return_type = new_type;
294 return;
296 var error_types = get_error_types ();
297 for (int i = 0; i < error_types.size; i++) {
298 if (error_types[i] == old_type) {
299 error_types[i] = new_type;
300 return;
305 public string get_prototype_string (string name) {
306 return "%s %s %s".printf (get_return_type_string (), name, get_parameters_string ());
309 string get_return_type_string () {
310 string str = "";
311 if (!return_type.value_owned && return_type is ReferenceType) {
312 str = "weak ";
314 str += return_type.to_string ();
316 return str;
319 string get_parameters_string () {
320 string str = "(";
322 int i = 1;
323 foreach (FormalParameter param in parameters) {
324 if (i > 1) {
325 str += ", ";
328 if (param.direction == ParameterDirection.IN) {
329 if (param.parameter_type.value_owned) {
330 str += "owned ";
332 } else {
333 if (param.direction == ParameterDirection.REF) {
334 str += "ref ";
335 } else if (param.direction == ParameterDirection.OUT) {
336 str += "out ";
338 if (!param.parameter_type.value_owned && param.parameter_type is ReferenceType) {
339 str += "weak ";
343 str += param.parameter_type.to_string ();
345 i++;
348 str += ")";
350 return str;
353 public override bool check (SemanticAnalyzer analyzer) {
354 if (checked) {
355 return !error;
358 checked = true;
360 process_attributes ();
362 var old_source_file = analyzer.current_source_file;
364 if (source_reference != null) {
365 analyzer.current_source_file = source_reference.file;
368 foreach (TypeParameter p in type_parameters) {
369 p.check (analyzer);
372 return_type.check (analyzer);
374 foreach (FormalParameter param in parameters) {
375 param.check (analyzer);
378 foreach (DataType error_type in get_error_types ()) {
379 error_type.check (analyzer);
382 analyzer.current_source_file = old_source_file;
384 return !error;