codegen: Drop unnecessary comma expressions when boxing values
[vala-lang.git] / codegen / valaccodearraymodule.vala
blob9a998d6c3a5f07ab660f31ddec1ad887e44c1a7a
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 var name_cnode = get_variable_cexpression (temp_var.name);
48 int i = 0;
50 emit_temp_var (temp_var);
52 append_initializer_list (name_cnode, expr.initializer_list, expr.rank, ref i);
54 set_cvalue (expr, name_cnode);
56 return;
59 CCodeFunctionCall gnew;
60 if (context.profile == Profile.POSIX) {
61 cfile.add_include ("stdlib.h");
62 gnew = new CCodeFunctionCall (new CCodeIdentifier ("calloc"));
63 } else {
64 gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
65 gnew.add_argument (new CCodeIdentifier (expr.element_type.get_cname ()));
68 bool first = true;
69 CCodeExpression cexpr = null;
71 // iterate over each dimension
72 foreach (Expression size in expr.get_sizes ()) {
73 CCodeExpression csize = get_cvalue (size);
75 if (!is_pure_ccode_expression (csize)) {
76 var temp_var = get_temp_variable (int_type, false, expr);
77 var name_cnode = get_variable_cexpression (temp_var.name);
78 set_cvalue (size, name_cnode);
80 emit_temp_var (temp_var);
82 csize = new CCodeAssignment (name_cnode, csize);
84 append_array_length (expr, name_cnode);
85 } else {
86 append_array_length (expr, csize);
89 if (first) {
90 cexpr = csize;
91 first = false;
92 } else {
93 cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, cexpr, csize);
97 // add extra item to have array NULL-terminated for all reference types
98 if (expr.element_type.data_type != null && expr.element_type.data_type.is_reference_type ()) {
99 cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, cexpr, new CCodeConstant ("1"));
102 gnew.add_argument (cexpr);
104 if (context.profile == Profile.POSIX) {
105 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
106 csizeof.add_argument (new CCodeIdentifier (expr.element_type.get_cname ()));
107 gnew.add_argument (csizeof);
110 var temp_var = get_temp_variable (expr.value_type, true, expr);
111 var name_cnode = get_variable_cexpression (temp_var.name);
112 int i = 0;
114 emit_temp_var (temp_var);
116 ccode.add_assignment (name_cnode, gnew);
118 if (expr.initializer_list != null) {
119 append_initializer_list (name_cnode, expr.initializer_list, expr.rank, ref i);
122 set_cvalue (expr, name_cnode);
125 public override string get_array_length_cname (string array_cname, int dim) {
126 return "%s_length%d".printf (array_cname, dim);
129 public override string get_parameter_array_length_cname (Parameter param, int dim) {
130 if (param.has_array_length_cname) {
131 return param.get_array_length_cname ();
132 } else {
133 return get_array_length_cname (get_variable_cname (param.name), dim);
137 public override CCodeExpression get_array_length_cexpression (Expression array_expr, int dim = -1) {
138 return get_array_length_cvalue (array_expr.target_value, dim);
141 public override CCodeExpression get_array_length_cvalue (TargetValue value, int dim = -1) {
142 var array_type = value.value_type as ArrayType;
144 if (array_type != null && array_type.fixed_length) {
145 return new CCodeConstant (array_type.length.to_string ());
148 // dim == -1 => total size over all dimensions
149 if (dim == -1) {
150 if (array_type != null && array_type.rank > 1) {
151 CCodeExpression cexpr = get_array_length_cvalue (value, 1);
152 for (dim = 2; dim <= array_type.rank; dim++) {
153 cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, cexpr, get_array_length_cvalue (value, dim));
155 return cexpr;
156 } else {
157 dim = 1;
161 List<CCodeExpression> size = ((GLibValue) value).array_length_cvalues;
162 assert (size != null && size.size >= dim);
163 return size[dim - 1];
166 public override string get_array_size_cname (string array_cname) {
167 return "_%s_size_".printf (array_cname);
170 public override void visit_element_access (ElementAccess expr) {
171 List<Expression> indices = expr.get_indices ();
172 int rank = indices.size;
174 var ccontainer = get_cvalue (expr.container);
175 var cindex = get_cvalue (indices[0]);
176 if (expr.container.symbol_reference is ArrayLengthField) {
177 /* Figure if cindex is a constant expression and calculate dim...*/
178 var lit = indices[0] as IntegerLiteral;
179 var memberaccess = expr.container as MemberAccess;
180 if (lit != null && memberaccess != null) {
181 int dim = int.parse (lit.value);
182 set_cvalue (expr, get_array_length_cexpression (memberaccess.inner, dim + 1));
183 } else {
184 Report.error (expr.source_reference, "only integer literals supported as index");
186 } else {
187 // access to element in an array
188 for (int i = 1; i < rank; i++) {
189 var cmul = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, cindex, get_array_length_cexpression (expr.container, i + 1));
190 cindex = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, cmul, get_cvalue (indices[i]));
192 set_cvalue (expr, new CCodeElementAccess (ccontainer, cindex));
196 public override void visit_slice_expression (SliceExpression expr) {
197 var ccontainer = get_cvalue (expr.container);
198 var cstart = get_cvalue (expr.start);
199 var cstop = get_cvalue (expr.stop);
201 var cstartpointer = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, ccontainer, cstart);
202 var splicelen = new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, cstop, cstart);
204 set_cvalue (expr, cstartpointer);
205 append_array_length (expr, splicelen);
208 void append_struct_array_free_loop (Struct st) {
209 var cforinit = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0"));
210 var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("array_length"));
211 var cforiter = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("i"), new CCodeConstant ("1")));
212 ccode.open_for (cforinit, cforcond, cforiter);
214 var cptrarray = new CCodeIdentifier ("array");
215 var cea = new CCodeElementAccess (cptrarray, new CCodeIdentifier ("i"));
217 var cfreecall = new CCodeFunctionCall (get_destroy_func_expression (new StructValueType (st)));
218 cfreecall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cea));
219 ccode.add_expression (cfreecall);
221 ccode.close ();
224 public override string? append_struct_array_free (Struct st) {
225 string cname = "_vala_%s_array_free".printf (st.get_cname ());;
227 if (cfile.add_declaration (cname)) {
228 return cname;
231 var fun = new CCodeFunction (cname, "void");
232 fun.modifiers = CCodeModifiers.STATIC;
233 fun.add_parameter (new CCodeParameter ("array", "%s*".printf (st.get_cname ())));
234 fun.add_parameter (new CCodeParameter ("array_length", "gint"));
236 push_function (fun);
238 var ccondarr = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("array"), new CCodeConstant ("NULL"));
239 ccode.open_if (ccondarr);
241 ccode.add_declaration ("int", new CCodeVariableDeclarator ("i"));
242 append_struct_array_free_loop (st);
244 ccode.close ();
246 var carrfree = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
247 carrfree.add_argument (new CCodeIdentifier ("array"));
248 ccode.add_expression (carrfree);
250 pop_function ();
252 cfile.add_function_declaration (fun);
253 cfile.add_function (fun);
255 return cname;
258 void append_vala_array_free_loop () {
259 var cforinit = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0"));
260 var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("array_length"));
261 var cforiter = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("i"), new CCodeConstant ("1")));
262 ccode.open_for (cforinit, cforcond, cforiter);
264 var cptrarray = new CCodeCastExpression (new CCodeIdentifier ("array"), "gpointer*");
265 var cea = new CCodeElementAccess (cptrarray, new CCodeIdentifier ("i"));
267 var cfreecond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, cea, new CCodeConstant ("NULL"));
268 ccode.open_if (cfreecond);
270 var cfreecall = new CCodeFunctionCall (new CCodeIdentifier ("destroy_func"));
271 cfreecall.add_argument (cea);
272 ccode.add_expression (cfreecall);
274 ccode.close ();
277 public override void append_vala_array_free () {
278 // _vala_array_destroy only frees elements but not the array itself
280 var fun = new CCodeFunction ("_vala_array_destroy", "void");
281 fun.modifiers = CCodeModifiers.STATIC;
282 fun.add_parameter (new CCodeParameter ("array", "gpointer"));
283 fun.add_parameter (new CCodeParameter ("array_length", "gint"));
284 fun.add_parameter (new CCodeParameter ("destroy_func", "GDestroyNotify"));
286 push_function (fun);
288 var ccondarr = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("array"), new CCodeConstant ("NULL"));
289 var ccondfunc = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("destroy_func"), new CCodeConstant ("NULL"));
290 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, ccondarr, ccondfunc));
292 ccode.add_declaration ("int", new CCodeVariableDeclarator ("i"));
293 append_vala_array_free_loop ();
295 ccode.close ();
297 pop_function ();
299 cfile.add_function_declaration (fun);
300 cfile.add_function (fun);
302 // _vala_array_free frees elements and array
304 fun = new CCodeFunction ("_vala_array_free", "void");
305 fun.modifiers = CCodeModifiers.STATIC;
306 fun.add_parameter (new CCodeParameter ("array", "gpointer"));
307 fun.add_parameter (new CCodeParameter ("array_length", "gint"));
308 fun.add_parameter (new CCodeParameter ("destroy_func", "GDestroyNotify"));
310 push_function (fun);
312 // call _vala_array_destroy to free the array elements
313 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_destroy"));
314 ccall.add_argument (new CCodeIdentifier ("array"));
315 ccall.add_argument (new CCodeIdentifier ("array_length"));
316 ccall.add_argument (new CCodeIdentifier ("destroy_func"));
317 ccode.add_expression (ccall);
319 var carrfree = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
320 carrfree.add_argument (new CCodeIdentifier ("array"));
321 ccode.add_expression (carrfree);
323 pop_function ();
325 cfile.add_function_declaration (fun);
326 cfile.add_function (fun);
329 public override void append_vala_array_move () {
330 cfile.add_include ("string.h");
332 // assumes that overwritten array elements are null before invocation
333 // FIXME will leak memory if that's not the case
334 var fun = new CCodeFunction ("_vala_array_move", "void");
335 fun.modifiers = CCodeModifiers.STATIC;
336 fun.add_parameter (new CCodeParameter ("array", "gpointer"));
337 fun.add_parameter (new CCodeParameter ("element_size", "gsize"));
338 fun.add_parameter (new CCodeParameter ("src", "gint"));
339 fun.add_parameter (new CCodeParameter ("dest", "gint"));
340 fun.add_parameter (new CCodeParameter ("length", "gint"));
342 push_function (fun);
344 var array = new CCodeCastExpression (new CCodeIdentifier ("array"), "char*");
345 var element_size = new CCodeIdentifier ("element_size");
346 var length = new CCodeIdentifier ("length");
347 var src = new CCodeIdentifier ("src");
348 var dest = new CCodeIdentifier ("dest");
349 var src_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, src, element_size));
350 var dest_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, dest, element_size));
351 var dest_end_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, dest, length), element_size));
353 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_memmove"));
354 ccall.add_argument (dest_address);
355 ccall.add_argument (src_address);
356 ccall.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, length, element_size));
357 ccode.add_expression (ccall);
359 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, src, dest));
361 var czero1 = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
362 czero1.add_argument (src_address);
363 czero1.add_argument (new CCodeConstant ("0"));
364 czero1.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, dest, src), element_size));
365 ccode.add_expression (czero1);
367 ccode.add_else ();
369 var czero2 = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
370 czero2.add_argument (dest_end_address);
371 czero2.add_argument (new CCodeConstant ("0"));
372 czero2.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, src, dest), element_size));
373 ccode.add_expression (czero2);
375 ccode.close ();
377 pop_function ();
379 cfile.add_function_declaration (fun);
380 cfile.add_function (fun);
383 public override void append_vala_array_length () {
384 var fun = new CCodeFunction ("_vala_array_length", "gint");
385 fun.modifiers = CCodeModifiers.STATIC;
386 fun.add_parameter (new CCodeParameter ("array", "gpointer"));
388 push_function (fun);
390 ccode.add_declaration ("int", new CCodeVariableDeclarator ("length", new CCodeConstant ("0")));
392 // return 0 if the array is NULL
393 // avoids an extra NULL check on the caller side
394 var array_check = new CCodeIdentifier ("array");
395 ccode.open_if (array_check);
397 var array_element_check = new CCodeElementAccess (new CCodeCastExpression (new CCodeIdentifier ("array"), "gpointer*"), new CCodeConstant ("length"));
398 ccode.open_while (array_element_check);
399 ccode.add_expression (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("length")));
400 ccode.close ();
402 ccode.close ();
404 ccode.add_return (new CCodeIdentifier ("length"));
406 pop_function ();
408 cfile.add_function_declaration (fun);
409 cfile.add_function (fun);
412 public override CCodeExpression? get_ref_cexpression (DataType expression_type, CCodeExpression cexpr, Expression? expr, CodeNode node) {
413 if (expression_type is ArrayType) {
414 var array_type = (ArrayType) expression_type;
416 if (!array_type.fixed_length) {
417 return base.get_ref_cexpression (expression_type, cexpr, expr, node);
420 var decl = get_temp_variable (expression_type, false, node);
421 emit_temp_var (decl);
423 var ctemp = get_variable_cexpression (decl.name);
425 var copy_call = new CCodeFunctionCall (new CCodeIdentifier (generate_array_copy_wrapper (array_type)));
426 copy_call.add_argument (cexpr);
427 copy_call.add_argument (ctemp);
429 var ccomma = new CCodeCommaExpression ();
431 ccomma.append_expression (copy_call);
432 ccomma.append_expression (ctemp);
434 return ccomma;
435 } else {
436 return base.get_ref_cexpression (expression_type, cexpr, expr, node);
440 public override CCodeExpression? get_dup_func_expression (DataType type, SourceReference? source_reference, bool is_chainup) {
441 if (type is ArrayType) {
442 var array_type = (ArrayType) type;
443 // fixed length arrays use different code
444 // generated by overridden get_ref_cexpression method
445 assert (!array_type.fixed_length);
446 return new CCodeIdentifier (generate_array_dup_wrapper (array_type));
447 } else {
448 return base.get_dup_func_expression (type, source_reference, is_chainup);
452 public override CCodeExpression destroy_variable (Variable variable, CCodeExpression? inner = null) {
453 var array_type = variable.variable_type as ArrayType;
454 if (array_type != null && array_type.fixed_length) {
455 requires_array_free = true;
457 var ccall = new CCodeFunctionCall (get_destroy_func_expression (variable.variable_type));
458 var value = get_variable_cvalue (variable);
460 ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_destroy"));
461 ccall.add_argument (get_cvalue_ (value));
462 ccall.add_argument (new CCodeConstant ("%d".printf (array_type.length)));
463 ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), "GDestroyNotify"));
465 return ccall;
468 return base.destroy_variable (variable, inner);
471 public override CCodeExpression destroy_value (TargetValue value, bool is_macro_definition = false) {
472 var type = value.value_type;
474 if (type is ArrayType) {
475 var array_type = (ArrayType) type;
477 if (!array_type.fixed_length) {
478 return base.destroy_value (value, is_macro_definition);
481 requires_array_free = true;
483 var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
485 ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_destroy"));
486 ccall.add_argument (get_cvalue_ (value));
487 ccall.add_argument (new CCodeConstant ("%d".printf (array_type.length)));
488 ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), "GDestroyNotify"));
490 return ccall;
491 } else {
492 return base.destroy_value (value, is_macro_definition);
496 string generate_array_dup_wrapper (ArrayType array_type) {
497 string dup_func = "_vala_array_dup%d".printf (++next_array_dup_id);
499 if (!add_wrapper (dup_func)) {
500 // wrapper already defined
501 return dup_func;
504 // declaration
506 var function = new CCodeFunction (dup_func, array_type.get_cname ());
507 function.modifiers = CCodeModifiers.STATIC;
509 function.add_parameter (new CCodeParameter ("self", array_type.get_cname ()));
510 // total length over all dimensions
511 function.add_parameter (new CCodeParameter ("length", "int"));
512 if (array_type.element_type is GenericType) {
513 // dup function array elements
514 string func_name = "%s_dup_func".printf (array_type.element_type.type_parameter.name.down ());
515 function.add_parameter (new CCodeParameter (func_name, "GBoxedCopyFunc"));
518 // definition
520 push_context (new EmitContext ());
521 push_function (function);
523 if (requires_copy (array_type.element_type)) {
524 var cvardecl = new CCodeVariableDeclarator ("result");
525 var gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
526 gnew.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
528 CCodeExpression length_expr = new CCodeIdentifier ("length");
529 // add extra item to have array NULL-terminated for all reference types
530 if (array_type.element_type.data_type != null && array_type.element_type.data_type.is_reference_type ()) {
531 length_expr = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, length_expr, new CCodeConstant ("1"));
533 gnew.add_argument (length_expr);
535 ccode.add_declaration (array_type.get_cname (), cvardecl);
536 ccode.add_assignment (new CCodeIdentifier ("result"), gnew);
538 ccode.add_declaration ("int", new CCodeVariableDeclarator ("i"));
540 ccode.open_for (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")),
541 new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("length")),
542 new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i")));
544 ccode.add_assignment (new CCodeElementAccess (new CCodeIdentifier ("result"), new CCodeIdentifier ("i")), get_ref_cexpression (array_type.element_type, new CCodeElementAccess (new CCodeIdentifier ("self"), new CCodeIdentifier ("i")), null, array_type));
545 ccode.close ();
547 ccode.add_return (new CCodeIdentifier ("result"));
548 } else {
549 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup"));
550 dup_call.add_argument (new CCodeIdentifier ("self"));
552 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
553 sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
554 dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeIdentifier ("length"), sizeof_call));
556 ccode.add_return (dup_call);
559 // append to file
561 cfile.add_function_declaration (function);
562 cfile.add_function (function);
564 pop_context ();
566 return dup_func;
569 string generate_array_copy_wrapper (ArrayType array_type) {
570 string dup_func = "_vala_array_copy%d".printf (++next_array_dup_id);
572 if (!add_wrapper (dup_func)) {
573 // wrapper already defined
574 return dup_func;
577 // declaration
579 var function = new CCodeFunction (dup_func, "void");
580 function.modifiers = CCodeModifiers.STATIC;
582 function.add_parameter (new CCodeParameter ("self", array_type.get_cname () + "*"));
583 function.add_parameter (new CCodeParameter ("dest", array_type.get_cname () + "*"));
585 // definition
587 push_context (new EmitContext ());
588 push_function (function);
590 if (requires_copy (array_type.element_type)) {
591 ccode.add_declaration ("int", new CCodeVariableDeclarator ("i"));
593 ccode.open_for (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")),
594 new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeConstant ("%d".printf (array_type.length))),
595 new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i")));
598 ccode.add_assignment (new CCodeElementAccess (new CCodeIdentifier ("dest"), new CCodeIdentifier ("i")), get_ref_cexpression (array_type.element_type, new CCodeElementAccess (new CCodeIdentifier ("self"), new CCodeIdentifier ("i")), null, array_type));
599 } else {
600 cfile.add_include ("string.h");
602 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
603 dup_call.add_argument (new CCodeIdentifier ("dest"));
604 dup_call.add_argument (new CCodeIdentifier ("self"));
606 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
607 sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
608 dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("%d".printf (array_type.length)), sizeof_call));
610 ccode.add_expression (dup_call);
613 // append to file
615 cfile.add_function_declaration (function);
616 cfile.add_function (function);
618 pop_context ();
620 return dup_func;
623 string generate_array_add_wrapper (ArrayType array_type) {
624 string add_func = "_vala_array_add%d".printf (++next_array_add_id);
626 if (!add_wrapper (add_func)) {
627 // wrapper already defined
628 return add_func;
631 var function = new CCodeFunction (add_func, "void");
632 function.modifiers = CCodeModifiers.STATIC;
634 function.add_parameter (new CCodeParameter ("array", array_type.get_cname () + "*"));
635 function.add_parameter (new CCodeParameter ("length", "int*"));
636 function.add_parameter (new CCodeParameter ("size", "int*"));
638 push_function (function);
640 string typename = array_type.element_type.get_cname ();
641 CCodeExpression value = new CCodeIdentifier ("value");
642 if (array_type.element_type.is_real_struct_type ()) {
643 if (!array_type.element_type.nullable || !array_type.element_type.value_owned) {
644 typename = "const " + typename;
646 if (!array_type.element_type.nullable) {
647 typename += "*";
648 value = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, value);
651 function.add_parameter (new CCodeParameter ("value", typename));
653 var array = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("array"));
654 var length = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("length"));
655 var size = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("size"));
657 var renew_call = new CCodeFunctionCall (new CCodeIdentifier ("g_renew"));
658 renew_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
659 renew_call.add_argument (array);
660 if (array_type.element_type.is_reference_type_or_type_parameter ()) {
661 // NULL terminate array
662 renew_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, size, new CCodeConstant ("1")));
663 } else {
664 renew_call.add_argument (size);
667 var csizecheck = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, length, size);
668 ccode.open_if (csizecheck);
669 ccode.add_assignment (size, new CCodeConditionalExpression (size, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("2"), size), new CCodeConstant ("4")));
670 ccode.add_assignment (array, renew_call);
671 ccode.close ();
673 ccode.add_assignment (new CCodeElementAccess (array, new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, length)), value);
675 if (array_type.element_type.is_reference_type_or_type_parameter ()) {
676 // NULL terminate array
677 ccode.add_assignment (new CCodeElementAccess (array, length), new CCodeConstant ("NULL"));
680 pop_function ();
682 cfile.add_function_declaration (function);
683 cfile.add_function (function);
685 return add_func;
688 bool is_array_add (Assignment assignment) {
689 var binary = assignment.right as BinaryExpression;
690 if (binary != null && binary.left.value_type is ArrayType) {
691 if (binary.operator == BinaryOperator.PLUS) {
692 if (assignment.left.symbol_reference == binary.left.symbol_reference) {
693 return true;
698 return false;
701 public override void visit_assignment (Assignment assignment) {
702 if (!is_array_add (assignment)) {
703 base.visit_assignment (assignment);
704 return;
707 var binary = (BinaryExpression) assignment.right;
709 var array = binary.left;
710 var array_type = (ArrayType) array.value_type;
711 var element = binary.right;
713 var array_var = assignment.left.symbol_reference;
714 if (array_type.rank == 1 && array_var != null && array_var.is_internal_symbol ()
715 && (array_var is LocalVariable || array_var is Field)) {
716 // valid array add
717 } else {
718 Report.error (assignment.source_reference, "Array concatenation not supported for public array variables and parameters");
719 return;
722 var value_param = new Parameter ("value", element.target_type);
724 var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_array_add_wrapper (array_type)));
725 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (array)));
726 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_length_cexpression (array)));
727 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_size_cvalue (array.target_value)));
728 ccall.add_argument (handle_struct_argument (value_param, element, get_cvalue (element)));
730 ccode.add_expression (ccall);
733 public override CCodeParameter generate_parameter (Parameter param, CCodeFile decl_space, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
734 if (!(param.variable_type is ArrayType)) {
735 return base.generate_parameter (param, decl_space, cparam_map, carg_map);
738 string ctypename = param.variable_type.get_cname ();
740 if (param.direction != ParameterDirection.IN) {
741 ctypename += "*";
744 var main_cparam = new CCodeParameter (get_variable_cname (param.name), ctypename);
746 var array_type = (ArrayType) param.variable_type;
748 generate_type_declaration (array_type.element_type, decl_space);
750 cparam_map.set (get_param_pos (param.cparameter_position), main_cparam);
751 if (carg_map != null) {
752 carg_map.set (get_param_pos (param.cparameter_position), get_variable_cexpression (param.name));
755 if (!param.no_array_length) {
756 string length_ctype = "int";
757 if (param.array_length_type != null) {
758 length_ctype = param.array_length_type;
760 if (param.direction != ParameterDirection.IN) {
761 length_ctype = "%s*".printf (length_ctype);
764 for (int dim = 1; dim <= array_type.rank; dim++) {
765 var cparam = new CCodeParameter (get_parameter_array_length_cname (param, dim), length_ctype);
766 cparam_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), cparam);
767 if (carg_map != null) {
768 carg_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), get_variable_cexpression (cparam.name));
773 return main_cparam;