GAsync: Another temp variable fix
[vala-lang.git] / codegen / valaccodeassignmentmodule.vala
blobab079ea0aa601c84a935a8b137efdb4b76707907
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
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
25 using GLib;
26 using Gee;
28 /**
29 * The link between an assignment and generated code.
31 internal class Vala.CCodeAssignmentModule : CCodeMemberAccessModule {
32 public CCodeAssignmentModule (CCodeGenerator codegen, CCodeModule? next) {
33 base (codegen, 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);
55 } else {
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;
86 } else {
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
100 return ccomma;
101 } else {
102 return ccall;
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);
113 bool array = false;
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);
144 temp_vars.insert (0, temp_decl);
145 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_decl.name), rhs));
146 if (unref_old) {
147 /* unref old value */
148 ccomma.append_expression (get_unref_expression (lhs, assignment.left.value_type, assignment.left));
151 if (array) {
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 var lhs_delegate_target = get_delegate_target_cexpression (assignment.left);
169 var rhs_delegate_target = get_delegate_target_cexpression (assignment.right);
170 ccomma.append_expression (new CCodeAssignment (lhs_delegate_target, rhs_delegate_target));
173 ccomma.append_expression (get_variable_cexpression (temp_decl.name));
175 rhs = ccomma;
178 var cop = CCodeAssignmentOperator.SIMPLE;
179 if (assignment.operator == AssignmentOperator.BITWISE_OR) {
180 cop = CCodeAssignmentOperator.BITWISE_OR;
181 } else if (assignment.operator == AssignmentOperator.BITWISE_AND) {
182 cop = CCodeAssignmentOperator.BITWISE_AND;
183 } else if (assignment.operator == AssignmentOperator.BITWISE_XOR) {
184 cop = CCodeAssignmentOperator.BITWISE_XOR;
185 } else if (assignment.operator == AssignmentOperator.ADD) {
186 cop = CCodeAssignmentOperator.ADD;
187 } else if (assignment.operator == AssignmentOperator.SUB) {
188 cop = CCodeAssignmentOperator.SUB;
189 } else if (assignment.operator == AssignmentOperator.MUL) {
190 cop = CCodeAssignmentOperator.MUL;
191 } else if (assignment.operator == AssignmentOperator.DIV) {
192 cop = CCodeAssignmentOperator.DIV;
193 } else if (assignment.operator == AssignmentOperator.PERCENT) {
194 cop = CCodeAssignmentOperator.PERCENT;
195 } else if (assignment.operator == AssignmentOperator.SHIFT_LEFT) {
196 cop = CCodeAssignmentOperator.SHIFT_LEFT;
197 } else if (assignment.operator == AssignmentOperator.SHIFT_RIGHT) {
198 cop = CCodeAssignmentOperator.SHIFT_RIGHT;
201 CCodeExpression codenode = new CCodeAssignment (lhs, rhs, cop);
203 if (outer_ccomma != null) {
204 outer_ccomma.append_expression (codenode);
205 codenode = outer_ccomma;
208 return codenode;
211 CCodeExpression emit_fixed_length_array_assignment (Assignment assignment, ArrayType array_type) {
212 CCodeExpression rhs = (CCodeExpression) assignment.right.ccodenode;
213 CCodeExpression lhs = (CCodeExpression) get_ccodenode (assignment.left);
215 source_declarations.add_include ("string.h");
217 // it is necessary to use memcpy for fixed-length (stack-allocated) arrays
218 // simple assignments do not work in C
219 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
220 sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
221 var size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("%d".printf (array_type.length)), sizeof_call);
222 var ccopy = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
223 ccopy.add_argument (lhs);
224 ccopy.add_argument (rhs);
225 ccopy.add_argument (size);
227 return ccopy;
230 public override void visit_assignment (Assignment assignment) {
231 assignment.right.accept (codegen);
233 if (assignment.left.error || assignment.right.error) {
234 assignment.error = true;
235 return;
238 if (assignment.left.symbol_reference is Property) {
239 assignment.ccodenode = emit_property_assignment (assignment);
240 } else {
241 var array_type = assignment.left.value_type as ArrayType;
242 if (array_type != null && array_type.fixed_length) {
243 assignment.ccodenode = emit_fixed_length_array_assignment (assignment, array_type);
244 } else {
245 assignment.ccodenode = emit_simple_assignment (assignment);