3 * Copyright (C) 2006-2012 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 an object signal. Signals enable objects to provide notifications.
28 public class Vala
.Signal
: Symbol
, Callable
{
30 * The return type of handlers of this signal.
32 public DataType return_type
{
33 get { return _return_type
; }
36 _return_type
.parent_node
= this
;
51 * Specifies whether this signal has virtual method handler.
53 public bool is_virtual
{ get; set; }
55 private List
<Parameter
> parameters
= new ArrayList
<Parameter
> ();
57 * Refers to the default signal handler, which is an anonymous
58 * function in the scope.
60 public Method default_handler
{ get; private set; }
63 * Refers to the public signal emitter method, which is an anonymous
64 * function in the scope.
66 public Method emitter
{ get; private set; }
68 private DataType _return_type
;
73 * Creates a new signal.
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
80 public Signal (string name
, DataType return_type
, SourceReference? source_reference
= null, Comment? comment
= null) {
81 base (name
, source_reference
, comment
);
82 this
.return_type
= return_type
;
86 * Appends parameter to signal handler.
88 * @param param a formal parameter
90 public void add_parameter (Parameter param
) {
91 parameters
.add (param
);
92 scope
.add (param
.name
, param
);
95 public List
<Parameter
> get_parameters () {
100 * Returns generated delegate to be used for signal handlers.
104 public Delegate
get_delegate (DataType sender_type
, CodeNode node_reference
) {
105 var actual_return_type
= return_type
.get_actual_type (sender_type
, null, node_reference
);
107 var generated_delegate
= new
Delegate (null, actual_return_type
);
108 generated_delegate
.access
= SymbolAccessibility
.PUBLIC
;
109 generated_delegate
.owner
= scope
;
111 // sender parameter is never null and doesn't own its value
112 var sender_param_type
= sender_type
.copy ();
113 sender_param_type
.value_owned
= false;
114 sender_param_type
.nullable
= false;
116 generated_delegate
.sender_type
= sender_param_type
;
118 bool is_generic
= false;
120 foreach (Parameter param
in parameters
) {
121 var actual_param
= param
.copy ();
122 actual_param
.variable_type
= actual_param
.variable_type
.get_actual_type (sender_type
, null, node_reference
);
123 generated_delegate
.add_parameter (actual_param
);
125 if (actual_param
.variable_type is GenericType
) {
131 var cl
= (ObjectTypeSymbol
) parent_symbol
;
132 foreach (var type_param
in cl
.get_type_parameters ()) {
133 generated_delegate
.add_type_parameter (new
TypeParameter (type_param
.name
, type_param
.source_reference
));
136 // parameter types must refer to the delegate type parameters
137 // instead of to the class type parameters
138 foreach (var param
in generated_delegate
.get_parameters ()) {
139 var generic_type
= param
.variable_type as GenericType
;
140 if (generic_type
!= null) {
141 generic_type
.type_parameter
= generated_delegate
.get_type_parameters ().get (generated_delegate
.get_type_parameter_index (generic_type
.type_parameter
.name
));
146 scope
.add (null, generated_delegate
);
148 return generated_delegate
;
151 public override void accept (CodeVisitor visitor
) {
152 visitor
.visit_signal (this
);
155 public override void accept_children (CodeVisitor visitor
) {
156 return_type
.accept (visitor
);
158 foreach (Parameter param
in parameters
) {
159 param
.accept (visitor
);
161 if (default_handler
== null && body
!= null) {
162 body
.accept (visitor
);
163 } else if (default_handler
!= null) {
164 default_handler
.accept (visitor
);
166 if (emitter
!= null) {
167 emitter
.accept (visitor
);
171 public override void replace_type (DataType old_type
, DataType new_type
) {
172 if (return_type
== old_type
) {
173 return_type
= new_type
;
177 public override bool check (CodeContext context
) {
184 return_type
.check (context
);
186 foreach (Parameter param
in parameters
) {
187 if (param
.ellipsis
) {
188 Report
.error (param
.source_reference
, "Signals with variable argument lists are not supported");
192 param
.check (context
);
195 if (!is_virtual
&& body
!= null) {
196 Report
.error (source_reference
, "Only virtual signals can have a default signal handler body");
201 default_handler
= new
Method (name
, return_type
, source_reference
);
203 default_handler
.owner
= owner
;
204 default_handler
.access
= access
;
205 default_handler
.external
= external
;
206 default_handler
.hides
= hides
;
207 default_handler
.is_virtual
= true;
208 default_handler
.signal_reference
= this
;
209 default_handler
.body
= body
;
212 foreach (Parameter param
in parameters
) {
213 default_handler
.add_parameter (param
);
216 var cl
= parent_symbol as ObjectTypeSymbol
;
218 cl
.add_hidden_method (default_handler
);
219 default_handler
.check (context
);
222 if (!external_package
&& get_attribute ("HasEmitter") != null) {
223 emitter
= new
Method (name
, return_type
, source_reference
);
225 emitter
.owner
= owner
;
226 emitter
.access
= access
;
228 var body
= new
Block (source_reference
);
229 var call
= new
MethodCall (new MemberAccess
.simple (name
, source_reference
), source_reference
);
231 foreach (Parameter param
in parameters
) {
232 emitter
.add_parameter (param
);
233 call
.add_argument (new MemberAccess
.simple (param
.name
, source_reference
));
236 if (return_type is VoidType
) {
237 body
.add_statement (new
ExpressionStatement (call
, source_reference
));
239 body
.add_statement (new
ReturnStatement (call
, source_reference
));
243 var cl
= parent_symbol as ObjectTypeSymbol
;
245 cl
.add_hidden_method (emitter
);
246 emitter
.check (context
);
250 if (!external_package
&& !hides
&& get_hidden_member () != null) {
251 Report
.warning (source_reference
, "%s hides inherited signal `%s'. Use the `new' keyword if hiding was intentional".printf (get_full_name (), get_hidden_member ().get_full_name ()));