fa2540ba1ae0700a96ff4ffad004704febe70ce7
[roobuilder] / src / codegen / valaccodeassignmentmodule.vala
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 public class Vala.CCodeAssignmentModule : CCodeMemberAccessModule {
31         TargetValue emit_simple_assignment (Assignment assignment) {
32                 if (requires_destroy (assignment.left.value_type)) {
33                         /* unref old value */
34                         ccode.add_expression (destroy_value (assignment.left.target_value));
35                 }
36
37                 if (assignment.operator == AssignmentOperator.SIMPLE) {
38                         store_value (assignment.left.target_value, assignment.right.target_value, assignment.source_reference);
39                 } else {
40                         CCodeAssignmentOperator cop;
41
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;
68                                 } else {
69                                         cop = CCodeAssignmentOperator.PERCENT;
70                                 }
71                                 break;
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 ();
75                         }
76
77                         CCodeExpression codenode = new CCodeAssignment (get_cvalue (assignment.left), get_cvalue (assignment.right), cop);
78                         ccode.add_expression (codenode);
79                 }
80
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);
84                 } else {
85                         return assignment.left.target_value;
86                 }
87         }
88
89         public override void visit_assignment (Assignment assignment) {
90                 if (assignment.left.error || assignment.right.error) {
91                         assignment.error = true;
92                         return;
93                 }
94
95                 if (assignment.left.symbol_reference is Property) {
96                         unowned MemberAccess ma = (MemberAccess) assignment.left;
97                         unowned Property prop = (Property) assignment.left.symbol_reference;
98
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
103                 } else {
104                         assignment.target_value = emit_simple_assignment (assignment);
105                 }
106         }
107
108         public override void store_value (TargetValue lvalue, TargetValue value, SourceReference? source_reference = null) {
109                 var array_type = lvalue.value_type as ArrayType;
110
111                 if (array_type != null && array_type.fixed_length) {
112                         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                         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);
119
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);
125
126                         return;
127                 }
128
129                 var cexpr = get_cvalue_ (value);
130                 if (get_ctype (lvalue) != null) {
131                         cexpr = new CCodeCastExpression (cexpr, get_ctype (lvalue));
132                 }
133
134                 ccode.add_assignment (get_cvalue_ (lvalue), cexpr);
135
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));
141                                 }
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));
146
147                                 ccode.add_assignment (get_array_length_cvalue (lvalue, 1), len_call);
148                         } else {
149                                 for (int dim = 1; dim <= array_type.rank; dim++) {
150                                         ccode.add_assignment (get_array_length_cvalue (lvalue, dim), new CCodeConstant ("-1"));
151                                 }
152                         }
153
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));
156                         }
157                 }
158
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);
166                                 } else {
167                                         Report.error (source_reference, "Assigning delegate without required target in scope");
168                                         ccode.add_assignment (lvalue_target, new CCodeInvalidExpression ());
169                                 }
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);
175                                         } else {
176                                                 ccode.add_assignment (lvalue_destroy_notify, new CCodeConstant ("NULL"));
177                                         }
178                                 }
179                         }
180                 }
181         }
182
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));
187                 }
188
189                 store_value (get_local_cvalue (local), value, source_reference);
190         }
191
192         public override void store_parameter (Parameter param, TargetValue _value, bool capturing_parameter = false, SourceReference? source_reference = null) {
193                 var value = _value;
194
195                 bool capturing_parameter_in_coroutine = capturing_parameter && is_in_coroutine ();
196
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;
203
204                                 var old_coroutine = is_in_coroutine ();
205                                 if (old_coroutine) {
206                                         current_method.coroutine = false;
207                                 }
208
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);
213                                 }
214
215                                 if (old_coroutine) {
216                                         current_method.coroutine = true;
217                                 }
218                         }
219                 }
220
221                 if (requires_destroy (param_type)) {
222                         /* unref old value */
223                         ccode.add_expression (destroy_parameter (param));
224                 }
225
226                 store_value (get_parameter_cvalue (param), value, source_reference);
227         }
228
229         public override void store_field (Vala.Field field, Vala.TargetValue? instance, Vala.TargetValue value, Vala.SourceReference? source_reference = null, bool initializer = false)
230         {
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;
235                 }
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));
239                 }
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);
244                         }
245                 }
246
247                 store_value (lvalue, value, source_reference);
248         }
249 }