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_simple_assignment (Assignment assignment
) {
32 Variable variable
= (Variable
) assignment
.left
.symbol_reference
;
34 CCodeExpression rhs
= get_cvalue (assignment
.right
);
35 CCodeExpression lhs
= (CCodeExpression
) get_ccodenode (assignment
.left
);
37 bool unref_old
= requires_destroy (assignment
.left
.value_type
);
39 bool instance_delegate
= false;
40 if (assignment
.left
.value_type is ArrayType
) {
41 array
= !(variable is Field
) || !variable
.no_array_length
;
42 } else if (assignment
.left
.value_type is DelegateType
) {
43 var delegate_type
= (DelegateType
) assignment
.left
.value_type
;
44 if (delegate_type
.delegate_symbol
.has_target
) {
45 instance_delegate
= !(variable is Field
) || !variable
.no_delegate_target
;
49 if (unref_old
|| array
|| instance_delegate
) {
50 if (!is_pure_ccode_expression (lhs
)) {
51 /* Assign lhs to temp var to avoid repeating side effect */
52 var lhs_value_type
= assignment
.left
.value_type
.copy ();
53 string lhs_temp_name
= "_tmp%d_".printf (next_temp_var_id
++);
54 var lhs_temp
= new
LocalVariable (lhs_value_type
, "*" + lhs_temp_name
);
55 emit_temp_var (lhs_temp
);
56 ccode
.add_assignment (get_variable_cexpression (lhs_temp_name
), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, lhs
));
57 lhs
= new
CCodeParenthesizedExpression (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, get_variable_cexpression (lhs_temp_name
)));
60 var temp_decl
= get_temp_variable (assignment
.left
.value_type
, true, null, false);
61 emit_temp_var (temp_decl
);
62 ccode
.add_assignment (get_variable_cexpression (temp_decl
.name
), rhs
);
65 ccode
.add_expression (get_unref_expression (lhs
, assignment
.left
.value_type
, assignment
.left
));
68 if (array
&& !variable
.no_array_length
&& !variable
.array_null_terminated
) {
69 var array_type
= (ArrayType
) assignment
.left
.value_type
;
70 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
71 var lhs_array_len
= get_array_length_cexpression (assignment
.left
, dim
);
72 var rhs_array_len
= get_array_length_cexpression (assignment
.right
, dim
);
73 ccode
.add_assignment (lhs_array_len
, rhs_array_len
);
75 if (array_type
.rank
== 1) {
76 var array_var
= assignment
.left
.symbol_reference
;
77 var array_local
= array_var as LocalVariable
;
78 if (array_var
!= null && array_var
.is_internal_symbol ()
79 && ((array_var is LocalVariable
&& !array_local
.captured
) || array_var is Field
)) {
80 var lhs_array_size
= get_array_size_cvalue (assignment
.left
.target_value
);
81 var rhs_array_len
= get_array_length_cexpression (assignment
.left
, 1);
82 ccode
.add_assignment (lhs_array_size
, rhs_array_len
);
85 } else if (instance_delegate
) {
86 CCodeExpression lhs_delegate_target_destroy_notify
, rhs_delegate_target_destroy_notify
;
87 var lhs_delegate_target
= get_delegate_target_cexpression (assignment
.left
, out lhs_delegate_target_destroy_notify
);
88 var rhs_delegate_target
= get_delegate_target_cexpression (assignment
.right
, out rhs_delegate_target_destroy_notify
);
89 ccode
.add_assignment (lhs_delegate_target
, rhs_delegate_target
);
90 if (assignment
.right
.target_type
.value_owned
) {
91 ccode
.add_assignment (lhs_delegate_target_destroy_notify
, rhs_delegate_target_destroy_notify
);
95 rhs
= get_variable_cexpression (temp_decl
.name
);
98 var cop
= CCodeAssignmentOperator
.SIMPLE
;
99 if (assignment
.operator
== AssignmentOperator
.BITWISE_OR
) {
100 cop
= CCodeAssignmentOperator
.BITWISE_OR
;
101 } else if (assignment
.operator
== AssignmentOperator
.BITWISE_AND
) {
102 cop
= CCodeAssignmentOperator
.BITWISE_AND
;
103 } else if (assignment
.operator
== AssignmentOperator
.BITWISE_XOR
) {
104 cop
= CCodeAssignmentOperator
.BITWISE_XOR
;
105 } else if (assignment
.operator
== AssignmentOperator
.ADD
) {
106 cop
= CCodeAssignmentOperator
.ADD
;
107 } else if (assignment
.operator
== AssignmentOperator
.SUB
) {
108 cop
= CCodeAssignmentOperator
.SUB
;
109 } else if (assignment
.operator
== AssignmentOperator
.MUL
) {
110 cop
= CCodeAssignmentOperator
.MUL
;
111 } else if (assignment
.operator
== AssignmentOperator
.DIV
) {
112 cop
= CCodeAssignmentOperator
.DIV
;
113 } else if (assignment
.operator
== AssignmentOperator
.PERCENT
) {
114 cop
= CCodeAssignmentOperator
.PERCENT
;
115 } else if (assignment
.operator
== AssignmentOperator
.SHIFT_LEFT
) {
116 cop
= CCodeAssignmentOperator
.SHIFT_LEFT
;
117 } else if (assignment
.operator
== AssignmentOperator
.SHIFT_RIGHT
) {
118 cop
= CCodeAssignmentOperator
.SHIFT_RIGHT
;
121 CCodeExpression codenode
= new
CCodeAssignment (lhs
, rhs
, cop
);
123 ccode
.add_expression (codenode
);
128 CCodeExpression?
emit_fixed_length_array_assignment (Assignment assignment
, ArrayType array_type
) {
129 CCodeExpression rhs
= get_cvalue (assignment
.right
);
130 CCodeExpression lhs
= (CCodeExpression
) get_ccodenode (assignment
.left
);
132 cfile
.add_include ("string.h");
134 // it is necessary to use memcpy for fixed-length (stack-allocated) arrays
135 // simple assignments do not work in C
136 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
137 sizeof_call
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
138 var size
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeConstant ("%d".printf (array_type
.length
)), sizeof_call
);
139 var ccopy
= new
CCodeFunctionCall (new
CCodeIdentifier ("memcpy"));
140 ccopy
.add_argument (lhs
);
141 ccopy
.add_argument (rhs
);
142 ccopy
.add_argument (size
);
144 ccode
.add_expression (ccopy
);
149 public override void visit_assignment (Assignment assignment
) {
150 if (assignment
.left
.error
|| assignment
.right
.error
) {
151 assignment
.error
= true;
155 if (assignment
.left
.symbol_reference is Property
) {
156 var ma
= assignment
.left as MemberAccess
;
157 var prop
= (Property
) assignment
.left
.symbol_reference
;
159 store_property (prop
, ma
.inner
, assignment
.right
.target_value
);
161 set_cvalue (assignment
, get_ccodenode (assignment
.right
));
163 var array_type
= assignment
.left
.value_type as ArrayType
;
164 if (array_type
!= null && array_type
.fixed_length
) {
165 set_cvalue (assignment
, emit_fixed_length_array_assignment (assignment
, array_type
));
167 set_cvalue (assignment
, emit_simple_assignment (assignment
));
172 void store_variable (Variable variable
, TargetValue lvalue
, TargetValue value
, bool initializer
) {
173 var array_type
= variable
.variable_type as ArrayType
;
175 if (array_type
!= null && array_type
.fixed_length
) {
176 cfile
.add_include ("string.h");
178 // it is necessary to use memcpy for fixed-length (stack-allocated) arrays
179 // simple assignments do not work in C
180 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
181 sizeof_call
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
182 var size
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeConstant ("%d".printf (array_type
.length
)), sizeof_call
);
184 var ccopy
= new
CCodeFunctionCall (new
CCodeIdentifier ("memcpy"));
185 ccopy
.add_argument (get_cvalue_ (lvalue
));
186 ccopy
.add_argument (get_cvalue_ (value
));
187 ccopy
.add_argument (size
);
188 ccode
.add_expression (ccopy
);
193 ccode
.add_assignment (get_cvalue_ (lvalue
), get_cvalue_ (value
));
195 if (array_type
!= null) {
196 if (!variable
.no_array_length
&& !variable
.array_null_terminated
) {
197 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
198 ccode
.add_assignment (get_array_length_cvalue (lvalue
, dim
), get_array_length_cvalue (value
, dim
));
200 if (array_type
.rank
== 1) {
201 if (get_array_size_cvalue (lvalue
) != null) {
202 if (get_array_size_cvalue (value
) != null) {
203 ccode
.add_assignment (get_array_size_cvalue (lvalue
), get_array_size_cvalue (value
));
205 ccode
.add_assignment (get_array_size_cvalue (lvalue
), get_array_length_cvalue (value
, 1));
212 var delegate_type
= variable
.variable_type as DelegateType
;
213 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
214 if (get_delegate_target_cvalue (lvalue
) != null) {
215 ccode
.add_assignment (get_delegate_target_cvalue (lvalue
), get_delegate_target_cvalue (value
));
216 if (get_delegate_target_destroy_notify_cvalue (lvalue
) != null) {
217 ccode
.add_assignment (get_delegate_target_destroy_notify_cvalue (lvalue
), get_delegate_target_destroy_notify_cvalue (value
));
223 public override void store_local (LocalVariable local
, TargetValue value
, bool initializer
) {
224 if (!initializer
&& requires_destroy (local
.variable_type
)) {
225 /* unref old value */
226 ccode
.add_expression (destroy_local (local
));
229 store_variable (local
, get_local_cvalue (local
), value
, initializer
);
232 public override void store_parameter (Parameter param
, TargetValue value
) {
233 if (requires_destroy (param
.variable_type
)) {
234 /* unref old value */
235 ccode
.add_expression (destroy_parameter (param
));
238 store_variable (param
, get_parameter_cvalue (param
), value
, false);
241 public override void store_field (Field field
, TargetValue? instance
, TargetValue value
) {
242 if (requires_destroy (field
.variable_type
)) {
243 /* unref old value */
244 ccode
.add_expression (destroy_field (field
, instance
));
247 store_variable (field
, get_field_cvalue (field
, instance
), value
, false);