valacodegeneratorassignment.vala 12 KB
Newer Older
Jürg Billeter's avatar
Jürg Billeter committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/* valacodegeneratorassignment.vala
 *
 * Copyright (C) 2006-2007  Jürg Billeter, Raffaele Sandrini
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.

 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 *
 * Author:
 * 	Jürg Billeter <j@bitron.ch>
 *	Raffaele Sandrini <rasa@gmx.ch>
 */

using GLib;

public class Vala.CodeGenerator {
	public override void visit_end_assignment (Assignment! a) {
		MemberAccess ma = null;
		
		if (a.left is MemberAccess) {
31
			ma = (MemberAccess) a.left;
Jürg Billeter's avatar
Jürg Billeter committed
32
33
		}

34
35
		if (a.left.symbol_reference is Property) {
			var prop = (Property) a.left.symbol_reference;
Jürg Billeter's avatar
Jürg Billeter committed
36
			
37
			if (prop.set_accessor.construction && current_type_symbol is Class && ma.inner == null && in_creation_method) {
Jürg Billeter's avatar
Jürg Billeter committed
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
				// this property is used as a construction parameter
				var cpointer = new CCodeIdentifier ("__params_it");
				
				var ccomma = new CCodeCommaExpression ();
				// set name in array for current parameter
				var cnamemember = new CCodeMemberAccess.pointer (cpointer, "name");
				var cnameassign = new CCodeAssignment (cnamemember, prop.get_canonical_cconstant ());
				ccomma.append_expression (cnameassign);
				
				var gvaluearg = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (cpointer, "value"));
				
				// initialize GValue in array for current parameter
				var cvalueinit = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
				cvalueinit.add_argument (gvaluearg);
				cvalueinit.add_argument (new CCodeIdentifier (prop.type_reference.data_type.get_type_id ()));
				ccomma.append_expression (cvalueinit);
				
				// set GValue for current parameter
				var cvalueset = new CCodeFunctionCall (get_value_setter_function (prop.type_reference));
				cvalueset.add_argument (gvaluearg);
				cvalueset.add_argument ((CCodeExpression) a.right.ccodenode);
				ccomma.append_expression (cvalueset);
				
				// move pointer to next parameter in array
				ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, cpointer));
				
				a.ccodenode = ccomma;
			} else {
66
				CCodeExpression cexpr = (CCodeExpression) a.right.ccodenode;
Jürg Billeter's avatar
Jürg Billeter committed
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
				
				if (!prop.no_accessor_method
				    && prop.type_reference.data_type != null
				    && prop.type_reference.data_type.is_reference_type ()
				    && a.right.static_type.data_type != null
				    && prop.type_reference.data_type != a.right.static_type.data_type) {
					/* cast is necessary */
					var ccast = new CCodeFunctionCall (new CCodeIdentifier (prop.type_reference.data_type.get_upper_case_cname (null)));
					ccast.add_argument (cexpr);
					cexpr = ccast;
				}
				
				if (a.operator != AssignmentOperator.SIMPLE) {
					CCodeBinaryOperator cop;
					if (a.operator == AssignmentOperator.BITWISE_OR) {
						cop = CCodeBinaryOperator.BITWISE_OR;
					} else if (a.operator == AssignmentOperator.BITWISE_AND) {
						cop = CCodeBinaryOperator.BITWISE_AND;
					} else if (a.operator == AssignmentOperator.BITWISE_XOR) {
						cop = CCodeBinaryOperator.BITWISE_XOR;
					} else if (a.operator == AssignmentOperator.ADD) {
						cop = CCodeBinaryOperator.PLUS;
					} else if (a.operator == AssignmentOperator.SUB) {
						cop = CCodeBinaryOperator.MINUS;
					} else if (a.operator == AssignmentOperator.MUL) {
						cop = CCodeBinaryOperator.MUL;
					} else if (a.operator == AssignmentOperator.DIV) {
						cop = CCodeBinaryOperator.DIV;
					} else if (a.operator == AssignmentOperator.PERCENT) {
						cop = CCodeBinaryOperator.MOD;
					} else if (a.operator == AssignmentOperator.SHIFT_LEFT) {
						cop = CCodeBinaryOperator.SHIFT_LEFT;
					} else if (a.operator == AssignmentOperator.SHIFT_RIGHT) {
						cop = CCodeBinaryOperator.SHIFT_RIGHT;
					}
					cexpr = new CCodeBinaryExpression (cop, (CCodeExpression) a.left.ccodenode, new CCodeParenthesizedExpression (cexpr));
				}
				
				var ccall = get_property_set_call (prop, ma, cexpr);
				
107
108
109
110
111
112
113
114
115
116
				// assignments are expressions, so return the current property value, except if we're sure that it can't be used
				if (!(a.parent_node is ExpressionStatement)) {
					var ccomma = new CCodeCommaExpression ();
					ccomma.append_expression (ccall); // update property
					ccomma.append_expression ((CCodeExpression) ma.ccodenode); // current property value
					
					a.ccodenode = ccomma;
				} else {
					a.ccodenode = ccall;
				}
Jürg Billeter's avatar
Jürg Billeter committed
117
			}
118
119
		} else if (a.left.symbol_reference is Signal) {
			var sig = (Signal) a.left.symbol_reference;
Jürg Billeter's avatar
Jürg Billeter committed
120
			
121
			var m = (Method) a.right.symbol_reference;
Jürg Billeter's avatar
Jürg Billeter committed
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158

			string connect_func;
			bool disconnect = false;

			if (a.operator == AssignmentOperator.ADD) {
				connect_func = "g_signal_connect_object";
				if (!m.instance) {
					connect_func = "g_signal_connect";
				}
			} else if (a.operator == AssignmentOperator.SUB) {
				connect_func = "g_signal_handlers_disconnect_matched";
				disconnect = true;
			} else {
				a.error = true;
				Report.error (a.source_reference, "Specified compound assignment type for signals not supported.");
				return;
			}

			var ccall = new CCodeFunctionCall (new CCodeIdentifier (connect_func));
		
			if (ma.inner != null) {
				ccall.add_argument ((CCodeExpression) ma.inner.ccodenode);
			} else {
				ccall.add_argument (new CCodeIdentifier ("self"));
			}

			if (!disconnect) {
				ccall.add_argument (sig.get_canonical_cconstant ());
			} else {
				ccall.add_argument (new CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
				
				// get signal id
				var ccomma = new CCodeCommaExpression ();
				var temp_decl = get_temp_variable_declarator (uint_type);
				temp_vars.prepend (temp_decl);
				var parse_call = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_parse_name"));
				parse_call.add_argument (sig.get_canonical_cconstant ());
159
				var decl_type = (DataType) sig.parent_symbol;
Jürg Billeter's avatar
Jürg Billeter committed
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
				parse_call.add_argument (new CCodeIdentifier (decl_type.get_type_id ()));
				parse_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_decl.name)));
				parse_call.add_argument (new CCodeConstant ("NULL"));
				parse_call.add_argument (new CCodeConstant ("FALSE"));
				ccomma.append_expression (parse_call);
				ccomma.append_expression (new CCodeIdentifier (temp_decl.name));
				
				ccall.add_argument (ccomma);

				ccall.add_argument (new CCodeConstant ("0"));
				ccall.add_argument (new CCodeConstant ("NULL"));
			}

			ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier (m.get_cname ()), "GCallback"));

			if (m.instance) {
				if (a.right is MemberAccess) {
					var right_ma = (MemberAccess) a.right;
					if (right_ma.inner != null) {
						ccall.add_argument ((CCodeExpression) right_ma.inner.ccodenode);
					} else {
						ccall.add_argument (new CCodeIdentifier ("self"));
					}
				} else if (a.right is LambdaExpression) {
					ccall.add_argument (new CCodeIdentifier ("self"));
				}
				if (!disconnect) {
					ccall.add_argument (new CCodeConstant ("0"));
				}
			} else {
				ccall.add_argument (new CCodeConstant ("NULL"));
			}
			
			a.ccodenode = ccall;
		} else {
			/* explicitly use strong reference as ccast gets
			 * unrefed at end of inner block
			 */
198
			CCodeExpression rhs = (CCodeExpression) a.right.ccodenode;
Jürg Billeter's avatar
Jürg Billeter committed
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
			
			if (a.left.static_type.data_type != null
			    && a.right.static_type.data_type != null
			    && a.left.static_type.data_type.is_reference_type ()
			    && a.right.static_type.data_type != a.left.static_type.data_type) {
				var ccast = new CCodeFunctionCall (new CCodeIdentifier (a.left.static_type.data_type.get_upper_case_cname (null)));
				ccast.add_argument (rhs);
				rhs = ccast;
			}
			
			bool unref_old = (memory_management && a.left.static_type.takes_ownership);
			bool array = false;
			if (a.left.static_type.data_type is Array) {
				array = !(get_array_length_cexpression (a.left, 1) is CCodeConstant);
			}
			
			if (unref_old || array) {
				var ccomma = new CCodeCommaExpression ();
				
				var temp_decl = get_temp_variable_declarator (a.left.static_type);
				temp_vars.prepend (temp_decl);
				ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (temp_decl.name), rhs));
				if (unref_old) {
					/* unref old value */
					ccomma.append_expression (get_unref_expression ((CCodeExpression) a.left.ccodenode, a.left.static_type));
				}
				
				if (array) {
					var lhs_array_len = get_array_length_cexpression (a.left, 1);
					var rhs_array_len = get_array_length_cexpression (a.right, 1);
					ccomma.append_expression (new CCodeAssignment (lhs_array_len, rhs_array_len));
				}
				
				ccomma.append_expression (new CCodeIdentifier (temp_decl.name));
				
				rhs = ccomma;
			}
			
			var cop = CCodeAssignmentOperator.SIMPLE;
			if (a.operator == AssignmentOperator.BITWISE_OR) {
				cop = CCodeAssignmentOperator.BITWISE_OR;
			} else if (a.operator == AssignmentOperator.BITWISE_AND) {
				cop = CCodeAssignmentOperator.BITWISE_AND;
			} else if (a.operator == AssignmentOperator.BITWISE_XOR) {
				cop = CCodeAssignmentOperator.BITWISE_XOR;
			} else if (a.operator == AssignmentOperator.ADD) {
				cop = CCodeAssignmentOperator.ADD;
			} else if (a.operator == AssignmentOperator.SUB) {
				cop = CCodeAssignmentOperator.SUB;
			} else if (a.operator == AssignmentOperator.MUL) {
				cop = CCodeAssignmentOperator.MUL;
			} else if (a.operator == AssignmentOperator.DIV) {
				cop = CCodeAssignmentOperator.DIV;
			} else if (a.operator == AssignmentOperator.PERCENT) {
				cop = CCodeAssignmentOperator.PERCENT;
			} else if (a.operator == AssignmentOperator.SHIFT_LEFT) {
				cop = CCodeAssignmentOperator.SHIFT_LEFT;
			} else if (a.operator == AssignmentOperator.SHIFT_RIGHT) {
				cop = CCodeAssignmentOperator.SHIFT_RIGHT;
			}
		
			a.ccodenode = new CCodeAssignment ((CCodeExpression) a.left.ccodenode, rhs, cop);
		}
	}

264
	private CCodeFunctionCall get_property_set_call (Property! prop, MemberAccess! ma, CCodeExpression! cexpr) {
265
		var cl = (Class) prop.parent_symbol;
Jürg Billeter's avatar
Jürg Billeter committed
266
267
		var set_func = "g_object_set";
		
268
		var base_property = prop;
Jürg Billeter's avatar
Jürg Billeter committed
269
		if (!prop.no_accessor_method) {
270
271
272
273
274
			if (prop.base_property != null) {
				base_property = prop.base_property;
			} else if (prop.base_interface_property != null) {
				base_property = prop.base_interface_property;
			}
275
			var base_property_type = (DataType) base_property.parent_symbol;
276
			set_func = "%s_set_%s".printf (base_property_type.get_lower_case_cname (null), base_property.name);
Jürg Billeter's avatar
Jürg Billeter committed
277
278
279
280
281
		}
		
		var ccall = new CCodeFunctionCall (new CCodeIdentifier (set_func));

		/* target instance is first argument */
282
		CCodeExpression instance;
Jürg Billeter's avatar
Jürg Billeter committed
283
284
285
286
287
		var req_cast = false;

		if (ma.inner == null) {
			instance = new CCodeIdentifier ("self");
			/* require casts for inherited properties */
288
			req_cast = (base_property.parent_symbol != current_type_symbol);
Jürg Billeter's avatar
Jürg Billeter committed
289
290
291
292
		} else {
			instance = (CCodeExpression) ma.inner.ccodenode;
			/* require casts if the type of the used instance is
			 * different than the type which declared the property */
293
			req_cast = base_property.parent_symbol != ma.inner.static_type.data_type;
Jürg Billeter's avatar
Jürg Billeter committed
294
295
		}
		
296
297
		if (req_cast && ((DataType) prop.parent_symbol).is_reference_type ()) {
			var ccast = new CCodeFunctionCall (new CCodeIdentifier (((DataType) base_property.parent_symbol).get_upper_case_cname (null)));
Jürg Billeter's avatar
Jürg Billeter committed
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
			ccast.add_argument (instance);
			instance = ccast;
		}

		ccall.add_argument (instance);

		if (prop.no_accessor_method) {
			/* property name is second argument of g_object_set */
			ccall.add_argument (prop.get_canonical_cconstant ());
		}
			
		ccall.add_argument (cexpr);
		
		if (prop.no_accessor_method) {
			ccall.add_argument (new CCodeConstant ("NULL"));
		}

		return ccall;
	}
}