vapigen: Remove misleading --metadata, each .gir must have its own .metadata.
[vala-lang.git] / codegen / valaccodeassignmentmodule.vala
blobc3604190d45ad379704983451949578567fe356d
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_property_assignment (Assignment assignment) {
32 var ma = assignment.left as MemberAccess;
34 var prop = (Property) assignment.left.symbol_reference;
36 if (!(prop is DynamicProperty)) {
37 generate_property_accessor_declaration (prop.set_accessor, cfile);
39 if (!prop.external && prop.external_package) {
40 // internal VAPI properties
41 // only add them once per source file
42 if (add_generated_external_symbol (prop)) {
43 visit_property (prop);
48 CCodeExpression cexpr = get_cvalue (assignment.right);
50 if (prop.property_type.is_real_non_null_struct_type ()) {
51 cexpr = get_address_of_expression (assignment.right, cexpr);
54 if (assignment.operator != AssignmentOperator.SIMPLE) {
55 CCodeBinaryOperator cop;
56 if (assignment.operator == AssignmentOperator.BITWISE_OR) {
57 cop = CCodeBinaryOperator.BITWISE_OR;
58 } else if (assignment.operator == AssignmentOperator.BITWISE_AND) {
59 cop = CCodeBinaryOperator.BITWISE_AND;
60 } else if (assignment.operator == AssignmentOperator.BITWISE_XOR) {
61 cop = CCodeBinaryOperator.BITWISE_XOR;
62 } else if (assignment.operator == AssignmentOperator.ADD) {
63 cop = CCodeBinaryOperator.PLUS;
64 } else if (assignment.operator == AssignmentOperator.SUB) {
65 cop = CCodeBinaryOperator.MINUS;
66 } else if (assignment.operator == AssignmentOperator.MUL) {
67 cop = CCodeBinaryOperator.MUL;
68 } else if (assignment.operator == AssignmentOperator.DIV) {
69 cop = CCodeBinaryOperator.DIV;
70 } else if (assignment.operator == AssignmentOperator.PERCENT) {
71 cop = CCodeBinaryOperator.MOD;
72 } else if (assignment.operator == AssignmentOperator.SHIFT_LEFT) {
73 cop = CCodeBinaryOperator.SHIFT_LEFT;
74 } else if (assignment.operator == AssignmentOperator.SHIFT_RIGHT) {
75 cop = CCodeBinaryOperator.SHIFT_RIGHT;
76 } else {
77 assert_not_reached ();
79 cexpr = new CCodeBinaryExpression (cop, (CCodeExpression) get_ccodenode (assignment.left), cexpr);
82 store_property (prop, ma, cexpr, assignment.right);
84 // assignments are expressions, so return the current property value, except if we're sure that it can't be used
85 if (assignment.parent_node is ExpressionStatement) {
86 return null;
87 } else {
88 return get_ccodenode (ma); // current property value
92 CCodeExpression? emit_simple_assignment (Assignment assignment) {
93 CCodeExpression rhs = get_cvalue (assignment.right);
94 CCodeExpression lhs = (CCodeExpression) get_ccodenode (assignment.left);
96 bool unref_old = requires_destroy (assignment.left.value_type);
97 bool array = false;
98 bool instance_delegate = false;
99 if (assignment.left.value_type is ArrayType) {
100 var array_field = assignment.left.symbol_reference as Field;
101 array = (array_field == null || !array_field.no_array_length);
102 } else if (assignment.left.value_type is DelegateType) {
103 var delegate_type = (DelegateType) assignment.left.value_type;
104 if (delegate_type.delegate_symbol.has_target) {
105 var delegate_field = assignment.left.symbol_reference as Field;
106 if (delegate_field == null || !delegate_field.no_delegate_target) {
107 instance_delegate = true;
112 if (unref_old || array || instance_delegate) {
113 if (!is_pure_ccode_expression (lhs)) {
114 /* Assign lhs to temp var to avoid repeating side effect */
115 var lhs_value_type = assignment.left.value_type.copy ();
116 string lhs_temp_name = "_tmp%d_".printf (next_temp_var_id++);
117 var lhs_temp = new LocalVariable (lhs_value_type, "*" + lhs_temp_name);
118 emit_temp_var (lhs_temp);
119 ccode.add_expression (new CCodeAssignment (get_variable_cexpression (lhs_temp_name), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, lhs)));
120 lhs = new CCodeParenthesizedExpression (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (lhs_temp_name)));
123 var temp_decl = get_temp_variable (assignment.left.value_type, true, null, false);
124 emit_temp_var (temp_decl);
125 ccode.add_expression (new CCodeAssignment (get_variable_cexpression (temp_decl.name), rhs));
126 if (unref_old) {
127 /* unref old value */
128 ccode.add_expression (get_unref_expression (lhs, assignment.left.value_type, assignment.left));
131 if (array) {
132 var array_type = (ArrayType) assignment.left.value_type;
133 for (int dim = 1; dim <= array_type.rank; dim++) {
134 var lhs_array_len = get_array_length_cexpression (assignment.left, dim);
135 var rhs_array_len = get_array_length_cexpression (assignment.right, dim);
136 ccode.add_expression (new CCodeAssignment (lhs_array_len, rhs_array_len));
138 if (array_type.rank == 1) {
139 var array_var = assignment.left.symbol_reference;
140 var array_local = array_var as LocalVariable;
141 if (array_var != null && array_var.is_internal_symbol ()
142 && ((array_var is LocalVariable && !array_local.captured) || array_var is Field)) {
143 var lhs_array_size = get_array_size_cvalue (assignment.left.target_value);
144 var rhs_array_len = get_array_length_cexpression (assignment.left, 1);
145 ccode.add_expression (new CCodeAssignment (lhs_array_size, rhs_array_len));
148 } else if (instance_delegate) {
149 CCodeExpression lhs_delegate_target_destroy_notify, rhs_delegate_target_destroy_notify;
150 var lhs_delegate_target = get_delegate_target_cexpression (assignment.left, out lhs_delegate_target_destroy_notify);
151 var rhs_delegate_target = get_delegate_target_cexpression (assignment.right, out rhs_delegate_target_destroy_notify);
152 ccode.add_expression (new CCodeAssignment (lhs_delegate_target, rhs_delegate_target));
153 if (assignment.right.target_type.value_owned) {
154 ccode.add_expression (new CCodeAssignment (lhs_delegate_target_destroy_notify, rhs_delegate_target_destroy_notify));
158 rhs = get_variable_cexpression (temp_decl.name);
161 var cop = CCodeAssignmentOperator.SIMPLE;
162 if (assignment.operator == AssignmentOperator.BITWISE_OR) {
163 cop = CCodeAssignmentOperator.BITWISE_OR;
164 } else if (assignment.operator == AssignmentOperator.BITWISE_AND) {
165 cop = CCodeAssignmentOperator.BITWISE_AND;
166 } else if (assignment.operator == AssignmentOperator.BITWISE_XOR) {
167 cop = CCodeAssignmentOperator.BITWISE_XOR;
168 } else if (assignment.operator == AssignmentOperator.ADD) {
169 cop = CCodeAssignmentOperator.ADD;
170 } else if (assignment.operator == AssignmentOperator.SUB) {
171 cop = CCodeAssignmentOperator.SUB;
172 } else if (assignment.operator == AssignmentOperator.MUL) {
173 cop = CCodeAssignmentOperator.MUL;
174 } else if (assignment.operator == AssignmentOperator.DIV) {
175 cop = CCodeAssignmentOperator.DIV;
176 } else if (assignment.operator == AssignmentOperator.PERCENT) {
177 cop = CCodeAssignmentOperator.PERCENT;
178 } else if (assignment.operator == AssignmentOperator.SHIFT_LEFT) {
179 cop = CCodeAssignmentOperator.SHIFT_LEFT;
180 } else if (assignment.operator == AssignmentOperator.SHIFT_RIGHT) {
181 cop = CCodeAssignmentOperator.SHIFT_RIGHT;
184 CCodeExpression codenode = new CCodeAssignment (lhs, rhs, cop);
186 ccode.add_expression (codenode);
188 if (assignment.parent_node is ExpressionStatement) {
189 return null;
190 } else {
191 return lhs;
195 CCodeExpression? emit_fixed_length_array_assignment (Assignment assignment, ArrayType array_type) {
196 CCodeExpression rhs = get_cvalue (assignment.right);
197 CCodeExpression lhs = (CCodeExpression) get_ccodenode (assignment.left);
199 cfile.add_include ("string.h");
201 // it is necessary to use memcpy for fixed-length (stack-allocated) arrays
202 // simple assignments do not work in C
203 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
204 sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
205 var size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("%d".printf (array_type.length)), sizeof_call);
206 var ccopy = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
207 ccopy.add_argument (lhs);
208 ccopy.add_argument (rhs);
209 ccopy.add_argument (size);
211 ccode.add_expression (ccopy);
213 if (assignment.parent_node is ExpressionStatement) {
214 return null;
215 } else {
216 return lhs;
220 public override void visit_assignment (Assignment assignment) {
221 if (assignment.left.error || assignment.right.error) {
222 assignment.error = true;
223 return;
226 if (assignment.left.symbol_reference is Property) {
227 set_cvalue (assignment, emit_property_assignment (assignment));
228 } else {
229 var array_type = assignment.left.value_type as ArrayType;
230 if (array_type != null && array_type.fixed_length) {
231 set_cvalue (assignment, emit_fixed_length_array_assignment (assignment, array_type));
232 } else {
233 set_cvalue (assignment, emit_simple_assignment (assignment));
238 void store_variable (Variable variable, TargetValue lvalue, TargetValue value) {
239 if (requires_destroy (variable.variable_type)) {
240 /* unref old value */
241 ccode.add_expression (destroy_value (lvalue));
244 ccode.add_expression (new CCodeAssignment (get_cvalue_ (lvalue), get_cvalue_ (value)));
246 var array_type = variable.variable_type as ArrayType;
247 if (array_type != null) {
248 for (int dim = 1; dim <= array_type.rank; dim++) {
249 if (get_array_length_cvalue (lvalue, dim) != null) {
250 ccode.add_expression (new CCodeAssignment (get_array_length_cvalue (lvalue, dim), get_array_length_cvalue (value, dim)));
253 if (array_type.rank == 1) {
254 if (get_array_size_cvalue (lvalue) != null) {
255 if (get_array_size_cvalue (value) != null) {
256 ccode.add_expression (new CCodeAssignment (get_array_size_cvalue (lvalue), get_array_size_cvalue (value)));
257 } else {
258 ccode.add_expression (new CCodeAssignment (get_array_size_cvalue (lvalue), get_array_length_cvalue (value, 1)));
264 var delegate_type = variable.variable_type as DelegateType;
265 if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
266 if (get_delegate_target_cvalue (lvalue) != null) {
267 ccode.add_expression (new CCodeAssignment (get_delegate_target_cvalue (lvalue), get_delegate_target_cvalue (value)));
268 if (get_delegate_target_destroy_notify_cvalue (lvalue) != null) {
269 ccode.add_expression (new CCodeAssignment (get_delegate_target_destroy_notify_cvalue (lvalue), get_delegate_target_destroy_notify_cvalue (value)));
275 public override void store_local (LocalVariable local, TargetValue value) {
276 store_variable (local, get_local_cvalue (local), value);