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
20 * Jürg Billeter <j@bitron.ch>
21 * Raffaele Sandrini <raffaele@sandrini.ch>
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) {
30 } else if (t is ErrorType
) {
32 } else if (t is ArrayType
) {
33 if (((ArrayType
) t
).element_type
.data_type
== string_type
.data_type
) {
38 } else if (t is VoidType
) {
40 } else if (dbus
&& t
.get_type_signature ().has_prefix ("(")) {
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
) {
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
);
60 if (predefined_marshal_set
.contains (signature
)) {
61 prefix
= "g_cclosure_marshal";
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) {
72 foreach (FormalParameter p
in params
) {
73 ret
= "%s_%s".printf (ret
, get_marshaller_type_name_for_parameter (p
, dbus
));
80 private string?
get_value_type_name_from_type_reference (DataType t
) {
81 if (t is PointerType
|| t
.type_parameter
!= null) {
83 } else if (t is VoidType
) {
85 } else if (t
.data_type
== string_type
.data_type
) {
87 } else if (t
.data_type is Class
|| t
.data_type is Interface
) {
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 ();
96 } else if (t
.data_type is Enum
) {
98 } else if (t is ArrayType
) {
100 } else if (t is ErrorType
) {
107 private string?
get_value_type_name_from_parameter (FormalParameter p
) {
108 if (p
.direction
!= ParameterDirection
.IN
) {
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) {
118 signature
= "%s:".printf (get_marshaller_type_name (return_type
, dbus
));
119 if (params
== null || params
.size
== 0) {
120 signature
= signature
+ "VOID";
123 foreach (FormalParameter p
in params
) {
125 signature
= signature
+ get_marshaller_type_name_for_parameter (p
, dbus
);
128 signature
= "%s,%s".printf (signature
, get_marshaller_type_name_for_parameter (p
, dbus
));
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
)) {
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 ()));
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) {
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
)) {
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"));
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
)));
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"));
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";
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
);
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"));
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"));
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
));
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
);