linux: Add psiginfo(3)
[vala-gnome.git] / vala / valadelegate.vala
blob3e79527a8e4d23268bf495407d4c61c16982f8fb
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, Callable {
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 {
46 get {
47 if (_has_target == null) {
48 _has_target = get_attribute_bool ("CCode", "has_target", true);
50 return _has_target;
52 set {
53 _has_target = value;
54 if (value) {
55 remove_attribute_argument ("CCode", "has_target");
56 } else {
57 set_attribute_bool ("CCode", "has_target", false);
62 public DataType? sender_type { get; set; }
64 private List<TypeParameter> type_parameters = new ArrayList<TypeParameter> ();
66 private List<Parameter> parameters = new ArrayList<Parameter> ();
68 private DataType _return_type;
69 private bool? _has_target;
71 /**
72 * Creates a new delegate.
74 * @param name delegate type name
75 * @param return_type return type
76 * @param source_reference reference to source code
77 * @return newly created delegate
79 public Delegate (string? name, DataType return_type, SourceReference? source_reference = null, Comment? comment = null) {
80 base (name, source_reference, comment);
81 this.return_type = return_type;
84 /**
85 * Appends the specified parameter to the list of type parameters.
87 * @param p a type parameter
89 public void add_type_parameter (TypeParameter p) {
90 type_parameters.add (p);
91 scope.add (p.name, p);
94 public List<TypeParameter> get_type_parameters () {
95 return type_parameters;
98 public override int get_type_parameter_index (string name) {
99 int i = 0;
100 foreach (TypeParameter parameter in type_parameters) {
101 if (parameter.name == name) {
102 return i;
104 i++;
106 return -1;
110 * Appends paramater to this callback function.
112 * @param param a formal parameter
114 public void add_parameter (Parameter param) {
115 parameters.add (param);
116 scope.add (param.name, param);
120 * Return copy of parameter list.
122 * @return parameter list
124 public List<Parameter> get_parameters () {
125 return parameters;
129 * Checks whether the arguments and return type of the specified method
130 * matches this callback.
132 * @param m a method
133 * @return true if the specified method is compatible to this callback
135 public bool matches_method (Method m, DataType dt) {
136 if (m.coroutine && !(parent_symbol is Signal)) {
137 // async delegates are not yet supported
138 return false;
141 // method is allowed to ensure stricter return type (stronger postcondition)
142 if (!m.return_type.stricter (return_type.get_actual_type (dt, null, this))) {
143 return false;
146 var method_params = m.get_parameters ();
147 Iterator<Parameter> method_params_it = method_params.iterator ();
149 if (sender_type != null && method_params.size == parameters.size + 1) {
150 // method has sender parameter
151 method_params_it.next ();
153 // method is allowed to accept arguments of looser types (weaker precondition)
154 var method_param = method_params_it.get ();
155 if (!sender_type.stricter (method_param.variable_type)) {
156 return false;
160 bool first = true;
161 foreach (Parameter param in parameters) {
162 /* use first callback parameter as instance parameter if
163 * an instance method is being compared to a static
164 * callback
166 if (first && m.binding == MemberBinding.INSTANCE && !has_target) {
167 first = false;
168 continue;
171 /* method is allowed to accept less arguments */
172 if (!method_params_it.next ()) {
173 break;
176 // method is allowed to accept arguments of looser types (weaker precondition)
177 var method_param = method_params_it.get ();
178 if (!param.variable_type.get_actual_type (dt, null, this).stricter (method_param.variable_type)) {
179 return false;
183 /* method may not expect more arguments */
184 if (method_params_it.next ()) {
185 return false;
188 var error_types = get_error_types ();
189 var method_error_types = m.get_error_types ();
191 // method must throw error if the delegate does
192 if (error_types.size > 0 && method_error_types.size == 0) {
193 return false;
196 // method may throw less but not more errors than the delegate
197 foreach (DataType method_error_type in method_error_types) {
198 bool match = false;
199 foreach (DataType delegate_error_type in error_types) {
200 if (method_error_type.compatible (delegate_error_type)) {
201 match = true;
202 break;
206 if (!match) {
207 return false;
211 return true;
214 public override void accept (CodeVisitor visitor) {
215 visitor.visit_delegate (this);
218 public override void accept_children (CodeVisitor visitor) {
219 foreach (TypeParameter p in type_parameters) {
220 p.accept (visitor);
223 return_type.accept (visitor);
225 foreach (Parameter param in parameters) {
226 param.accept (visitor);
229 foreach (DataType error_type in get_error_types ()) {
230 error_type.accept (visitor);
234 public override bool is_reference_type () {
235 return false;
238 public override void replace_type (DataType old_type, DataType new_type) {
239 if (return_type == old_type) {
240 return_type = new_type;
241 return;
243 var error_types = get_error_types ();
244 for (int i = 0; i < error_types.size; i++) {
245 if (error_types[i] == old_type) {
246 error_types[i] = new_type;
247 return;
252 public override bool check (CodeContext context) {
253 if (checked) {
254 return !error;
257 checked = true;
259 var old_source_file = context.analyzer.current_source_file;
261 if (source_reference != null) {
262 context.analyzer.current_source_file = source_reference.file;
265 foreach (TypeParameter p in type_parameters) {
266 p.check (context);
269 return_type.check (context);
271 foreach (Parameter param in parameters) {
272 param.check (context);
275 foreach (DataType error_type in get_error_types ()) {
276 error_type.check (context);
279 context.analyzer.current_source_file = old_source_file;
281 return !error;