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 TargetValue emit_simple_assignment (Assignment assignment) {
32 if (requires_destroy (assignment.left.value_type)) {
34 ccode.add_expression (destroy_value (assignment.left.target_value));
37 if (assignment.operator == AssignmentOperator.SIMPLE) {
38 store_value (assignment.left.target_value, assignment.right.target_value, assignment.source_reference);
40 CCodeAssignmentOperator cop;
42 switch (assignment.operator) {
43 case AssignmentOperator.BITWISE_OR: cop = CCodeAssignmentOperator.BITWISE_OR; break;
44 case AssignmentOperator.BITWISE_AND: cop = CCodeAssignmentOperator.BITWISE_AND; break;
45 case AssignmentOperator.BITWISE_XOR: cop = CCodeAssignmentOperator.BITWISE_XOR; break;
46 case AssignmentOperator.ADD: cop = CCodeAssignmentOperator.ADD; break;
47 case AssignmentOperator.SUB: cop = CCodeAssignmentOperator.SUB; break;
48 case AssignmentOperator.MUL: cop = CCodeAssignmentOperator.MUL; break;
49 case AssignmentOperator.DIV: cop = CCodeAssignmentOperator.DIV; break;
50 case AssignmentOperator.PERCENT:
51 // FIXME Code duplication with CCodeBaseModule.visit_binary_expression()
52 var cleft = get_cvalue (assignment.left);
53 var cright = get_cvalue (assignment.right);
54 if (assignment.value_type.equals (double_type)) {
55 cfile.add_include ("math.h");
56 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("fmod"));
57 ccall.add_argument (cleft);
58 ccall.add_argument (cright);
59 set_cvalue (assignment.right, ccall);
60 cop = CCodeAssignmentOperator.SIMPLE;
61 } else if (assignment.value_type.equals (float_type)) {
62 cfile.add_include ("math.h");
63 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("fmodf"));
64 ccall.add_argument (cleft);
65 ccall.add_argument (cright);
66 set_cvalue (assignment.right, ccall);
67 cop = CCodeAssignmentOperator.SIMPLE;
69 cop = CCodeAssignmentOperator.PERCENT;
72 case AssignmentOperator.SHIFT_LEFT: cop = CCodeAssignmentOperator.SHIFT_LEFT; break;
73 case AssignmentOperator.SHIFT_RIGHT: cop = CCodeAssignmentOperator.SHIFT_RIGHT; break;
74 default: assert_not_reached ();
77 CCodeExpression codenode = new CCodeAssignment (get_cvalue (assignment.left), get_cvalue (assignment.right), cop);
78 ccode.add_expression (codenode);
81 if (assignment.left.value_type is ArrayType && (((ArrayType) assignment.left.value_type).inline_allocated)) {
82 unowned Variable variable = (Variable) assignment.left.symbol_reference;
83 return load_variable (variable, assignment.left.target_value);
85 return assignment.left.target_value;
89 public override void visit_assignment (Assignment assignment) {
90 if (assignment.left.error || assignment.right.error) {
91 assignment.error = true;
95 if (assignment.left.symbol_reference is Property) {
96 unowned MemberAccess ma = (MemberAccess) assignment.left;
97 unowned Property prop = (Property) assignment.left.symbol_reference;
99 store_property (prop, ma.inner, assignment.right.target_value);
100 assignment.target_value = assignment.right.target_value;
101 } else if (assignment.left.symbol_reference is Variable && is_simple_struct_creation ((Variable) assignment.left.symbol_reference, assignment.right)) {
102 // delegate to visit_object_creation_expression
104 assignment.target_value = emit_simple_assignment (assignment);
108 public override void store_value (TargetValue lvalue, TargetValue value, SourceReference? source_reference = null) {
109 var array_type = lvalue.value_type as ArrayType;
111 if (array_type != null && array_type.fixed_length) {
112 cfile.add_include ("string.h");
114 // it is necessary to use memcpy for fixed-length (stack-allocated) arrays
115 // simple assignments do not work in C
116 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
117 sizeof_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
118 var size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, get_ccodenode (array_type.length), sizeof_call);
120 var ccopy = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
121 ccopy.add_argument (get_cvalue_ (lvalue));
122 ccopy.add_argument (get_cvalue_ (value));
123 ccopy.add_argument (size);
124 ccode.add_expression (ccopy);
129 var cexpr = get_cvalue_ (value);
130 if (get_ctype (lvalue) != null) {
131 cexpr = new CCodeCastExpression (cexpr, get_ctype (lvalue));
134 ccode.add_assignment (get_cvalue_ (lvalue), cexpr);
136 if (array_type != null && ((GLibValue) lvalue).array_length_cvalues != null) {
137 var glib_value = (GLibValue) value;
138 if (glib_value.array_length_cvalues != null) {
139 for (int dim = 1; dim <= array_type.rank; dim++) {
140 ccode.add_assignment (get_array_length_cvalue (lvalue, dim), get_array_length_cvalue (value, dim));
142 } else if (glib_value.array_null_terminated) {
143 requires_array_length = true;
144 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
145 len_call.add_argument (get_cvalue_ (value));
147 ccode.add_assignment (get_array_length_cvalue (lvalue, 1), len_call);
149 for (int dim = 1; dim <= array_type.rank; dim++) {
150 ccode.add_assignment (get_array_length_cvalue (lvalue, dim), new CCodeConstant ("-1"));
154 if (array_type.rank == 1 && get_array_size_cvalue (lvalue) != null) {
155 ccode.add_assignment (get_array_size_cvalue (lvalue), get_array_length_cvalue (lvalue, 1));
159 var delegate_type = lvalue.value_type as DelegateType;
160 if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
161 var lvalue_target = get_delegate_target_cvalue (lvalue);
162 var rvalue_target = get_delegate_target_cvalue (value);
163 if (lvalue_target != null) {
164 if (rvalue_target != null) {
165 ccode.add_assignment (lvalue_target, rvalue_target);
167 Report.error (source_reference, "Assigning delegate without required target in scope");
168 ccode.add_assignment (lvalue_target, new CCodeInvalidExpression ());
170 var lvalue_destroy_notify = get_delegate_target_destroy_notify_cvalue (lvalue);
171 var rvalue_destroy_notify = get_delegate_target_destroy_notify_cvalue (value);
172 if (lvalue_destroy_notify != null) {
173 if (rvalue_destroy_notify != null) {
174 ccode.add_assignment (lvalue_destroy_notify, rvalue_destroy_notify);
176 ccode.add_assignment (lvalue_destroy_notify, new CCodeConstant ("NULL"));
183 public override void store_local (LocalVariable local, TargetValue value, bool initializer, SourceReference? source_reference = null) {
184 if (!initializer && requires_destroy (local.variable_type)) {
185 /* unref old value */
186 ccode.add_expression (destroy_local (local));
189 store_value (get_local_cvalue (local), value, source_reference);
192 public override void store_parameter (Parameter param, TargetValue _value, bool capturing_parameter = false, SourceReference? source_reference = null) {
195 bool capturing_parameter_in_coroutine = capturing_parameter && is_in_coroutine ();
197 var param_type = param.variable_type.copy ();
198 if (param.captured || is_in_coroutine ()) {
199 if (!param_type.value_owned && !no_implicit_copy (param_type)) {
200 // parameter value has been implicitly copied into a heap data structure
201 // treat parameter as owned
202 param_type.value_owned = true;
204 var old_coroutine = is_in_coroutine ();
206 current_method.coroutine = false;
209 if (requires_copy (param_type) && !capturing_parameter_in_coroutine) {
210 // do not copy value when capturing parameter in coroutine
211 // as the value was already copied on coroutine initialization
212 value = copy_value (value, param);
216 current_method.coroutine = true;
221 if (requires_destroy (param_type)) {
222 /* unref old value */
223 ccode.add_expression (destroy_parameter (param));
226 store_value (get_parameter_cvalue (param), value, source_reference);
229 public override void store_field (Vala.Field field, Vala.TargetValue? instance, Vala.TargetValue value, Vala.SourceReference? source_reference = null, bool initializer = false)
231 var lvalue = get_field_cvalue (field, instance);
232 var type = lvalue.value_type;
233 if (lvalue.actual_value_type != null) {
234 type = lvalue.actual_value_type;
236 if (!initializer && (!(field.variable_type is DelegateType) || get_ccode_delegate_target (field)) && requires_destroy (type)) {
237 /* unref old value */
238 ccode.add_expression (destroy_field (field, instance));
240 if (initializer && instance != null && get_ccode_delegate_target (field) && get_delegate_target_cvalue (value) == null) {
241 unowned DelegateType delegate_type = field.variable_type as DelegateType;
242 if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
243 ((GLibValue) value).delegate_target_cvalue = get_cvalue_ (instance);
247 store_value (lvalue, value, source_reference);