Release 0.41.92
[vala-gnome.git] / vala / valasignal.vala
blob9e971b6f8edd44584ed729acdcac443da977c7aa
1 /* valasignal.vala
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
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
25 /**
26 * Represents an object signal. Signals enable objects to provide notifications.
28 public class Vala.Signal : Symbol, Callable {
29 /**
30 * The return type of handlers of this signal.
32 public DataType return_type {
33 get { return _return_type; }
34 set {
35 _return_type = value;
36 _return_type.parent_node = this;
40 public Block body {
41 get { return _body; }
42 set {
43 _body = value;
44 if (_body != null) {
45 _body.owner = scope;
50 /**
51 * Specifies whether this signal has virtual method handler.
53 public bool is_virtual { get; set; }
55 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 public Method default_handler { get; private set; }
62 /**
63 * Refers to the public signal emitter method, which is an anonymous
64 * function in the scope.
65 * */
66 public Method emitter { get; private set; }
68 private DataType _return_type;
70 private Block _body;
72 /**
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;
85 /**
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 () {
96 return parameters;
99 /**
100 * Returns generated delegate to be used for signal handlers.
102 * @return delegate
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) {
126 is_generic = true;
130 if (is_generic) {
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) {
178 if (checked) {
179 return !error;
182 checked = true;
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");
189 return false;
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");
200 if (is_virtual) {
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));
238 } else {
239 body.add_statement (new ReturnStatement (call, source_reference));
241 emitter.body = body;
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 ()));
254 return !error;