1 /* valaccodeassignmentmodule.vala
3 * Copyright (C) 2006-2010 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
28 * The link between an assignment and generated code.
30 public class Vala
.CCodeAssignmentModule
: CCodeMemberAccessModule
{
31 CCodeExpression?
emit_property_assignment (Assignment assignment
) {
32 var ma
= assignment
.left as MemberAccess
;
34 var prop
= (Property
) assignment
.left
.symbol_reference
;
36 if (!(prop is DynamicProperty
)) {
37 generate_property_accessor_declaration (prop
.set_accessor
, cfile
);
39 if (!prop
.external
&& prop
.external_package
) {
40 // internal VAPI properties
41 // only add them once per source file
42 if (add_generated_external_symbol (prop
)) {
43 visit_property (prop
);
48 CCodeExpression cexpr
= get_cvalue (assignment
.right
);
50 if (prop
.property_type
.is_real_non_null_struct_type ()) {
51 cexpr
= get_address_of_expression (assignment
.right
, cexpr
);
54 if (assignment
.operator
!= AssignmentOperator
.SIMPLE
) {
55 CCodeBinaryOperator cop
;
56 if (assignment
.operator
== AssignmentOperator
.BITWISE_OR
) {
57 cop
= CCodeBinaryOperator
.BITWISE_OR
;
58 } else if (assignment
.operator
== AssignmentOperator
.BITWISE_AND
) {
59 cop
= CCodeBinaryOperator
.BITWISE_AND
;
60 } else if (assignment
.operator
== AssignmentOperator
.BITWISE_XOR
) {
61 cop
= CCodeBinaryOperator
.BITWISE_XOR
;
62 } else if (assignment
.operator
== AssignmentOperator
.ADD
) {
63 cop
= CCodeBinaryOperator
.PLUS
;
64 } else if (assignment
.operator
== AssignmentOperator
.SUB
) {
65 cop
= CCodeBinaryOperator
.MINUS
;
66 } else if (assignment
.operator
== AssignmentOperator
.MUL
) {
67 cop
= CCodeBinaryOperator
.MUL
;
68 } else if (assignment
.operator
== AssignmentOperator
.DIV
) {
69 cop
= CCodeBinaryOperator
.DIV
;
70 } else if (assignment
.operator
== AssignmentOperator
.PERCENT
) {
71 cop
= CCodeBinaryOperator
.MOD
;
72 } else if (assignment
.operator
== AssignmentOperator
.SHIFT_LEFT
) {
73 cop
= CCodeBinaryOperator
.SHIFT_LEFT
;
74 } else if (assignment
.operator
== AssignmentOperator
.SHIFT_RIGHT
) {
75 cop
= CCodeBinaryOperator
.SHIFT_RIGHT
;
77 assert_not_reached ();
79 cexpr
= new
CCodeBinaryExpression (cop
, (CCodeExpression
) get_ccodenode (assignment
.left
), cexpr
);
82 store_property (prop
, ma
, cexpr
, assignment
.right
);
84 // assignments are expressions, so return the current property value, except if we're sure that it can't be used
85 if (assignment
.parent_node is ExpressionStatement
) {
88 return get_ccodenode (ma
); // current property value
92 CCodeExpression?
emit_simple_assignment (Assignment assignment
) {
93 CCodeExpression rhs
= get_cvalue (assignment
.right
);
94 CCodeExpression lhs
= (CCodeExpression
) get_ccodenode (assignment
.left
);
96 bool unref_old
= requires_destroy (assignment
.left
.value_type
);
98 bool instance_delegate
= false;
99 if (assignment
.left
.value_type is ArrayType
) {
100 var array_field
= assignment
.left
.symbol_reference as Field
;
101 array
= (array_field
== null || !array_field
.no_array_length
);
102 } else if (assignment
.left
.value_type is DelegateType
) {
103 var delegate_type
= (DelegateType
) assignment
.left
.value_type
;
104 if (delegate_type
.delegate_symbol
.has_target
) {
105 var delegate_field
= assignment
.left
.symbol_reference as Field
;
106 if (delegate_field
== null || !delegate_field
.no_delegate_target
) {
107 instance_delegate
= true;
112 if (unref_old
|| array
|| instance_delegate
) {
113 if (!is_pure_ccode_expression (lhs
)) {
114 /* Assign lhs to temp var to avoid repeating side effect */
115 var lhs_value_type
= assignment
.left
.value_type
.copy ();
116 string lhs_temp_name
= "_tmp%d_".printf (next_temp_var_id
++);
117 var lhs_temp
= new
LocalVariable (lhs_value_type
, "*" + lhs_temp_name
);
118 emit_temp_var (lhs_temp
);
119 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (lhs_temp_name
), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, lhs
)));
120 lhs
= new
CCodeParenthesizedExpression (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_variable_cexpression (lhs_temp_name
)));
123 var temp_decl
= get_temp_variable (assignment
.left
.value_type
, true, null, false);
124 emit_temp_var (temp_decl
);
125 ccode
.add_expression (new
CCodeAssignment (get_variable_cexpression (temp_decl
.name
), rhs
));
127 /* unref old value */
128 ccode
.add_expression (get_unref_expression (lhs
, assignment
.left
.value_type
, assignment
.left
));
132 var array_type
= (ArrayType
) assignment
.left
.value_type
;
133 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
134 var lhs_array_len
= get_array_length_cexpression (assignment
.left
, dim
);
135 var rhs_array_len
= get_array_length_cexpression (assignment
.right
, dim
);
136 ccode
.add_expression (new
CCodeAssignment (lhs_array_len
, rhs_array_len
));
138 if (array_type
.rank
== 1) {
139 var array_var
= assignment
.left
.symbol_reference
;
140 var array_local
= array_var as LocalVariable
;
141 if (array_var
!= null && array_var
.is_internal_symbol ()
142 && ((array_var is LocalVariable
&& !array_local
.captured
) || array_var is Field
)) {
143 var lhs_array_size
= get_array_size_cvalue (assignment
.left
.target_value
);
144 var rhs_array_len
= get_array_length_cexpression (assignment
.left
, 1);
145 ccode
.add_expression (new
CCodeAssignment (lhs_array_size
, rhs_array_len
));
148 } else if (instance_delegate
) {
149 CCodeExpression lhs_delegate_target_destroy_notify
, rhs_delegate_target_destroy_notify
;
150 var lhs_delegate_target
= get_delegate_target_cexpression (assignment
.left
, out lhs_delegate_target_destroy_notify
);
151 var rhs_delegate_target
= get_delegate_target_cexpression (assignment
.right
, out rhs_delegate_target_destroy_notify
);
152 ccode
.add_expression (new
CCodeAssignment (lhs_delegate_target
, rhs_delegate_target
));
153 if (assignment
.right
.target_type
.value_owned
) {
154 ccode
.add_expression (new
CCodeAssignment (lhs_delegate_target_destroy_notify
, rhs_delegate_target_destroy_notify
));
158 rhs
= get_variable_cexpression (temp_decl
.name
);
161 var cop
= CCodeAssignmentOperator
.SIMPLE
;
162 if (assignment
.operator
== AssignmentOperator
.BITWISE_OR
) {
163 cop
= CCodeAssignmentOperator
.BITWISE_OR
;
164 } else if (assignment
.operator
== AssignmentOperator
.BITWISE_AND
) {
165 cop
= CCodeAssignmentOperator
.BITWISE_AND
;
166 } else if (assignment
.operator
== AssignmentOperator
.BITWISE_XOR
) {
167 cop
= CCodeAssignmentOperator
.BITWISE_XOR
;
168 } else if (assignment
.operator
== AssignmentOperator
.ADD
) {
169 cop
= CCodeAssignmentOperator
.ADD
;
170 } else if (assignment
.operator
== AssignmentOperator
.SUB
) {
171 cop
= CCodeAssignmentOperator
.SUB
;
172 } else if (assignment
.operator
== AssignmentOperator
.MUL
) {
173 cop
= CCodeAssignmentOperator
.MUL
;
174 } else if (assignment
.operator
== AssignmentOperator
.DIV
) {
175 cop
= CCodeAssignmentOperator
.DIV
;
176 } else if (assignment
.operator
== AssignmentOperator
.PERCENT
) {
177 cop
= CCodeAssignmentOperator
.PERCENT
;
178 } else if (assignment
.operator
== AssignmentOperator
.SHIFT_LEFT
) {
179 cop
= CCodeAssignmentOperator
.SHIFT_LEFT
;
180 } else if (assignment
.operator
== AssignmentOperator
.SHIFT_RIGHT
) {
181 cop
= CCodeAssignmentOperator
.SHIFT_RIGHT
;
184 CCodeExpression codenode
= new
CCodeAssignment (lhs
, rhs
, cop
);
186 ccode
.add_expression (codenode
);
188 if (assignment
.parent_node is ExpressionStatement
) {
195 CCodeExpression?
emit_fixed_length_array_assignment (Assignment assignment
, ArrayType array_type
) {
196 CCodeExpression rhs
= get_cvalue (assignment
.right
);
197 CCodeExpression lhs
= (CCodeExpression
) get_ccodenode (assignment
.left
);
199 cfile
.add_include ("string.h");
201 // it is necessary to use memcpy for fixed-length (stack-allocated) arrays
202 // simple assignments do not work in C
203 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
204 sizeof_call
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
205 var size
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeConstant ("%d".printf (array_type
.length
)), sizeof_call
);
206 var ccopy
= new
CCodeFunctionCall (new
CCodeIdentifier ("memcpy"));
207 ccopy
.add_argument (lhs
);
208 ccopy
.add_argument (rhs
);
209 ccopy
.add_argument (size
);
211 ccode
.add_expression (ccopy
);
213 if (assignment
.parent_node is ExpressionStatement
) {
220 public override void visit_assignment (Assignment assignment
) {
221 if (assignment
.left
.error
|| assignment
.right
.error
) {
222 assignment
.error
= true;
226 if (assignment
.left
.symbol_reference is Property
) {
227 set_cvalue (assignment
, emit_property_assignment (assignment
));
229 var array_type
= assignment
.left
.value_type as ArrayType
;
230 if (array_type
!= null && array_type
.fixed_length
) {
231 set_cvalue (assignment
, emit_fixed_length_array_assignment (assignment
, array_type
));
233 set_cvalue (assignment
, emit_simple_assignment (assignment
));
238 void store_variable (Variable variable
, TargetValue lvalue
, TargetValue value
) {
239 if (requires_destroy (variable
.variable_type
)) {
240 /* unref old value */
241 ccode
.add_expression (destroy_value (lvalue
));
244 ccode
.add_expression (new
CCodeAssignment (get_cvalue_ (lvalue
), get_cvalue_ (value
)));
246 var array_type
= variable
.variable_type as ArrayType
;
247 if (array_type
!= null) {
248 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
249 if (get_array_length_cvalue (lvalue
, dim
) != null) {
250 ccode
.add_expression (new
CCodeAssignment (get_array_length_cvalue (lvalue
, dim
), get_array_length_cvalue (value
, dim
)));
253 if (array_type
.rank
== 1) {
254 if (get_array_size_cvalue (lvalue
) != null) {
255 if (get_array_size_cvalue (value
) != null) {
256 ccode
.add_expression (new
CCodeAssignment (get_array_size_cvalue (lvalue
), get_array_size_cvalue (value
)));
258 ccode
.add_expression (new
CCodeAssignment (get_array_size_cvalue (lvalue
), get_array_length_cvalue (value
, 1)));
264 var delegate_type
= variable
.variable_type as DelegateType
;
265 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
266 if (get_delegate_target_cvalue (lvalue
) != null) {
267 ccode
.add_expression (new
CCodeAssignment (get_delegate_target_cvalue (lvalue
), get_delegate_target_cvalue (value
)));
268 if (get_delegate_target_destroy_notify_cvalue (lvalue
) != null) {
269 ccode
.add_expression (new
CCodeAssignment (get_delegate_target_destroy_notify_cvalue (lvalue
), get_delegate_target_destroy_notify_cvalue (value
)));
275 public override void store_local (LocalVariable local
, TargetValue value
) {
276 store_variable (local
, get_local_cvalue (local
), value
);