Line data Source code
1 : /* valaccodeassignmentmodule.vala
2 : *
3 : * Copyright (C) 2006-2010 Jürg Billeter
4 : * Copyright (C) 2006-2008 Raffaele Sandrini
5 : *
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.
10 :
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.
15 :
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
19 : *
20 : * Author:
21 : * Jürg Billeter <j@bitron.ch>
22 : * Raffaele Sandrini <raffaele@sandrini.ch>
23 : */
24 :
25 : using GLib;
26 :
27 : /**
28 : * The link between an assignment and generated code.
29 : */
30 2930 : public class Vala.CCodeAssignmentModule : CCodeMemberAccessModule {
31 202 : TargetValue emit_simple_assignment (Assignment assignment) {
32 202 : if (requires_destroy (assignment.left.value_type)) {
33 : /* unref old value */
34 20 : ccode.add_expression (destroy_value (assignment.left.target_value));
35 : }
36 :
37 281 : if (assignment.operator == AssignmentOperator.SIMPLE) {
38 123 : store_value (assignment.left.target_value, assignment.right.target_value, assignment.source_reference);
39 : } else {
40 : CCodeAssignmentOperator cop;
41 :
42 79 : switch (assignment.operator) {
43 : case AssignmentOperator.BITWISE_OR: cop = CCodeAssignmentOperator.BITWISE_OR; break;
44 3 : case AssignmentOperator.BITWISE_AND: cop = CCodeAssignmentOperator.BITWISE_AND; break;
45 3 : case AssignmentOperator.BITWISE_XOR: cop = CCodeAssignmentOperator.BITWISE_XOR; break;
46 40 : case AssignmentOperator.ADD: cop = CCodeAssignmentOperator.ADD; break;
47 9 : case AssignmentOperator.SUB: cop = CCodeAssignmentOperator.SUB; break;
48 5 : case AssignmentOperator.MUL: cop = CCodeAssignmentOperator.MUL; break;
49 5 : case AssignmentOperator.DIV: cop = CCodeAssignmentOperator.DIV; break;
50 : case AssignmentOperator.PERCENT:
51 : // FIXME Code duplication with CCodeBaseModule.visit_binary_expression()
52 40557 : var cleft = get_cvalue (assignment.left);
53 5 : var cright = get_cvalue (assignment.right);
54 6 : if (assignment.value_type.equals (double_type)) {
55 1 : cfile.add_include ("math.h");
56 1 : var ccall = new CCodeFunctionCall (new CCodeIdentifier ("fmod"));
57 1 : ccall.add_argument (cleft);
58 1 : ccall.add_argument (cright);
59 1 : set_cvalue (assignment.right, ccall);
60 1 : cop = CCodeAssignmentOperator.SIMPLE;
61 5 : } else if (assignment.value_type.equals (float_type)) {
62 1 : cfile.add_include ("math.h");
63 1 : var ccall = new CCodeFunctionCall (new CCodeIdentifier ("fmodf"));
64 1 : ccall.add_argument (cleft);
65 1 : ccall.add_argument (cright);
66 1 : set_cvalue (assignment.right, ccall);
67 1 : cop = CCodeAssignmentOperator.SIMPLE;
68 : } else {
69 : cop = CCodeAssignmentOperator.PERCENT;
70 : }
71 5 : break;
72 3 : case AssignmentOperator.SHIFT_LEFT: cop = CCodeAssignmentOperator.SHIFT_LEFT; break;
73 3 : case AssignmentOperator.SHIFT_RIGHT: cop = CCodeAssignmentOperator.SHIFT_RIGHT; break;
74 0 : default: assert_not_reached ();
75 : }
76 :
77 79 : CCodeExpression codenode = new CCodeAssignment (get_cvalue (assignment.left), get_cvalue (assignment.right), cop);
78 79 : ccode.add_expression (codenode);
79 : }
80 :
81 202 : if (assignment.left.value_type is ArrayType && (((ArrayType) assignment.left.value_type).inline_allocated)) {
82 0 : unowned Variable variable = (Variable) assignment.left.symbol_reference;
83 0 : return load_variable (variable, assignment.left.target_value);
84 : } else {
85 3000 : return assignment.left.target_value;
86 : }
87 : }
88 :
89 1002 : public override void visit_assignment (Assignment assignment) {
90 1002 : if (assignment.left.error || assignment.right.error) {
91 0 : assignment.error = true;
92 0 : return;
93 : }
94 :
95 1002 : if (assignment.left.symbol_reference is Property) {
96 797 : unowned MemberAccess ma = (MemberAccess) assignment.left;
97 797 : unowned Property prop = (Property) assignment.left.symbol_reference;
98 :
99 797 : store_property (prop, ma.inner, assignment.right.target_value);
100 797 : assignment.target_value = assignment.right.target_value;
101 205 : } 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
103 : } else {
104 202 : assignment.target_value = emit_simple_assignment (assignment);
105 : }
106 : }
107 :
108 81121 : public override void store_value (TargetValue lvalue, TargetValue value, SourceReference? source_reference = null) {
109 45309 : var array_type = lvalue.value_type as ArrayType;
110 :
111 2517 : if (array_type != null && array_type.fixed_length) {
112 29 : cfile.add_include ("string.h");
113 :
114 : // it is necessary to use memcpy for fixed-length (stack-allocated) arrays
115 : // simple assignments do not work in C
116 29 : var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
117 29 : sizeof_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
118 29 : var size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, get_ccodenode (array_type.length), sizeof_call);
119 :
120 29 : var ccopy = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
121 29 : ccopy.add_argument (get_cvalue_ (lvalue));
122 29 : ccopy.add_argument (get_cvalue_ (value));
123 29 : ccopy.add_argument (size);
124 29 : ccode.add_expression (ccopy);
125 :
126 29 : return;
127 : }
128 :
129 40546 : var cexpr = get_cvalue_ (value);
130 40546 : if (get_ctype (lvalue) != null) {
131 4 : cexpr = new CCodeCastExpression (cexpr, get_ctype (lvalue));
132 : }
133 :
134 40546 : ccode.add_assignment (get_cvalue_ (lvalue), cexpr);
135 :
136 43007 : if (array_type != null && ((GLibValue) lvalue).array_length_cvalues != null) {
137 2461 : var glib_value = (GLibValue) value;
138 2461 : if (glib_value.array_length_cvalues != null) {
139 4969 : for (int dim = 1; dim <= array_type.rank; dim++) {
140 2526 : ccode.add_assignment (get_array_length_cvalue (lvalue, dim), get_array_length_cvalue (value, dim));
141 : }
142 20 : } else if (glib_value.array_null_terminated) {
143 2 : requires_array_length = true;
144 2 : var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
145 2 : len_call.add_argument (get_cvalue_ (value));
146 :
147 2 : ccode.add_assignment (get_array_length_cvalue (lvalue, 1), len_call);
148 : } else {
149 32 : for (int dim = 1; dim <= array_type.rank; dim++) {
150 16 : ccode.add_assignment (get_array_length_cvalue (lvalue, dim), new CCodeConstant ("-1"));
151 : }
152 : }
153 :
154 2461 : if (array_type.rank == 1 && get_array_size_cvalue (lvalue) != null) {
155 495 : ccode.add_assignment (get_array_size_cvalue (lvalue), get_array_length_cvalue (lvalue, 1));
156 : }
157 : }
158 :
159 40546 : var delegate_type = lvalue.value_type as DelegateType;
160 41283 : if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
161 236 : var lvalue_target = get_delegate_target_cvalue (lvalue);
162 236 : var rvalue_target = get_delegate_target_cvalue (value);
163 464 : if (lvalue_target != null) {
164 228 : if (rvalue_target != null) {
165 227 : ccode.add_assignment (lvalue_target, rvalue_target);
166 : } else {
167 1 : Report.error (source_reference, "Assigning delegate without required target in scope");
168 1 : ccode.add_assignment (lvalue_target, new CCodeInvalidExpression ());
169 : }
170 228 : var lvalue_destroy_notify = get_delegate_target_destroy_notify_cvalue (lvalue);
171 228 : var rvalue_destroy_notify = get_delegate_target_destroy_notify_cvalue (value);
172 228 : if (lvalue_destroy_notify != null) {
173 133 : if (rvalue_destroy_notify != null) {
174 133 : ccode.add_assignment (lvalue_destroy_notify, rvalue_destroy_notify);
175 : } else {
176 0 : ccode.add_assignment (lvalue_destroy_notify, new CCodeConstant ("NULL"));
177 : }
178 : }
179 : }
180 : }
181 : }
182 :
183 9035 : public override void store_local (LocalVariable local, TargetValue value, bool initializer, SourceReference? source_reference = null) {
184 9035 : if (!initializer && requires_destroy (local.variable_type)) {
185 : /* unref old value */
186 817 : ccode.add_expression (destroy_local (local));
187 : }
188 :
189 9035 : store_value (get_local_cvalue (local), value, source_reference);
190 : }
191 :
192 674 : public override void store_parameter (Parameter param, TargetValue _value, bool capturing_parameter = false, SourceReference? source_reference = null) {
193 337 : var value = _value;
194 :
195 337 : bool capturing_parameter_in_coroutine = capturing_parameter && is_in_coroutine ();
196 :
197 337 : var param_type = param.variable_type.copy ();
198 337 : if (param.captured || is_in_coroutine ()) {
199 81 : 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 44 : param_type.value_owned = true;
203 :
204 44 : var old_coroutine = is_in_coroutine ();
205 44 : if (old_coroutine) {
206 27 : current_method.coroutine = false;
207 : }
208 :
209 44 : 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 21 : value = copy_value (value, param);
213 : }
214 :
215 44 : if (old_coroutine) {
216 27 : current_method.coroutine = true;
217 : }
218 : }
219 : }
220 :
221 337 : if (requires_destroy (param_type)) {
222 : /* unref old value */
223 100 : ccode.add_expression (destroy_parameter (param));
224 : }
225 :
226 337 : store_value (get_parameter_cvalue (param), value, source_reference);
227 : }
228 :
229 4554 : public override void store_field (Field field, TargetValue? instance, TargetValue value, bool initializer, SourceReference? source_reference = null) {
230 2277 : var lvalue = get_field_cvalue (field, instance);
231 2277 : var type = lvalue.value_type;
232 2277 : if (lvalue.actual_value_type != null) {
233 3912 : type = lvalue.actual_value_type;
234 : }
235 2277 : if (!initializer && (!(field.variable_type is DelegateType) || get_ccode_delegate_target (field)) && requires_destroy (type)) {
236 : /* unref old value */
237 1108 : ccode.add_expression (destroy_field (field, instance));
238 : }
239 2277 : if (initializer && instance != null && get_ccode_delegate_target (field) && get_delegate_target_cvalue (value) == null) {
240 1 : unowned DelegateType delegate_type = field.variable_type as DelegateType;
241 1 : if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
242 2 : ((GLibValue) value).delegate_target_cvalue = get_cvalue_ (instance);
243 : }
244 : }
245 :
246 2277 : store_value (lvalue, value, source_reference);
247 : }
248 : }
|