codegen: Fix floating reference regression with Variants
[vala-gnome.git] / codegen / valaccodearraymodule.vala
blobcd93775122421edb2af70b76ca7a73593df06ac7
1 /* valaccodearraymodule.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>
26 public class Vala.CCodeArrayModule : CCodeMethodCallModule {
27 int next_array_dup_id = 0;
28 int next_array_add_id = 0;
30 void append_initializer_list (CCodeExpression name_cnode, InitializerList initializer_list, int rank, ref int i) {
31 foreach (Expression e in initializer_list.get_initializers ()) {
32 if (rank > 1) {
33 append_initializer_list (name_cnode, (InitializerList) e, rank - 1, ref i);
34 } else {
35 ccode.add_assignment (new CCodeElementAccess (name_cnode, new CCodeConstant (i.to_string ())), get_cvalue (e));
36 i++;
41 public override void visit_array_creation_expression (ArrayCreationExpression expr) {
42 var array_type = expr.target_type as ArrayType;
43 if (array_type != null && array_type.fixed_length) {
44 // no heap allocation for fixed-length arrays
46 var temp_var = get_temp_variable (array_type, true, expr);
47 temp_var.init = true;
48 var name_cnode = get_variable_cexpression (temp_var.name);
49 int i = 0;
51 emit_temp_var (temp_var);
53 append_initializer_list (name_cnode, expr.initializer_list, expr.rank, ref i);
55 set_cvalue (expr, name_cnode);
57 return;
60 CCodeFunctionCall gnew;
61 if (context.profile == Profile.POSIX) {
62 cfile.add_include ("stdlib.h");
63 gnew = new CCodeFunctionCall (new CCodeIdentifier ("calloc"));
64 } else {
65 gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
66 gnew.add_argument (new CCodeIdentifier (get_ccode_name (expr.element_type)));
69 bool first = true;
70 CCodeExpression cexpr = null;
72 // iterate over each dimension
73 foreach (Expression size in expr.get_sizes ()) {
74 CCodeExpression csize = get_cvalue (size);
75 append_array_length (expr, csize);
77 if (first) {
78 cexpr = csize;
79 first = false;
80 } else {
81 cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, cexpr, csize);
85 // add extra item to have array NULL-terminated for all reference types
86 if (expr.element_type.data_type != null && expr.element_type.data_type.is_reference_type ()) {
87 cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, cexpr, new CCodeConstant ("1"));
90 gnew.add_argument (cexpr);
92 if (context.profile == Profile.POSIX) {
93 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
94 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (expr.element_type)));
95 gnew.add_argument (csizeof);
98 var temp_var = get_temp_variable (expr.value_type, true, expr);
99 var name_cnode = get_variable_cexpression (temp_var.name);
100 int i = 0;
102 emit_temp_var (temp_var);
104 ccode.add_assignment (name_cnode, gnew);
106 if (expr.initializer_list != null) {
107 append_initializer_list (name_cnode, expr.initializer_list, expr.rank, ref i);
110 set_cvalue (expr, name_cnode);
113 public override string get_array_length_cname (string array_cname, int dim) {
114 return "%s_length%d".printf (array_cname, dim);
117 public override string get_parameter_array_length_cname (Parameter param, int dim) {
118 if (get_ccode_array_length_name (param) != null) {
119 return get_ccode_array_length_name (param);
120 } else {
121 return get_array_length_cname (get_variable_cname (param.name), dim);
125 public override CCodeExpression get_array_length_cexpression (Expression array_expr, int dim = -1) {
126 return get_array_length_cvalue (array_expr.target_value, dim);
129 public override CCodeExpression get_array_length_cvalue (TargetValue value, int dim = -1) {
130 var array_type = value.value_type as ArrayType;
132 if (array_type != null && array_type.fixed_length) {
133 return get_ccodenode (array_type.length);
136 // dim == -1 => total size over all dimensions
137 if (dim == -1) {
138 if (array_type != null && array_type.rank > 1) {
139 CCodeExpression cexpr = get_array_length_cvalue (value, 1);
140 for (dim = 2; dim <= array_type.rank; dim++) {
141 cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, cexpr, get_array_length_cvalue (value, dim));
143 return cexpr;
144 } else {
145 dim = 1;
149 List<CCodeExpression> size = ((GLibValue) value).array_length_cvalues;
150 assert (size != null && size.size >= dim);
151 return size[dim - 1];
154 public override string get_array_size_cname (string array_cname) {
155 return "_%s_size_".printf (array_cname);
158 public override void visit_element_access (ElementAccess expr) {
159 List<Expression> indices = expr.get_indices ();
160 int rank = indices.size;
162 var ccontainer = get_cvalue (expr.container);
163 var cindex = get_cvalue (indices[0]);
164 if (expr.container.symbol_reference is ArrayLengthField) {
165 /* Figure if cindex is a constant expression and calculate dim...*/
166 var lit = indices[0] as IntegerLiteral;
167 var memberaccess = expr.container as MemberAccess;
168 if (lit != null && memberaccess != null) {
169 int dim = int.parse (lit.value);
170 set_cvalue (expr, get_array_length_cexpression (memberaccess.inner, dim + 1));
171 } else {
172 Report.error (expr.source_reference, "only integer literals supported as index");
174 } else {
175 // access to element in an array
176 for (int i = 1; i < rank; i++) {
177 var cmul = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, cindex, get_array_length_cexpression (expr.container, i + 1));
178 cindex = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, cmul, get_cvalue (indices[i]));
179 if (expr.container.is_constant ()) {
180 ccontainer = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, ccontainer);
183 set_cvalue (expr, new CCodeElementAccess (ccontainer, cindex));
186 expr.target_value.value_type = expr.value_type.copy ();
187 if (!expr.lvalue) {
188 expr.target_value = store_temp_value (expr.target_value, expr);
190 ((GLibValue) expr.target_value).lvalue = true;
193 public override void visit_slice_expression (SliceExpression expr) {
194 var ccontainer = get_cvalue (expr.container);
195 var cstart = get_cvalue (expr.start);
196 var cstop = get_cvalue (expr.stop);
198 var cstartpointer = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, ccontainer, cstart);
199 var splicelen = new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, cstop, cstart);
201 set_cvalue (expr, cstartpointer);
202 append_array_length (expr, splicelen);
205 void append_struct_array_free_loop (Struct st) {
206 var cforinit = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0"));
207 var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("array_length"));
208 var cforiter = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("i"), new CCodeConstant ("1")));
209 ccode.open_for (cforinit, cforcond, cforiter);
211 var cptrarray = new CCodeIdentifier ("array");
212 var cea = new CCodeElementAccess (cptrarray, new CCodeIdentifier ("i"));
214 var cfreecall = new CCodeFunctionCall (get_destroy_func_expression (new StructValueType (st)));
215 cfreecall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cea));
216 ccode.add_expression (cfreecall);
218 ccode.close ();
221 public override string? append_struct_array_free (Struct st) {
222 string cname = "_vala_%s_array_free".printf (get_ccode_name (st));
224 if (cfile.add_declaration (cname)) {
225 return cname;
228 var fun = new CCodeFunction (cname, "void");
229 fun.modifiers = CCodeModifiers.STATIC;
230 fun.add_parameter (new CCodeParameter ("array", "%s *".printf (get_ccode_name (st))));
231 fun.add_parameter (new CCodeParameter ("array_length", "gint"));
233 push_function (fun);
235 var ccondarr = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("array"), new CCodeConstant ("NULL"));
236 ccode.open_if (ccondarr);
238 ccode.add_declaration ("int", new CCodeVariableDeclarator ("i"));
239 append_struct_array_free_loop (st);
241 ccode.close ();
243 var carrfree = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
244 carrfree.add_argument (new CCodeIdentifier ("array"));
245 ccode.add_expression (carrfree);
247 pop_function ();
249 cfile.add_function_declaration (fun);
250 cfile.add_function (fun);
252 return cname;
255 void append_vala_array_free_loop () {
256 var cforinit = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0"));
257 var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("array_length"));
258 var cforiter = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("i"), new CCodeConstant ("1")));
259 ccode.open_for (cforinit, cforcond, cforiter);
261 var cptrarray = new CCodeCastExpression (new CCodeIdentifier ("array"), "gpointer*");
262 var cea = new CCodeElementAccess (cptrarray, new CCodeIdentifier ("i"));
264 var cfreecond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, cea, new CCodeConstant ("NULL"));
265 ccode.open_if (cfreecond);
267 var cfreecall = new CCodeFunctionCall (new CCodeIdentifier ("destroy_func"));
268 cfreecall.add_argument (cea);
269 ccode.add_expression (cfreecall);
271 ccode.close ();
274 public override void append_vala_array_free () {
275 // _vala_array_destroy only frees elements but not the array itself
277 var fun = new CCodeFunction ("_vala_array_destroy", "void");
278 fun.modifiers = CCodeModifiers.STATIC;
279 fun.add_parameter (new CCodeParameter ("array", "gpointer"));
280 fun.add_parameter (new CCodeParameter ("array_length", "gint"));
281 fun.add_parameter (new CCodeParameter ("destroy_func", "GDestroyNotify"));
283 push_function (fun);
285 var ccondarr = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("array"), new CCodeConstant ("NULL"));
286 var ccondfunc = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("destroy_func"), new CCodeConstant ("NULL"));
287 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, ccondarr, ccondfunc));
289 ccode.add_declaration ("int", new CCodeVariableDeclarator ("i"));
290 append_vala_array_free_loop ();
292 ccode.close ();
294 pop_function ();
296 cfile.add_function_declaration (fun);
297 cfile.add_function (fun);
299 // _vala_array_free frees elements and array
301 fun = new CCodeFunction ("_vala_array_free", "void");
302 fun.modifiers = CCodeModifiers.STATIC;
303 fun.add_parameter (new CCodeParameter ("array", "gpointer"));
304 fun.add_parameter (new CCodeParameter ("array_length", "gint"));
305 fun.add_parameter (new CCodeParameter ("destroy_func", "GDestroyNotify"));
307 push_function (fun);
309 // call _vala_array_destroy to free the array elements
310 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_destroy"));
311 ccall.add_argument (new CCodeIdentifier ("array"));
312 ccall.add_argument (new CCodeIdentifier ("array_length"));
313 ccall.add_argument (new CCodeIdentifier ("destroy_func"));
314 ccode.add_expression (ccall);
316 var carrfree = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
317 carrfree.add_argument (new CCodeIdentifier ("array"));
318 ccode.add_expression (carrfree);
320 pop_function ();
322 cfile.add_function_declaration (fun);
323 cfile.add_function (fun);
326 public override void append_vala_array_move () {
327 cfile.add_include ("string.h");
329 // assumes that overwritten array elements are null before invocation
330 // FIXME will leak memory if that's not the case
331 var fun = new CCodeFunction ("_vala_array_move", "void");
332 fun.modifiers = CCodeModifiers.STATIC;
333 fun.add_parameter (new CCodeParameter ("array", "gpointer"));
334 fun.add_parameter (new CCodeParameter ("element_size", "gsize"));
335 fun.add_parameter (new CCodeParameter ("src", "gint"));
336 fun.add_parameter (new CCodeParameter ("dest", "gint"));
337 fun.add_parameter (new CCodeParameter ("length", "gint"));
339 push_function (fun);
341 var array = new CCodeCastExpression (new CCodeIdentifier ("array"), "char*");
342 var element_size = new CCodeIdentifier ("element_size");
343 var length = new CCodeIdentifier ("length");
344 var src = new CCodeIdentifier ("src");
345 var src_end = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, src, length);
346 var dest = new CCodeIdentifier ("dest");
347 var dest_end = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, dest, length);
348 var src_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, src, element_size));
349 var dest_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, dest, element_size));
350 var dest_end_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, dest_end, element_size));
352 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_memmove"));
353 ccall.add_argument (dest_address);
354 ccall.add_argument (src_address);
355 ccall.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, length, element_size));
356 ccode.add_expression (ccall);
358 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, src, dest), new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, src_end, dest)));
360 var czero1 = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
361 czero1.add_argument (src_address);
362 czero1.add_argument (new CCodeConstant ("0"));
363 czero1.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, dest, src), element_size));
364 ccode.add_expression (czero1);
366 ccode.else_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, src, dest), new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, src, dest_end)));
368 var czero2 = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
369 czero2.add_argument (dest_end_address);
370 czero2.add_argument (new CCodeConstant ("0"));
371 czero2.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, src, dest), element_size));
372 ccode.add_expression (czero2);
374 ccode.else_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, src, dest));
376 var czero3 = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
377 czero3.add_argument (src_address);
378 czero3.add_argument (new CCodeConstant ("0"));
379 czero3.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, length, element_size));
380 ccode.add_expression (czero3);
382 ccode.close ();
384 pop_function ();
386 cfile.add_function_declaration (fun);
387 cfile.add_function (fun);
390 public override void append_vala_array_length () {
391 var fun = new CCodeFunction ("_vala_array_length", "gint");
392 fun.modifiers = CCodeModifiers.STATIC;
393 fun.add_parameter (new CCodeParameter ("array", "gpointer"));
395 push_function (fun);
397 ccode.add_declaration ("int", new CCodeVariableDeclarator ("length", new CCodeConstant ("0")));
399 // return 0 if the array is NULL
400 // avoids an extra NULL check on the caller side
401 var array_check = new CCodeIdentifier ("array");
402 ccode.open_if (array_check);
404 var array_element_check = new CCodeElementAccess (new CCodeCastExpression (new CCodeIdentifier ("array"), "gpointer*"), new CCodeConstant ("length"));
405 ccode.open_while (array_element_check);
406 ccode.add_expression (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("length")));
407 ccode.close ();
409 ccode.close ();
411 ccode.add_return (new CCodeIdentifier ("length"));
413 pop_function ();
415 cfile.add_function_declaration (fun);
416 cfile.add_function (fun);
419 public override TargetValue? copy_value (TargetValue value, CodeNode node) {
420 var type = value.value_type;
421 var cexpr = get_cvalue_ (value);
423 if (type is ArrayType) {
424 var array_type = (ArrayType) type;
426 if (!array_type.fixed_length) {
427 return base.copy_value (value, node);
430 var temp_value = create_temp_value (type, false, node);
432 var copy_call = new CCodeFunctionCall (new CCodeIdentifier (generate_array_copy_wrapper (array_type)));
433 copy_call.add_argument (cexpr);
434 copy_call.add_argument (get_cvalue_ (temp_value));
435 ccode.add_expression (copy_call);
437 return temp_value;
438 } else {
439 return base.copy_value (value, node);
443 public override CCodeExpression? get_dup_func_expression (DataType type, SourceReference? source_reference, bool is_chainup) {
444 if (type is ArrayType) {
445 var array_type = (ArrayType) type;
446 // fixed length arrays use different code
447 // generated by overridden get_ref_cexpression method
448 assert (!array_type.fixed_length);
449 return new CCodeIdentifier (generate_array_dup_wrapper (array_type));
450 } else {
451 return base.get_dup_func_expression (type, source_reference, is_chainup);
455 public override CCodeExpression destroy_value (TargetValue value, bool is_macro_definition = false) {
456 var type = value.value_type;
458 if (type is ArrayType) {
459 var array_type = (ArrayType) type;
461 if (!array_type.fixed_length) {
462 return base.destroy_value (value, is_macro_definition);
465 requires_array_free = true;
467 var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
469 ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_destroy"));
470 ccall.add_argument (get_cvalue_ (value));
471 ccall.add_argument (get_ccodenode (array_type.length));
472 ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), "GDestroyNotify"));
474 return ccall;
475 } else {
476 return base.destroy_value (value, is_macro_definition);
480 string generate_array_dup_wrapper (ArrayType array_type) {
481 string dup_func = "_vala_array_dup%d".printf (++next_array_dup_id);
483 if (!add_wrapper (dup_func)) {
484 // wrapper already defined
485 return dup_func;
488 // declaration
490 var function = new CCodeFunction (dup_func, get_ccode_name (array_type));
491 function.modifiers = CCodeModifiers.STATIC;
493 function.add_parameter (new CCodeParameter ("self", get_ccode_name (array_type)));
494 // total length over all dimensions
495 function.add_parameter (new CCodeParameter ("length", "int"));
496 if (array_type.element_type is GenericType) {
497 // dup function array elements
498 string func_name = "%s_dup_func".printf (((GenericType) array_type.element_type).type_parameter.name.down ());
499 function.add_parameter (new CCodeParameter (func_name, "GBoxedCopyFunc"));
502 // definition
504 push_context (new EmitContext ());
505 push_function (function);
507 if (requires_copy (array_type.element_type)) {
508 var cvardecl = new CCodeVariableDeclarator ("result");
509 var gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
510 gnew.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
512 CCodeExpression length_expr = new CCodeIdentifier ("length");
513 // add extra item to have array NULL-terminated for all reference types
514 if (array_type.element_type.data_type != null && array_type.element_type.data_type.is_reference_type ()) {
515 length_expr = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, length_expr, new CCodeConstant ("1"));
517 gnew.add_argument (length_expr);
519 ccode.add_declaration (get_ccode_name (array_type), cvardecl);
520 ccode.add_assignment (new CCodeIdentifier ("result"), gnew);
522 ccode.add_declaration ("int", new CCodeVariableDeclarator ("i"));
524 ccode.open_for (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")),
525 new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("length")),
526 new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i")));
528 ccode.add_assignment (new CCodeElementAccess (new CCodeIdentifier ("result"), new CCodeIdentifier ("i")), get_cvalue_ (copy_value (new GLibValue (array_type.element_type, new CCodeElementAccess (new CCodeIdentifier ("self"), new CCodeIdentifier ("i")), true), array_type)));
529 ccode.close ();
531 ccode.add_return (new CCodeIdentifier ("result"));
532 } else {
533 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup"));
534 dup_call.add_argument (new CCodeIdentifier ("self"));
536 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
537 sizeof_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
538 dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeIdentifier ("length"), sizeof_call));
540 ccode.add_return (dup_call);
543 // append to file
545 cfile.add_function_declaration (function);
546 cfile.add_function (function);
548 pop_context ();
550 return dup_func;
553 string generate_array_copy_wrapper (ArrayType array_type) {
554 string dup_func = "_vala_array_copy%d".printf (++next_array_dup_id);
556 if (!add_wrapper (dup_func)) {
557 // wrapper already defined
558 return dup_func;
561 // declaration
563 var function = new CCodeFunction (dup_func, "void");
564 function.modifiers = CCodeModifiers.STATIC;
566 function.add_parameter (new CCodeParameter ("self", "%s *".printf (get_ccode_name (array_type))));
567 function.add_parameter (new CCodeParameter ("dest", "%s *".printf (get_ccode_name (array_type))));
569 // definition
571 push_context (new EmitContext ());
572 push_function (function);
574 if (requires_copy (array_type.element_type)) {
575 ccode.add_declaration ("int", new CCodeVariableDeclarator ("i"));
577 ccode.open_for (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")),
578 new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), get_ccodenode (array_type.length)),
579 new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i")));
582 ccode.add_assignment (new CCodeElementAccess (new CCodeIdentifier ("dest"), new CCodeIdentifier ("i")), get_cvalue_ (copy_value (new GLibValue (array_type.element_type, new CCodeElementAccess (new CCodeIdentifier ("self"), new CCodeIdentifier ("i")), true), array_type)));
583 } else {
584 cfile.add_include ("string.h");
586 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
587 dup_call.add_argument (new CCodeIdentifier ("dest"));
588 dup_call.add_argument (new CCodeIdentifier ("self"));
590 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
591 sizeof_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
592 dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, get_ccodenode (array_type.length), sizeof_call));
594 ccode.add_expression (dup_call);
597 // append to file
599 cfile.add_function_declaration (function);
600 cfile.add_function (function);
602 pop_context ();
604 return dup_func;
607 string generate_array_add_wrapper (ArrayType array_type) {
608 string add_func = "_vala_array_add%d".printf (++next_array_add_id);
610 if (!add_wrapper (add_func)) {
611 // wrapper already defined
612 return add_func;
615 var function = new CCodeFunction (add_func, "void");
616 function.modifiers = CCodeModifiers.STATIC;
618 function.add_parameter (new CCodeParameter ("array", "%s *".printf (get_ccode_name (array_type))));
619 function.add_parameter (new CCodeParameter ("length", "int*"));
620 function.add_parameter (new CCodeParameter ("size", "int*"));
622 push_function (function);
624 string typename = get_ccode_name (array_type.element_type);
625 CCodeExpression value = new CCodeIdentifier ("value");
626 if (array_type.element_type.is_real_struct_type ()) {
627 if (!array_type.element_type.nullable || !array_type.element_type.value_owned) {
628 typename = "const " + typename;
630 if (!array_type.element_type.nullable) {
631 typename += "*";
632 value = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, value);
635 function.add_parameter (new CCodeParameter ("value", typename));
637 var array = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("array"));
638 var length = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("length"));
639 var size = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("size"));
641 var renew_call = new CCodeFunctionCall (new CCodeIdentifier ("g_renew"));
642 renew_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
643 renew_call.add_argument (array);
644 if (array_type.element_type.is_reference_type_or_type_parameter ()) {
645 // NULL terminate array
646 renew_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, size, new CCodeConstant ("1")));
647 } else {
648 renew_call.add_argument (size);
651 var csizecheck = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, length, size);
652 ccode.open_if (csizecheck);
653 ccode.add_assignment (size, new CCodeConditionalExpression (size, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("2"), size), new CCodeConstant ("4")));
654 ccode.add_assignment (array, renew_call);
655 ccode.close ();
657 ccode.add_assignment (new CCodeElementAccess (array, new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, length)), value);
659 if (array_type.element_type.is_reference_type_or_type_parameter ()) {
660 // NULL terminate array
661 ccode.add_assignment (new CCodeElementAccess (array, length), new CCodeConstant ("NULL"));
664 pop_function ();
666 cfile.add_function_declaration (function);
667 cfile.add_function (function);
669 return add_func;
672 bool is_array_add (Assignment assignment) {
673 var binary = assignment.right as BinaryExpression;
674 if (binary != null && binary.left.value_type is ArrayType) {
675 if (binary.operator == BinaryOperator.PLUS) {
676 if (assignment.left.symbol_reference == binary.left.symbol_reference) {
677 return true;
682 return false;
685 public override void visit_assignment (Assignment assignment) {
686 if (!is_array_add (assignment)) {
687 base.visit_assignment (assignment);
688 return;
691 var binary = (BinaryExpression) assignment.right;
693 var array = assignment.left;
694 var array_type = (ArrayType) array.value_type;
695 var element = binary.right;
697 var array_var = array.symbol_reference;
698 if (array_type.rank == 1 && array_var != null && array_var.is_internal_symbol ()
699 && (array_var is LocalVariable || array_var is Field)) {
700 // valid array add
701 } else {
702 Report.error (assignment.source_reference, "Array concatenation not supported for public array variables and parameters");
703 return;
706 var value_param = new Parameter ("value", element.target_type);
708 var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_array_add_wrapper (array_type)));
709 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (array)));
710 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_length_cexpression (array)));
711 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_size_cvalue (array.target_value)));
712 ccall.add_argument (handle_struct_argument (value_param, element, get_cvalue (element)));
714 ccode.add_expression (ccall);
717 public override CCodeParameter generate_parameter (Parameter param, CCodeFile decl_space, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
718 if (!(param.variable_type is ArrayType)) {
719 return base.generate_parameter (param, decl_space, cparam_map, carg_map);
722 string ctypename = get_ccode_name (param.variable_type);
724 if (param.direction != ParameterDirection.IN) {
725 ctypename += "*";
728 var main_cparam = new CCodeParameter (get_variable_cname (param.name), ctypename);
730 var array_type = (ArrayType) param.variable_type;
732 generate_type_declaration (array_type.element_type, decl_space);
734 cparam_map.set (get_param_pos (get_ccode_pos (param)), main_cparam);
735 if (carg_map != null) {
736 carg_map.set (get_param_pos (get_ccode_pos (param)), get_variable_cexpression (param.name));
739 if (get_ccode_array_length (param)) {
740 string length_ctype = "int";
741 if (get_ccode_array_length_type (param) != null) {
742 length_ctype = get_ccode_array_length_type (param);
744 if (param.direction != ParameterDirection.IN) {
745 length_ctype = "%s*".printf (length_ctype);
748 for (int dim = 1; dim <= array_type.rank; dim++) {
749 var cparam = new CCodeParameter (get_parameter_array_length_cname (param, dim), length_ctype);
750 cparam_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), cparam);
751 if (carg_map != null) {
752 carg_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), get_variable_cexpression (cparam.name));
757 return main_cparam;