update for 0.3.3 release
[vala-lang.git] / gobject / valaccodegeneratorsignal.vala
blobf4ba0338fd2b501078e452da441de7bb3a3ae5af
1 /* valaccodegeneratorsignal.vala
3 * Copyright (C) 2006-2008 Jürg Billeter, Raffaele Sandrini
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>
21 * Raffaele Sandrini <raffaele@sandrini.ch>
24 using GLib;
26 public class Vala.CCodeGenerator {
27 private string get_marshaller_type_name (DataType t, bool dbus = false) {
28 if (t is PointerType || t.type_parameter != null) {
29 return ("POINTER");
30 } else if (t is ErrorType) {
31 return ("POINTER");
32 } else if (t is ArrayType) {
33 if (((ArrayType) t).element_type.data_type == string_type.data_type) {
34 return ("BOXED");
35 } else {
36 return ("POINTER");
38 } else if (t is VoidType) {
39 return ("VOID");
40 } else if (dbus && t.get_type_signature ().has_prefix ("(")) {
41 return ("BOXED");
42 } else {
43 return t.data_type.get_marshaller_type_name ();
47 private string get_marshaller_type_name_for_parameter (FormalParameter param, bool dbus = false) {
48 if (param.direction != ParameterDirection.IN) {
49 return ("POINTER");
50 } else {
51 return get_marshaller_type_name (param.parameter_type, dbus);
55 public string get_marshaller_function (Gee.List<FormalParameter> params, DataType return_type, string? prefix = null, bool dbus = false) {
56 var signature = get_marshaller_signature (params, return_type);
57 string ret;
59 if (prefix == null) {
60 if (predefined_marshal_set.contains (signature)) {
61 prefix = "g_cclosure_marshal";
62 } else {
63 prefix = "g_cclosure_user_marshal";
67 ret = "%s_%s_".printf (prefix, get_marshaller_type_name (return_type, dbus));
69 if (params == null || params.size == 0) {
70 ret = ret + "_VOID";
71 } else {
72 foreach (FormalParameter p in params) {
73 ret = "%s_%s".printf (ret, get_marshaller_type_name_for_parameter (p, dbus));
77 return ret;
80 private string? get_value_type_name_from_type_reference (DataType t) {
81 if (t is PointerType || t.type_parameter != null) {
82 return "gpointer";
83 } else if (t is VoidType) {
84 return "void";
85 } else if (t.data_type == string_type.data_type) {
86 return "const char*";
87 } else if (t.data_type is Class || t.data_type is Interface) {
88 return "gpointer";
89 } else if (t.data_type is Struct) {
90 var st = (Struct) t.data_type;
91 if (st.is_simple_type ()) {
92 return t.data_type.get_cname ();
93 } else {
94 return "gpointer";
96 } else if (t.data_type is Enum) {
97 return "gint";
98 } else if (t is ArrayType) {
99 return "gpointer";
100 } else if (t is ErrorType) {
101 return "gpointer";
104 return null;
107 private string? get_value_type_name_from_parameter (FormalParameter p) {
108 if (p.direction != ParameterDirection.IN) {
109 return "gpointer";
110 } else {
111 return get_value_type_name_from_type_reference (p.parameter_type);
115 private string get_marshaller_signature (Gee.List<FormalParameter> params, DataType return_type, bool dbus = false) {
116 string signature;
118 signature = "%s:".printf (get_marshaller_type_name (return_type, dbus));
119 if (params == null || params.size == 0) {
120 signature = signature + "VOID";
121 } else {
122 bool first = true;
123 foreach (FormalParameter p in params) {
124 if (first) {
125 signature = signature + get_marshaller_type_name_for_parameter (p, dbus);
126 first = false;
127 } else {
128 signature = "%s,%s".printf (signature, get_marshaller_type_name_for_parameter (p, dbus));
133 return signature;
136 public override void visit_signal (Signal sig) {
137 // parent_symbol may be null for late bound signals
138 if (sig.parent_symbol != null) {
139 var dt = sig.parent_symbol as TypeSymbol;
140 if (!dt.is_subtype_of (gobject_type)) {
141 sig.error = true;
142 Report.error (sig.source_reference, "Only classes and interfaces deriving from GLib.Object support signals. `%s' does not derive from GLib.Object.".printf (dt.get_full_name ()));
143 return;
147 sig.accept_children (this);
149 generate_marshaller (sig.get_parameters (), sig.return_type);
152 public void generate_marshaller (Gee.List<FormalParameter> params, DataType return_type, bool dbus = false) {
153 string signature;
154 int n_params, i;
156 /* check whether a signal with the same signature already exists for this source file (or predefined) */
157 signature = get_marshaller_signature (params, return_type);
158 if (predefined_marshal_set.contains (signature) || user_marshal_set.contains (signature)) {
159 return;
162 var signal_marshaller = new CCodeFunction (get_marshaller_function (params, return_type, null, dbus), "void");
163 signal_marshaller.modifiers = CCodeModifiers.STATIC;
165 signal_marshaller.add_parameter (new CCodeFormalParameter ("closure", "GClosure *"));
166 signal_marshaller.add_parameter (new CCodeFormalParameter ("return_value", "GValue *"));
167 signal_marshaller.add_parameter (new CCodeFormalParameter ("n_param_values", "guint"));
168 signal_marshaller.add_parameter (new CCodeFormalParameter ("param_values", "const GValue *"));
169 signal_marshaller.add_parameter (new CCodeFormalParameter ("invocation_hint", "gpointer"));
170 signal_marshaller.add_parameter (new CCodeFormalParameter ("marshal_data", "gpointer"));
172 source_signal_marshaller_declaration.append (signal_marshaller.copy ());
174 var marshaller_body = new CCodeBlock ();
176 var callback_decl = new CCodeFunctionDeclarator (get_marshaller_function (params, return_type, "GMarshalFunc", dbus));
177 callback_decl.add_parameter (new CCodeFormalParameter ("data1", "gpointer"));
178 n_params = 1;
179 foreach (FormalParameter p in params) {
180 callback_decl.add_parameter (new CCodeFormalParameter ("arg_%d".printf (n_params), get_value_type_name_from_parameter (p)));
181 n_params++;
183 callback_decl.add_parameter (new CCodeFormalParameter ("data2", "gpointer"));
184 marshaller_body.add_statement (new CCodeTypeDefinition (get_value_type_name_from_type_reference (return_type), callback_decl));
186 var var_decl = new CCodeDeclaration (get_marshaller_function (params, return_type, "GMarshalFunc", dbus));
187 var_decl.modifiers = CCodeModifiers.REGISTER;
188 var_decl.add_declarator (new CCodeVariableDeclarator ("callback"));
189 marshaller_body.add_statement (var_decl);
191 var_decl = new CCodeDeclaration ("GCClosure *");
192 var_decl.modifiers = CCodeModifiers.REGISTER;
193 var_decl.add_declarator (new CCodeVariableDeclarator.with_initializer ("cc", new CCodeCastExpression (new CCodeIdentifier ("closure"), "GCClosure *")));
194 marshaller_body.add_statement (var_decl);
196 var_decl = new CCodeDeclaration ("gpointer");
197 var_decl.modifiers = CCodeModifiers.REGISTER;
198 var_decl.add_declarator (new CCodeVariableDeclarator ("data1"));
199 var_decl.add_declarator (new CCodeVariableDeclarator ("data2"));
200 marshaller_body.add_statement (var_decl);
202 CCodeFunctionCall fc;
204 if (return_type.data_type != null || return_type.is_array ()) {
205 var_decl = new CCodeDeclaration (get_value_type_name_from_type_reference (return_type));
206 var_decl.add_declarator (new CCodeVariableDeclarator ("v_return"));
207 marshaller_body.add_statement (var_decl);
209 fc = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
210 fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("return_value"), new CCodeConstant ("NULL")));
211 marshaller_body.add_statement (new CCodeExpressionStatement (fc));
214 fc = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
215 fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("n_param_values"), new CCodeConstant (n_params.to_string())));
216 marshaller_body.add_statement (new CCodeExpressionStatement (fc));
218 var data = new CCodeMemberAccess (new CCodeIdentifier ("closure"), "data", true);
219 var param = new CCodeMemberAccess (new CCodeMemberAccess (new CCodeIdentifier ("param_values"), "data[0]", true), "v_pointer");
220 var cond = new CCodeFunctionCall (new CCodeConstant ("G_CCLOSURE_SWAP_DATA"));
221 cond.add_argument (new CCodeIdentifier ("closure"));
222 var true_block = new CCodeBlock ();
223 true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data1"), data)));
224 true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data2"), param)));
225 var false_block = new CCodeBlock ();
226 false_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data1"), param)));
227 false_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data2"), data)));
228 marshaller_body.add_statement (new CCodeIfStatement (cond, true_block, false_block));
230 var c_assign = new CCodeAssignment (new CCodeIdentifier ("callback"), new CCodeCastExpression (new CCodeConditionalExpression (new CCodeIdentifier ("marshal_data"), new CCodeIdentifier ("marshal_data"), new CCodeMemberAccess (new CCodeIdentifier ("cc"), "callback", true)), get_marshaller_function (params, return_type, "GMarshalFunc", dbus)));
231 marshaller_body.add_statement (new CCodeExpressionStatement (c_assign));
233 fc = new CCodeFunctionCall (new CCodeIdentifier ("callback"));
234 fc.add_argument (new CCodeIdentifier ("data1"));
235 i = 1;
236 foreach (FormalParameter p in params) {
237 string get_value_function;
238 if (p.parameter_type is PointerType || p.parameter_type.type_parameter != null || p.direction != ParameterDirection.IN) {
239 get_value_function = "g_value_get_pointer";
240 } else if (p.parameter_type is ErrorType) {
241 get_value_function = "g_value_get_pointer";
242 } else if (dbus && p.parameter_type.get_type_signature ().has_prefix ("(")) {
243 get_value_function = "g_value_get_boxed";
244 } else {
245 get_value_function = p.parameter_type.data_type.get_get_value_function ();
247 var inner_fc = new CCodeFunctionCall (new CCodeIdentifier (get_value_function));
248 inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ())));
249 fc.add_argument (inner_fc);
250 i++;
252 fc.add_argument (new CCodeIdentifier ("data2"));
254 if (return_type.data_type != null || return_type.is_array ()) {
255 marshaller_body.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("v_return"), fc)));
257 CCodeFunctionCall set_fc;
258 if (return_type.is_array ()) {
259 if (((ArrayType)return_type).element_type.data_type == string_type.data_type) {
260 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_boxed"));
261 } else {
262 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
264 } else if (return_type.type_parameter != null) {
265 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
266 } else if (return_type is ErrorType) {
267 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
268 } else if (return_type.data_type == string_type.data_type) {
269 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_string"));
270 } else if (return_type.data_type is Class || return_type.data_type is Interface) {
271 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_object"));
272 } else if (dbus && return_type.get_type_signature ().has_prefix ("(")) {
273 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_boxed"));
274 } else {
275 set_fc = new CCodeFunctionCall (new CCodeIdentifier (return_type.data_type.get_set_value_function ()));
277 set_fc.add_argument (new CCodeIdentifier ("return_value"));
278 set_fc.add_argument (new CCodeIdentifier ("v_return"));
280 marshaller_body.add_statement (new CCodeExpressionStatement (set_fc));
281 } else {
282 marshaller_body.add_statement (new CCodeExpressionStatement (fc));
285 signal_marshaller.block = marshaller_body;
287 source_signal_marshaller_definition.append (signal_marshaller);
288 user_marshal_set.add (signature);