1 /* valaccodeassignmentmodule.vala
3 * Copyright (C) 2006-2009 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>
29 * The link between an assignment and generated code.
31 internal class Vala
.CCodeAssignmentModule
: CCodeMemberAccessModule
{
32 public CCodeAssignmentModule (CCodeGenerator codegen
, CCodeModule? next
) {
36 CCodeExpression
emit_property_assignment (Assignment assignment
) {
37 var ma
= assignment
.left as MemberAccess
;
39 var prop
= (Property
) assignment
.left
.symbol_reference
;
41 if (!(prop is DynamicProperty
)) {
42 generate_property_accessor_declaration (prop
.set_accessor
, source_declarations
);
44 if (!prop
.external
&& prop
.external_package
) {
45 // internal VAPI properties
46 // only add them once per source file
47 if (add_generated_external_symbol (prop
)) {
48 visit_property (prop
);
53 if (prop
.set_accessor
.construction
&& current_type_symbol is Class
&& current_class
.is_subtype_of (gobject_type
) && in_creation_method
) {
54 return head
.get_construct_property_assignment (prop
.get_canonical_cconstant (), prop
.property_type
, (CCodeExpression
) assignment
.right
.ccodenode
);
56 CCodeExpression cexpr
= (CCodeExpression
) assignment
.right
.ccodenode
;
58 if (!prop
.no_accessor_method
) {
59 if (prop
.property_type
.is_real_struct_type ()) {
60 cexpr
= get_address_of_expression (assignment
.right
, cexpr
);
64 if (assignment
.operator
!= AssignmentOperator
.SIMPLE
) {
65 CCodeBinaryOperator cop
;
66 if (assignment
.operator
== AssignmentOperator
.BITWISE_OR
) {
67 cop
= CCodeBinaryOperator
.BITWISE_OR
;
68 } else if (assignment
.operator
== AssignmentOperator
.BITWISE_AND
) {
69 cop
= CCodeBinaryOperator
.BITWISE_AND
;
70 } else if (assignment
.operator
== AssignmentOperator
.BITWISE_XOR
) {
71 cop
= CCodeBinaryOperator
.BITWISE_XOR
;
72 } else if (assignment
.operator
== AssignmentOperator
.ADD
) {
73 cop
= CCodeBinaryOperator
.PLUS
;
74 } else if (assignment
.operator
== AssignmentOperator
.SUB
) {
75 cop
= CCodeBinaryOperator
.MINUS
;
76 } else if (assignment
.operator
== AssignmentOperator
.MUL
) {
77 cop
= CCodeBinaryOperator
.MUL
;
78 } else if (assignment
.operator
== AssignmentOperator
.DIV
) {
79 cop
= CCodeBinaryOperator
.DIV
;
80 } else if (assignment
.operator
== AssignmentOperator
.PERCENT
) {
81 cop
= CCodeBinaryOperator
.MOD
;
82 } else if (assignment
.operator
== AssignmentOperator
.SHIFT_LEFT
) {
83 cop
= CCodeBinaryOperator
.SHIFT_LEFT
;
84 } else if (assignment
.operator
== AssignmentOperator
.SHIFT_RIGHT
) {
85 cop
= CCodeBinaryOperator
.SHIFT_RIGHT
;
87 assert_not_reached ();
89 cexpr
= new
CCodeBinaryExpression (cop
, (CCodeExpression
) get_ccodenode (assignment
.left
), cexpr
);
92 var ccall
= get_property_set_call (prop
, ma
, cexpr
, assignment
.right
);
94 // assignments are expressions, so return the current property value, except if we're sure that it can't be used
95 if (!(assignment
.parent_node is ExpressionStatement
)) {
96 var ccomma
= new
CCodeCommaExpression ();
97 ccomma
.append_expression (ccall
); // update property
98 ccomma
.append_expression ((CCodeExpression
) get_ccodenode (ma
)); // current property value
107 CCodeExpression
emit_simple_assignment (Assignment assignment
) {
108 CCodeExpression rhs
= (CCodeExpression
) assignment
.right
.ccodenode
;
109 CCodeExpression lhs
= (CCodeExpression
) get_ccodenode (assignment
.left
);
110 CCodeCommaExpression outer_ccomma
= null;
112 bool unref_old
= requires_destroy (assignment
.left
.value_type
);
114 bool instance_delegate
= false;
115 if (assignment
.left
.value_type is ArrayType
) {
116 var array_field
= assignment
.left
.symbol_reference as Field
;
117 array
= (array_field
== null || !array_field
.no_array_length
);
118 } else if (assignment
.left
.value_type is DelegateType
) {
119 var delegate_type
= (DelegateType
) assignment
.left
.value_type
;
120 if (delegate_type
.delegate_symbol
.has_target
) {
121 var delegate_field
= assignment
.left
.symbol_reference as Field
;
122 if (delegate_field
== null || !delegate_field
.no_delegate_target
) {
123 instance_delegate
= true;
128 if (unref_old
|| array
|| instance_delegate
) {
129 var ccomma
= new
CCodeCommaExpression ();
131 if (!is_pure_ccode_expression (lhs
)) {
132 /* Assign lhs to temp var to avoid repeating side effect */
133 outer_ccomma
= new
CCodeCommaExpression ();
135 var lhs_value_type
= assignment
.left
.value_type
.copy ();
136 string lhs_temp_name
= "_tmp%d_".printf (next_temp_var_id
++);
137 var lhs_temp
= new
LocalVariable (lhs_value_type
, "*" + lhs_temp_name
);
138 temp_vars
.insert (0, lhs_temp
);
139 outer_ccomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (lhs_temp_name
), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, lhs
)));
140 lhs
= new
CCodeParenthesizedExpression (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_variable_cexpression (lhs_temp_name
)));
143 var temp_decl
= get_temp_variable (assignment
.left
.value_type
, true, null, false);
144 temp_vars
.insert (0, temp_decl
);
145 ccomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (temp_decl
.name
), rhs
));
147 /* unref old value */
148 ccomma
.append_expression (get_unref_expression (lhs
, assignment
.left
.value_type
, assignment
.left
));
152 var array_type
= (ArrayType
) assignment
.left
.value_type
;
153 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
154 var lhs_array_len
= head
.get_array_length_cexpression (assignment
.left
, dim
);
155 var rhs_array_len
= head
.get_array_length_cexpression (assignment
.right
, dim
);
156 ccomma
.append_expression (new
CCodeAssignment (lhs_array_len
, rhs_array_len
));
158 if (array_type
.rank
== 1) {
159 var array_var
= assignment
.left
.symbol_reference
;
160 if (array_var
!= null && array_var
.is_internal_symbol ()
161 && (array_var is LocalVariable
|| array_var is Field
)) {
162 var lhs_array_size
= head
.get_array_size_cexpression (assignment
.left
);
163 var rhs_array_len
= head
.get_array_length_cexpression (assignment
.left
, 1);
164 ccomma
.append_expression (new
CCodeAssignment (lhs_array_size
, rhs_array_len
));
167 } else if (instance_delegate
) {
168 CCodeExpression lhs_delegate_target_destroy_notify
, rhs_delegate_target_destroy_notify
;
169 var lhs_delegate_target
= get_delegate_target_cexpression (assignment
.left
, out lhs_delegate_target_destroy_notify
);
170 var rhs_delegate_target
= get_delegate_target_cexpression (assignment
.right
, out rhs_delegate_target_destroy_notify
);
171 ccomma
.append_expression (new
CCodeAssignment (lhs_delegate_target
, rhs_delegate_target
));
172 if (assignment
.right
.target_type
.value_owned
) {
173 ccomma
.append_expression (new
CCodeAssignment (lhs_delegate_target_destroy_notify
, rhs_delegate_target_destroy_notify
));
177 ccomma
.append_expression (get_variable_cexpression (temp_decl
.name
));
182 var cop
= CCodeAssignmentOperator
.SIMPLE
;
183 if (assignment
.operator
== AssignmentOperator
.BITWISE_OR
) {
184 cop
= CCodeAssignmentOperator
.BITWISE_OR
;
185 } else if (assignment
.operator
== AssignmentOperator
.BITWISE_AND
) {
186 cop
= CCodeAssignmentOperator
.BITWISE_AND
;
187 } else if (assignment
.operator
== AssignmentOperator
.BITWISE_XOR
) {
188 cop
= CCodeAssignmentOperator
.BITWISE_XOR
;
189 } else if (assignment
.operator
== AssignmentOperator
.ADD
) {
190 cop
= CCodeAssignmentOperator
.ADD
;
191 } else if (assignment
.operator
== AssignmentOperator
.SUB
) {
192 cop
= CCodeAssignmentOperator
.SUB
;
193 } else if (assignment
.operator
== AssignmentOperator
.MUL
) {
194 cop
= CCodeAssignmentOperator
.MUL
;
195 } else if (assignment
.operator
== AssignmentOperator
.DIV
) {
196 cop
= CCodeAssignmentOperator
.DIV
;
197 } else if (assignment
.operator
== AssignmentOperator
.PERCENT
) {
198 cop
= CCodeAssignmentOperator
.PERCENT
;
199 } else if (assignment
.operator
== AssignmentOperator
.SHIFT_LEFT
) {
200 cop
= CCodeAssignmentOperator
.SHIFT_LEFT
;
201 } else if (assignment
.operator
== AssignmentOperator
.SHIFT_RIGHT
) {
202 cop
= CCodeAssignmentOperator
.SHIFT_RIGHT
;
205 CCodeExpression codenode
= new
CCodeAssignment (lhs
, rhs
, cop
);
207 if (outer_ccomma
!= null) {
208 outer_ccomma
.append_expression (codenode
);
209 codenode
= outer_ccomma
;
215 CCodeExpression
emit_fixed_length_array_assignment (Assignment assignment
, ArrayType array_type
) {
216 CCodeExpression rhs
= (CCodeExpression
) assignment
.right
.ccodenode
;
217 CCodeExpression lhs
= (CCodeExpression
) get_ccodenode (assignment
.left
);
219 source_declarations
.add_include ("string.h");
221 // it is necessary to use memcpy for fixed-length (stack-allocated) arrays
222 // simple assignments do not work in C
223 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
224 sizeof_call
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
225 var size
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeConstant ("%d".printf (array_type
.length
)), sizeof_call
);
226 var ccopy
= new
CCodeFunctionCall (new
CCodeIdentifier ("memcpy"));
227 ccopy
.add_argument (lhs
);
228 ccopy
.add_argument (rhs
);
229 ccopy
.add_argument (size
);
234 public override void visit_assignment (Assignment assignment
) {
235 assignment
.right
.accept (codegen
);
237 if (assignment
.left
.error
|| assignment
.right
.error
) {
238 assignment
.error
= true;
242 if (assignment
.left
.symbol_reference is Property
) {
243 assignment
.ccodenode
= emit_property_assignment (assignment
);
245 var array_type
= assignment
.left
.value_type as ArrayType
;
246 if (array_type
!= null && array_type
.fixed_length
) {
247 assignment
.ccodenode
= emit_fixed_length_array_assignment (assignment
, array_type
);
249 assignment
.ccodenode
= emit_simple_assignment (assignment
);