Line data Source code
1 : /* valasignal.vala
2 : *
3 : * Copyright (C) 2006-2012 Jürg Billeter
4 : *
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.
9 :
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.
14 :
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
18 : *
19 : * Author:
20 : * Jürg Billeter <j@bitron.ch>
21 : */
22 :
23 : using GLib;
24 :
25 : /**
26 : * Represents an object signal. Signals enable objects to provide notifications.
27 : */
28 276518 : public class Vala.Signal : Symbol, Callable {
29 : /**
30 : * The return type of handlers of this signal.
31 : */
32 : public DataType return_type {
33 644109 : get { return _return_type; }
34 160508 : set {
35 289611 : _return_type = value;
36 160508 : _return_type.parent_node = this;
37 : }
38 : }
39 :
40 : public Block body {
41 377368 : get { return _body; }
42 14 : set {
43 28 : _body = value;
44 14 : if (_body != null) {
45 14 : _body.owner = scope;
46 : }
47 : }
48 : }
49 :
50 : /**
51 : * Specifies whether this signal has virtual method handler.
52 : */
53 152782 : public bool is_virtual { get; set; }
54 :
55 273458 : private List<Parameter> parameters = new ArrayList<Parameter> ();
56 : /**
57 : * Refers to the default signal handler, which is an anonymous
58 : * function in the scope.
59 : * */
60 602635 : public Method default_handler { get; private set; }
61 :
62 : /**
63 : * Refers to the public signal emitter method, which is an anonymous
64 : * function in the scope.
65 : * */
66 173990 : public Method emitter { get; private set; }
67 :
68 136729 : private DataType _return_type;
69 :
70 136729 : private Block _body;
71 :
72 : /**
73 : * Creates a new signal.
74 : *
75 : * @param name signal name
76 : * @param return_type signal return type
77 : * @param source_reference reference to source code
78 : * @return newly created signal
79 : */
80 410176 : public Signal (string name, DataType return_type, SourceReference? source_reference = null, Comment? comment = null) {
81 136729 : base (name, source_reference, comment);
82 136729 : this.return_type = return_type;
83 : }
84 :
85 : /**
86 : * Appends parameter to signal handler.
87 : *
88 : * @param param a formal parameter
89 : */
90 169091 : public void add_parameter (Parameter param) {
91 169091 : parameters.add (param);
92 169091 : scope.add (param.name, param);
93 : }
94 :
95 975 : public unowned List<Parameter> get_parameters () {
96 975 : return parameters;
97 : }
98 :
99 : /**
100 : * Returns generated delegate to be used for signal handlers.
101 : *
102 : * @return delegate
103 : */
104 114 : public Delegate get_delegate (DataType sender_type, CodeNode node_reference) {
105 114 : var actual_return_type = return_type.get_actual_type (sender_type, null, node_reference);
106 :
107 114 : var generated_delegate = new Delegate (null, actual_return_type, source_reference);
108 114 : generated_delegate.access = SymbolAccessibility.PUBLIC;
109 114 : generated_delegate.owner = scope;
110 :
111 : // sender parameter is never null and doesn't own its value
112 114 : var sender_param_type = sender_type.copy ();
113 114 : sender_param_type.value_owned = false;
114 114 : sender_param_type.nullable = false;
115 :
116 114 : generated_delegate.sender_type = sender_param_type;
117 :
118 114 : bool is_generic = actual_return_type.is_generic ();
119 :
120 294 : foreach (Parameter param in parameters) {
121 90 : var actual_param = param.copy ();
122 90 : actual_param.variable_type = actual_param.variable_type.get_actual_type (sender_type, null, node_reference);
123 90 : generated_delegate.add_parameter (actual_param);
124 :
125 90 : if (actual_param.variable_type.is_generic ()) {
126 2 : is_generic = true;
127 : }
128 : }
129 :
130 114 : if (is_generic) {
131 6 : unowned ObjectTypeSymbol cl = (ObjectTypeSymbol) parent_symbol;
132 26 : foreach (var type_param in cl.get_type_parameters ()) {
133 10 : generated_delegate.add_type_parameter (new TypeParameter (type_param.name, type_param.source_reference));
134 : }
135 :
136 : // return type and parameter types must refer to the delegate type parameters
137 : // instead of to the class type parameters
138 26 : foreach (var type_param in generated_delegate.get_type_parameters ()) {
139 10 : actual_return_type.replace_type_parameter (cl.get_type_parameters ().get (cl.get_type_parameter_index (type_param.name)), type_param);
140 : }
141 10 : foreach (var param in generated_delegate.get_parameters ()) {
142 6 : foreach (var type_param in generated_delegate.get_type_parameters ()) {
143 2 : param.variable_type.replace_type_parameter (cl.get_type_parameters ().get (cl.get_type_parameter_index (type_param.name)), type_param);
144 : }
145 : }
146 : }
147 :
148 114 : scope.add (null, generated_delegate);
149 :
150 114 : return generated_delegate;
151 : }
152 :
153 304034 : public override void accept (CodeVisitor visitor) {
154 304034 : visitor.visit_signal (this);
155 : }
156 :
157 215042 : public override void accept_children (CodeVisitor visitor) {
158 215042 : return_type.accept (visitor);
159 :
160 744650 : foreach (Parameter param in parameters) {
161 264804 : param.accept (visitor);
162 : }
163 215042 : if (default_handler == null && body != null) {
164 11 : body.accept (visitor);
165 215031 : } else if (default_handler != null) {
166 75519 : default_handler.accept (visitor);
167 : }
168 215042 : if (emitter != null) {
169 12761 : emitter.accept (visitor);
170 : }
171 : }
172 :
173 23768 : public override void replace_type (DataType old_type, DataType new_type) {
174 23768 : if (return_type == old_type) {
175 23768 : return_type = new_type;
176 : }
177 : }
178 :
179 127576 : public override bool check (CodeContext context) {
180 127576 : if (checked) {
181 204 : return !error;
182 : }
183 :
184 127372 : checked = true;
185 :
186 : // parent_symbol may be null for dynamic signals
187 127372 : unowned Class? parent_cl = parent_symbol as Class;
188 93911 : if (parent_cl != null && parent_cl.is_compact) {
189 1 : error = true;
190 1 : Report.error (source_reference, "Signals are not supported in compact classes");
191 1 : return false;
192 : }
193 :
194 127371 : if (parent_cl != null) {
195 418808 : foreach (DataType base_type in parent_cl.get_base_types ()) {
196 162450 : if (SemanticAnalyzer.symbol_lookup_inherited (base_type.type_symbol, name) is Signal) {
197 1 : error = true;
198 1 : Report.error (source_reference, "Signals with the same name as a signal in a base type are not supported");
199 1 : return false;
200 : }
201 : }
202 : }
203 :
204 127370 : if (this is DynamicSignal) {
205 11 : return !error;
206 : }
207 :
208 127359 : return_type.check (context);
209 127359 : if (!external_package) {
210 103 : context.analyzer.check_type (return_type);
211 103 : return_type.check_type_arguments (context, !(return_type is DelegateType));
212 : }
213 :
214 127359 : if (return_type.type_symbol == context.analyzer.va_list_type.type_symbol) {
215 1 : error = true;
216 1 : Report.error (source_reference, "`%s' not supported as return type", return_type.type_symbol.get_full_name ());
217 1 : return false;
218 : }
219 :
220 441812 : foreach (Parameter param in parameters) {
221 157227 : if (param.ellipsis) {
222 0 : Report.error (param.source_reference, "Signals with variable argument lists are not supported");
223 0 : return false;
224 : }
225 :
226 157227 : if (!param.check (context)) {
227 0 : error = true;
228 : }
229 : }
230 :
231 127358 : if (body != null || (is_virtual && external_package)) {
232 110476 : default_handler = new Method (name, return_type, source_reference);
233 :
234 110476 : default_handler.owner = owner;
235 110476 : default_handler.access = (is_virtual ? access : SymbolAccessibility.PRIVATE);
236 110476 : default_handler.external = external;
237 110476 : default_handler.hides = hides;
238 110476 : default_handler.is_virtual = is_virtual;
239 110476 : default_handler.signal_reference = this;
240 110476 : default_handler.body = body;
241 :
242 383260 : foreach (Parameter param in parameters) {
243 136392 : default_handler.add_parameter (param);
244 : }
245 :
246 110476 : unowned ObjectTypeSymbol? cl = parent_symbol as ObjectTypeSymbol;
247 :
248 110476 : cl.add_hidden_method (default_handler);
249 110476 : default_handler.check (context);
250 : }
251 :
252 145971 : if (has_attribute ("HasEmitter")) {
253 18613 : emitter = new Method (name, return_type, source_reference);
254 :
255 18613 : emitter.owner = owner;
256 18613 : emitter.access = access;
257 :
258 18613 : var body = new Block (source_reference);
259 18613 : var call = new MethodCall (new MemberAccess.simple (name, source_reference), source_reference);
260 :
261 71505 : foreach (Parameter param in parameters) {
262 26446 : emitter.add_parameter (param);
263 26446 : call.add_argument (new MemberAccess.simple (param.name, source_reference));
264 : }
265 :
266 18613 : if (return_type is VoidType) {
267 17017 : body.add_statement (new ExpressionStatement (call, source_reference));
268 : } else {
269 1596 : body.add_statement (new ReturnStatement (call, source_reference));
270 : }
271 18613 : emitter.body = body;
272 :
273 18613 : unowned ObjectTypeSymbol? cl = parent_symbol as ObjectTypeSymbol;
274 :
275 18613 : cl.add_hidden_method (emitter);
276 18613 : if (!external_package) {
277 4 : emitter.check (context);
278 : }
279 : }
280 :
281 :
282 127358 : if (!external_package && !hides && get_hidden_member () != null) {
283 0 : Report.warning (source_reference, "%s hides inherited signal `%s'. Use the `new' keyword if hiding was intentional", get_full_name (), get_hidden_member ().get_full_name ());
284 : }
285 :
286 127358 : return !error;
287 : }
288 : }
289 :
|