codegen: Use temporary variable for string concatenation
[vala-lang.git] / codegen / valaccodeassignmentmodule.vala
blob657d0e48ebd1c8945f71be4972602213834af954
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
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
25 using GLib;
27 /**
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);
38 bool array = false;
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);
63 if (unref_old) {
64 /* unref old value */
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);
125 return lhs;
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);
146 return lhs;
149 public override void visit_assignment (Assignment assignment) {
150 if (assignment.left.error || assignment.right.error) {
151 assignment.error = true;
152 return;
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));
162 } else {
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));
166 } else {
167 set_cvalue (assignment, emit_simple_assignment (assignment));
172 void store_variable (Variable variable, TargetValue lvalue, TargetValue value, bool initializer) {
173 if (!initializer && requires_destroy (variable.variable_type)) {
174 /* unref old value */
175 ccode.add_expression (destroy_value (lvalue));
178 ccode.add_assignment (get_cvalue_ (lvalue), get_cvalue_ (value));
180 var array_type = variable.variable_type as ArrayType;
181 if (array_type != null) {
182 if (array_type.fixed_length) {
183 cfile.add_include ("string.h");
185 // it is necessary to use memcpy for fixed-length (stack-allocated) arrays
186 // simple assignments do not work in C
187 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
188 sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
189 var size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("%d".printf (array_type.length)), sizeof_call);
191 var ccopy = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
192 ccopy.add_argument (get_cvalue_ (lvalue));
193 ccopy.add_argument (get_cvalue_ (value));
194 ccopy.add_argument (size);
195 ccode.add_expression (ccopy);
196 } else 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));
204 } else {
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 store_variable (local, get_local_cvalue (local), value, initializer);