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
, Lockable
, 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 bool lock_used
= false;
70 private DataType _return_type
;
75 * Creates a new signal.
77 * @param name signal name
78 * @param return_type signal return type
79 * @param source_reference reference to source code
80 * @return newly created signal
82 public Signal (string name
, DataType return_type
, SourceReference? source_reference
= null, Comment? comment
= null) {
83 base (name
, source_reference
, comment
);
84 this
.return_type
= return_type
;
88 * Appends parameter to signal handler.
90 * @param param a formal parameter
92 public void add_parameter (Parameter param
) {
93 parameters
.add (param
);
94 scope
.add (param
.name
, param
);
97 public List
<Parameter
> get_parameters () {
102 * Returns generated delegate to be used for signal handlers.
106 public Delegate
get_delegate (DataType sender_type
, CodeNode node_reference
) {
107 var actual_return_type
= return_type
.get_actual_type (sender_type
, null, node_reference
);
109 var generated_delegate
= new
Delegate (null, actual_return_type
);
110 generated_delegate
.access
= SymbolAccessibility
.PUBLIC
;
111 generated_delegate
.owner
= scope
;
113 // sender parameter is never null and doesn't own its value
114 var sender_param_type
= sender_type
.copy ();
115 sender_param_type
.value_owned
= false;
116 sender_param_type
.nullable
= false;
118 generated_delegate
.sender_type
= sender_param_type
;
120 bool is_generic
= false;
122 foreach (Parameter param
in parameters
) {
123 var actual_param
= param
.copy ();
124 actual_param
.variable_type
= actual_param
.variable_type
.get_actual_type (sender_type
, null, node_reference
);
125 generated_delegate
.add_parameter (actual_param
);
127 if (actual_param
.variable_type is GenericType
) {
133 var cl
= (ObjectTypeSymbol
) parent_symbol
;
134 foreach (var type_param
in cl
.get_type_parameters ()) {
135 generated_delegate
.add_type_parameter (new
TypeParameter (type_param
.name
, type_param
.source_reference
));
138 // parameter types must refer to the delegate type parameters
139 // instead of to the class type parameters
140 foreach (var param
in generated_delegate
.get_parameters ()) {
141 var generic_type
= param
.variable_type as GenericType
;
142 if (generic_type
!= null) {
143 generic_type
.type_parameter
= generated_delegate
.get_type_parameters ().get (generated_delegate
.get_type_parameter_index (generic_type
.type_parameter
.name
));
148 scope
.add (null, generated_delegate
);
150 return generated_delegate
;
153 public override void accept (CodeVisitor visitor
) {
154 visitor
.visit_signal (this
);
157 public override void accept_children (CodeVisitor visitor
) {
158 return_type
.accept (visitor
);
160 foreach (Parameter param
in parameters
) {
161 param
.accept (visitor
);
163 if (default_handler
== null && body
!= null) {
164 body
.accept (visitor
);
165 } else if (default_handler
!= null) {
166 default_handler
.accept (visitor
);
168 if (emitter
!= null) {
169 emitter
.accept (visitor
);
173 public bool get_lock_used () {
177 public void set_lock_used (bool used
) {
181 public override void replace_type (DataType old_type
, DataType new_type
) {
182 if (return_type
== old_type
) {
183 return_type
= new_type
;
187 public override bool check (CodeContext context
) {
194 return_type
.check (context
);
196 foreach (Parameter param
in parameters
) {
197 if (param
.ellipsis
) {
198 Report
.error (param
.source_reference
, "Signals with variable argument lists are not supported");
202 param
.check (context
);
205 if (!is_virtual
&& body
!= null) {
206 Report
.error (source_reference
, "Only virtual signals can have a default signal handler body");
211 default_handler
= new
Method (name
, return_type
, source_reference
);
213 default_handler
.owner
= owner
;
214 default_handler
.access
= access
;
215 default_handler
.external
= external
;
216 default_handler
.hides
= hides
;
217 default_handler
.is_virtual
= true;
218 default_handler
.signal_reference
= this
;
219 default_handler
.body
= body
;
222 foreach (Parameter param
in parameters
) {
223 default_handler
.add_parameter (param
);
226 var cl
= parent_symbol as ObjectTypeSymbol
;
228 cl
.add_hidden_method (default_handler
);
229 default_handler
.check (context
);
232 if (!external_package
&& get_attribute ("HasEmitter") != null) {
233 emitter
= new
Method (name
, return_type
, source_reference
);
235 emitter
.owner
= owner
;
236 emitter
.access
= access
;
238 var body
= new
Block (source_reference
);
239 var call
= new
MethodCall (new MemberAccess
.simple (name
, source_reference
), source_reference
);
241 foreach (Parameter param
in parameters
) {
242 emitter
.add_parameter (param
);
243 call
.add_argument (new MemberAccess
.simple (param
.name
, source_reference
));
246 if (return_type is VoidType
) {
247 body
.add_statement (new
ExpressionStatement (call
, source_reference
));
249 body
.add_statement (new
ReturnStatement (call
, source_reference
));
253 var cl
= parent_symbol as ObjectTypeSymbol
;
255 cl
.add_hidden_method (emitter
);
256 emitter
.check (context
);
260 if (!external_package
&& !hides
&& get_hidden_member () != null) {
261 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 ()));