codegen: Infer error parameter from abstract/virtual method implementations
[vala-gnome.git] / codegen / valaccodearraymodule.vala
blobea0a85ded308bda4062cc1d236d26e850da5608b
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 var gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
61 gnew.add_argument (new CCodeIdentifier (get_ccode_name (expr.element_type)));
63 bool first = true;
64 CCodeExpression cexpr = null;
66 // iterate over each dimension
67 foreach (Expression size in expr.get_sizes ()) {
68 CCodeExpression csize = get_cvalue (size);
69 append_array_length (expr, csize);
71 if (first) {
72 cexpr = csize;
73 first = false;
74 } else {
75 cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, cexpr, csize);
79 // add extra item to have array NULL-terminated for all reference types
80 if (expr.element_type.data_type != null && expr.element_type.data_type.is_reference_type ()) {
81 cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, cexpr, new CCodeConstant ("1"));
84 gnew.add_argument (cexpr);
86 var temp_var = get_temp_variable (expr.value_type, true, expr);
87 var name_cnode = get_variable_cexpression (temp_var.name);
88 int i = 0;
90 emit_temp_var (temp_var);
92 ccode.add_assignment (name_cnode, gnew);
94 if (expr.initializer_list != null) {
95 append_initializer_list (name_cnode, expr.initializer_list, expr.rank, ref i);
98 set_cvalue (expr, name_cnode);
101 public override string get_array_length_cname (string array_cname, int dim) {
102 return "%s_length%d".printf (array_cname, dim);
105 public override string get_parameter_array_length_cname (Parameter param, int dim) {
106 if (get_ccode_array_length_name (param) != null) {
107 return get_ccode_array_length_name (param);
108 } else {
109 return get_array_length_cname (get_variable_cname (param.name), dim);
113 public override CCodeExpression get_array_length_cexpression (Expression array_expr, int dim = -1) {
114 return get_array_length_cvalue (array_expr.target_value, dim);
117 public override CCodeExpression get_array_length_cvalue (TargetValue value, int dim = -1) {
118 var array_type = value.value_type as ArrayType;
120 if (array_type != null && array_type.fixed_length) {
121 return get_ccodenode (array_type.length);
124 // dim == -1 => total size over all dimensions
125 if (dim == -1) {
126 if (array_type != null && array_type.rank > 1) {
127 CCodeExpression cexpr = get_array_length_cvalue (value, 1);
128 for (dim = 2; dim <= array_type.rank; dim++) {
129 cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, cexpr, get_array_length_cvalue (value, dim));
131 return cexpr;
132 } else {
133 dim = 1;
137 List<CCodeExpression> size = ((GLibValue) value).array_length_cvalues;
138 assert (size != null && size.size >= dim);
139 return size[dim - 1];
142 public override string get_array_size_cname (string array_cname) {
143 return "_%s_size_".printf (array_cname);
146 public override void visit_element_access (ElementAccess expr) {
147 List<Expression> indices = expr.get_indices ();
148 int rank = indices.size;
150 var ccontainer = get_cvalue (expr.container);
151 var cindex = get_cvalue (indices[0]);
152 if (expr.container.symbol_reference is ArrayLengthField) {
153 /* Figure if cindex is a constant expression and calculate dim...*/
154 var lit = indices[0] as IntegerLiteral;
155 var memberaccess = expr.container as MemberAccess;
156 if (lit != null && memberaccess != null) {
157 int dim = int.parse (lit.value);
158 set_cvalue (expr, get_array_length_cexpression (memberaccess.inner, dim + 1));
159 } else {
160 Report.error (expr.source_reference, "only integer literals supported as index");
162 } else {
163 // access to element in an array
164 for (int i = 1; i < rank; i++) {
165 var cmul = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, cindex, get_array_length_cexpression (expr.container, i + 1));
166 cindex = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, cmul, get_cvalue (indices[i]));
168 set_cvalue (expr, new CCodeElementAccess (ccontainer, cindex));
171 expr.target_value.value_type = expr.value_type.copy ();
172 if (!expr.lvalue) {
173 expr.target_value = store_temp_value (expr.target_value, expr);
175 ((GLibValue) expr.target_value).lvalue = true;
178 public override void visit_slice_expression (SliceExpression expr) {
179 var ccontainer = get_cvalue (expr.container);
180 var cstart = get_cvalue (expr.start);
181 var cstop = get_cvalue (expr.stop);
183 var cstartpointer = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, ccontainer, cstart);
184 var splicelen = new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, cstop, cstart);
186 set_cvalue (expr, cstartpointer);
187 append_array_length (expr, splicelen);
190 void append_struct_array_free_loop (Struct st) {
191 var cforinit = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0"));
192 var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("array_length"));
193 var cforiter = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("i"), new CCodeConstant ("1")));
194 ccode.open_for (cforinit, cforcond, cforiter);
196 var cptrarray = new CCodeIdentifier ("array");
197 var cea = new CCodeElementAccess (cptrarray, new CCodeIdentifier ("i"));
199 var cfreecall = new CCodeFunctionCall (get_destroy_func_expression (new StructValueType (st)));
200 cfreecall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cea));
201 ccode.add_expression (cfreecall);
203 ccode.close ();
206 public override string? append_struct_array_free (Struct st) {
207 string cname = "_vala_%s_array_free".printf (get_ccode_name (st));
209 if (cfile.add_declaration (cname)) {
210 return cname;
213 var fun = new CCodeFunction (cname, "void");
214 fun.modifiers = CCodeModifiers.STATIC;
215 fun.add_parameter (new CCodeParameter ("array", "%s *".printf (get_ccode_name (st))));
216 fun.add_parameter (new CCodeParameter ("array_length", "gint"));
218 push_function (fun);
220 var ccondarr = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("array"), new CCodeConstant ("NULL"));
221 ccode.open_if (ccondarr);
223 ccode.add_declaration ("int", new CCodeVariableDeclarator ("i"));
224 append_struct_array_free_loop (st);
226 ccode.close ();
228 var carrfree = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
229 carrfree.add_argument (new CCodeIdentifier ("array"));
230 ccode.add_expression (carrfree);
232 pop_function ();
234 cfile.add_function_declaration (fun);
235 cfile.add_function (fun);
237 return cname;
240 void append_vala_array_free_loop () {
241 var cforinit = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0"));
242 var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("array_length"));
243 var cforiter = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("i"), new CCodeConstant ("1")));
244 ccode.open_for (cforinit, cforcond, cforiter);
246 var cptrarray = new CCodeCastExpression (new CCodeIdentifier ("array"), "gpointer*");
247 var cea = new CCodeElementAccess (cptrarray, new CCodeIdentifier ("i"));
249 var cfreecond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, cea, new CCodeConstant ("NULL"));
250 ccode.open_if (cfreecond);
252 var cfreecall = new CCodeFunctionCall (new CCodeIdentifier ("destroy_func"));
253 cfreecall.add_argument (cea);
254 ccode.add_expression (cfreecall);
256 ccode.close ();
259 public override void append_vala_array_free () {
260 // _vala_array_destroy only frees elements but not the array itself
262 var fun = new CCodeFunction ("_vala_array_destroy", "void");
263 fun.modifiers = CCodeModifiers.STATIC;
264 fun.add_parameter (new CCodeParameter ("array", "gpointer"));
265 fun.add_parameter (new CCodeParameter ("array_length", "gint"));
266 fun.add_parameter (new CCodeParameter ("destroy_func", "GDestroyNotify"));
268 push_function (fun);
270 var ccondarr = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("array"), new CCodeConstant ("NULL"));
271 var ccondfunc = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("destroy_func"), new CCodeConstant ("NULL"));
272 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, ccondarr, ccondfunc));
274 ccode.add_declaration ("int", new CCodeVariableDeclarator ("i"));
275 append_vala_array_free_loop ();
277 ccode.close ();
279 pop_function ();
281 cfile.add_function_declaration (fun);
282 cfile.add_function (fun);
284 // _vala_array_free frees elements and array
286 fun = new CCodeFunction ("_vala_array_free", "void");
287 fun.modifiers = CCodeModifiers.STATIC;
288 fun.add_parameter (new CCodeParameter ("array", "gpointer"));
289 fun.add_parameter (new CCodeParameter ("array_length", "gint"));
290 fun.add_parameter (new CCodeParameter ("destroy_func", "GDestroyNotify"));
292 push_function (fun);
294 // call _vala_array_destroy to free the array elements
295 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_destroy"));
296 ccall.add_argument (new CCodeIdentifier ("array"));
297 ccall.add_argument (new CCodeIdentifier ("array_length"));
298 ccall.add_argument (new CCodeIdentifier ("destroy_func"));
299 ccode.add_expression (ccall);
301 var carrfree = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
302 carrfree.add_argument (new CCodeIdentifier ("array"));
303 ccode.add_expression (carrfree);
305 pop_function ();
307 cfile.add_function_declaration (fun);
308 cfile.add_function (fun);
311 public override void append_vala_array_move () {
312 cfile.add_include ("string.h");
314 // assumes that overwritten array elements are null before invocation
315 // FIXME will leak memory if that's not the case
316 var fun = new CCodeFunction ("_vala_array_move", "void");
317 fun.modifiers = CCodeModifiers.STATIC;
318 fun.add_parameter (new CCodeParameter ("array", "gpointer"));
319 fun.add_parameter (new CCodeParameter ("element_size", "gsize"));
320 fun.add_parameter (new CCodeParameter ("src", "gint"));
321 fun.add_parameter (new CCodeParameter ("dest", "gint"));
322 fun.add_parameter (new CCodeParameter ("length", "gint"));
324 push_function (fun);
326 var array = new CCodeCastExpression (new CCodeIdentifier ("array"), "char*");
327 var element_size = new CCodeIdentifier ("element_size");
328 var length = new CCodeIdentifier ("length");
329 var src = new CCodeIdentifier ("src");
330 var src_end = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, src, length);
331 var dest = new CCodeIdentifier ("dest");
332 var dest_end = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, dest, length);
333 var src_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, src, element_size));
334 var dest_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, dest, element_size));
335 var dest_end_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, dest_end, element_size));
337 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_memmove"));
338 ccall.add_argument (dest_address);
339 ccall.add_argument (src_address);
340 ccall.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, length, element_size));
341 ccode.add_expression (ccall);
343 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, src, dest), new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, src_end, dest)));
345 var czero1 = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
346 czero1.add_argument (src_address);
347 czero1.add_argument (new CCodeConstant ("0"));
348 czero1.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, dest, src), element_size));
349 ccode.add_expression (czero1);
351 ccode.else_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, src, dest), new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, src, dest_end)));
353 var czero2 = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
354 czero2.add_argument (dest_end_address);
355 czero2.add_argument (new CCodeConstant ("0"));
356 czero2.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, src, dest), element_size));
357 ccode.add_expression (czero2);
359 ccode.else_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, src, dest));
361 var czero3 = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
362 czero3.add_argument (src_address);
363 czero3.add_argument (new CCodeConstant ("0"));
364 czero3.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, length, element_size));
365 ccode.add_expression (czero3);
367 ccode.close ();
369 pop_function ();
371 cfile.add_function_declaration (fun);
372 cfile.add_function (fun);
375 public override void append_vala_array_length () {
376 var fun = new CCodeFunction ("_vala_array_length", "gint");
377 fun.modifiers = CCodeModifiers.STATIC;
378 fun.add_parameter (new CCodeParameter ("array", "gpointer"));
380 push_function (fun);
382 ccode.add_declaration ("int", new CCodeVariableDeclarator ("length", new CCodeConstant ("0")));
384 // return 0 if the array is NULL
385 // avoids an extra NULL check on the caller side
386 var array_check = new CCodeIdentifier ("array");
387 ccode.open_if (array_check);
389 var array_element_check = new CCodeElementAccess (new CCodeCastExpression (new CCodeIdentifier ("array"), "gpointer*"), new CCodeConstant ("length"));
390 ccode.open_while (array_element_check);
391 ccode.add_expression (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("length")));
392 ccode.close ();
394 ccode.close ();
396 ccode.add_return (new CCodeIdentifier ("length"));
398 pop_function ();
400 cfile.add_function_declaration (fun);
401 cfile.add_function (fun);
404 public override TargetValue? copy_value (TargetValue value, CodeNode node) {
405 var type = value.value_type;
406 var cexpr = get_cvalue_ (value);
408 if (type is ArrayType) {
409 var array_type = (ArrayType) type;
411 if (!array_type.fixed_length) {
412 return base.copy_value (value, node);
415 var temp_value = create_temp_value (type, false, node);
417 var copy_call = new CCodeFunctionCall (new CCodeIdentifier (generate_array_copy_wrapper (array_type)));
418 copy_call.add_argument (cexpr);
419 copy_call.add_argument (get_cvalue_ (temp_value));
420 ccode.add_expression (copy_call);
422 return temp_value;
423 } else {
424 return base.copy_value (value, node);
428 public override CCodeExpression? get_dup_func_expression (DataType type, SourceReference? source_reference, bool is_chainup) {
429 if (type is ArrayType) {
430 var array_type = (ArrayType) type;
431 // fixed length arrays use different code
432 // generated by overridden get_ref_cexpression method
433 assert (!array_type.fixed_length);
434 return new CCodeIdentifier (generate_array_dup_wrapper (array_type));
435 } else {
436 return base.get_dup_func_expression (type, source_reference, is_chainup);
440 public override CCodeExpression destroy_value (TargetValue value, bool is_macro_definition = false) {
441 var type = value.value_type;
443 if (type is ArrayType) {
444 var array_type = (ArrayType) type;
446 if (!array_type.fixed_length) {
447 return base.destroy_value (value, is_macro_definition);
450 requires_array_free = true;
452 var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
454 ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_destroy"));
455 ccall.add_argument (get_cvalue_ (value));
456 ccall.add_argument (get_ccodenode (array_type.length));
457 ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), "GDestroyNotify"));
459 return ccall;
460 } else {
461 return base.destroy_value (value, is_macro_definition);
465 string generate_array_dup_wrapper (ArrayType array_type) {
466 string dup_func = "_vala_array_dup%d".printf (++next_array_dup_id);
468 if (!add_wrapper (dup_func)) {
469 // wrapper already defined
470 return dup_func;
473 // declaration
475 var function = new CCodeFunction (dup_func, get_ccode_name (array_type));
476 function.modifiers = CCodeModifiers.STATIC;
478 function.add_parameter (new CCodeParameter ("self", get_ccode_name (array_type)));
479 // total length over all dimensions
480 function.add_parameter (new CCodeParameter ("length", "int"));
481 if (array_type.element_type is GenericType) {
482 // dup function array elements
483 string func_name = "%s_dup_func".printf (array_type.element_type.type_parameter.name.down ());
484 function.add_parameter (new CCodeParameter (func_name, "GBoxedCopyFunc"));
487 // definition
489 push_context (new EmitContext ());
490 push_function (function);
492 if (requires_copy (array_type.element_type)) {
493 var cvardecl = new CCodeVariableDeclarator ("result");
494 var gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
495 gnew.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
497 CCodeExpression length_expr = new CCodeIdentifier ("length");
498 // add extra item to have array NULL-terminated for all reference types
499 if (array_type.element_type.data_type != null && array_type.element_type.data_type.is_reference_type ()) {
500 length_expr = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, length_expr, new CCodeConstant ("1"));
502 gnew.add_argument (length_expr);
504 ccode.add_declaration (get_ccode_name (array_type), cvardecl);
505 ccode.add_assignment (new CCodeIdentifier ("result"), gnew);
507 ccode.add_declaration ("int", new CCodeVariableDeclarator ("i"));
509 ccode.open_for (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")),
510 new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("length")),
511 new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i")));
513 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)));
514 ccode.close ();
516 ccode.add_return (new CCodeIdentifier ("result"));
517 } else {
518 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup"));
519 dup_call.add_argument (new CCodeIdentifier ("self"));
521 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
522 sizeof_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
523 dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeIdentifier ("length"), sizeof_call));
525 ccode.add_return (dup_call);
528 // append to file
530 cfile.add_function_declaration (function);
531 cfile.add_function (function);
533 pop_context ();
535 return dup_func;
538 string generate_array_copy_wrapper (ArrayType array_type) {
539 string dup_func = "_vala_array_copy%d".printf (++next_array_dup_id);
541 if (!add_wrapper (dup_func)) {
542 // wrapper already defined
543 return dup_func;
546 // declaration
548 var function = new CCodeFunction (dup_func, "void");
549 function.modifiers = CCodeModifiers.STATIC;
551 function.add_parameter (new CCodeParameter ("self", "%s *".printf (get_ccode_name (array_type))));
552 function.add_parameter (new CCodeParameter ("dest", "%s *".printf (get_ccode_name (array_type))));
554 // definition
556 push_context (new EmitContext ());
557 push_function (function);
559 if (requires_copy (array_type.element_type)) {
560 ccode.add_declaration ("int", new CCodeVariableDeclarator ("i"));
562 ccode.open_for (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")),
563 new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), get_ccodenode (array_type.length)),
564 new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i")));
567 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)));
568 } else {
569 cfile.add_include ("string.h");
571 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
572 dup_call.add_argument (new CCodeIdentifier ("dest"));
573 dup_call.add_argument (new CCodeIdentifier ("self"));
575 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
576 sizeof_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
577 dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, get_ccodenode (array_type.length), sizeof_call));
579 ccode.add_expression (dup_call);
582 // append to file
584 cfile.add_function_declaration (function);
585 cfile.add_function (function);
587 pop_context ();
589 return dup_func;
592 string generate_array_add_wrapper (ArrayType array_type) {
593 string add_func = "_vala_array_add%d".printf (++next_array_add_id);
595 if (!add_wrapper (add_func)) {
596 // wrapper already defined
597 return add_func;
600 var function = new CCodeFunction (add_func, "void");
601 function.modifiers = CCodeModifiers.STATIC;
603 function.add_parameter (new CCodeParameter ("array", "%s *".printf (get_ccode_name (array_type))));
604 function.add_parameter (new CCodeParameter ("length", "int*"));
605 function.add_parameter (new CCodeParameter ("size", "int*"));
607 push_function (function);
609 string typename = get_ccode_name (array_type.element_type);
610 CCodeExpression value = new CCodeIdentifier ("value");
611 if (array_type.element_type.is_real_struct_type ()) {
612 if (!array_type.element_type.nullable || !array_type.element_type.value_owned) {
613 typename = "const " + typename;
615 if (!array_type.element_type.nullable) {
616 typename += "*";
617 value = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, value);
620 function.add_parameter (new CCodeParameter ("value", typename));
622 var array = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("array"));
623 var length = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("length"));
624 var size = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("size"));
626 var renew_call = new CCodeFunctionCall (new CCodeIdentifier ("g_renew"));
627 renew_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
628 renew_call.add_argument (array);
629 if (array_type.element_type.is_reference_type_or_type_parameter ()) {
630 // NULL terminate array
631 renew_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, size, new CCodeConstant ("1")));
632 } else {
633 renew_call.add_argument (size);
636 var csizecheck = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, length, size);
637 ccode.open_if (csizecheck);
638 ccode.add_assignment (size, new CCodeConditionalExpression (size, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("2"), size), new CCodeConstant ("4")));
639 ccode.add_assignment (array, renew_call);
640 ccode.close ();
642 ccode.add_assignment (new CCodeElementAccess (array, new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, length)), value);
644 if (array_type.element_type.is_reference_type_or_type_parameter ()) {
645 // NULL terminate array
646 ccode.add_assignment (new CCodeElementAccess (array, length), new CCodeConstant ("NULL"));
649 pop_function ();
651 cfile.add_function_declaration (function);
652 cfile.add_function (function);
654 return add_func;
657 bool is_array_add (Assignment assignment) {
658 var binary = assignment.right as BinaryExpression;
659 if (binary != null && binary.left.value_type is ArrayType) {
660 if (binary.operator == BinaryOperator.PLUS) {
661 if (assignment.left.symbol_reference == binary.left.symbol_reference) {
662 return true;
667 return false;
670 public override void visit_assignment (Assignment assignment) {
671 if (!is_array_add (assignment)) {
672 base.visit_assignment (assignment);
673 return;
676 var binary = (BinaryExpression) assignment.right;
678 var array = assignment.left;
679 var array_type = (ArrayType) array.value_type;
680 var element = binary.right;
682 var array_var = array.symbol_reference;
683 if (array_type.rank == 1 && array_var != null && array_var.is_internal_symbol ()
684 && (array_var is LocalVariable || array_var is Field)) {
685 // valid array add
686 } else {
687 Report.error (assignment.source_reference, "Array concatenation not supported for public array variables and parameters");
688 return;
691 var value_param = new Parameter ("value", element.target_type);
693 var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_array_add_wrapper (array_type)));
694 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (array)));
695 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_length_cexpression (array)));
696 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_size_cvalue (array.target_value)));
697 ccall.add_argument (handle_struct_argument (value_param, element, get_cvalue (element)));
699 ccode.add_expression (ccall);
702 public override CCodeParameter generate_parameter (Parameter param, CCodeFile decl_space, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
703 if (!(param.variable_type is ArrayType)) {
704 return base.generate_parameter (param, decl_space, cparam_map, carg_map);
707 string ctypename = get_ccode_name (param.variable_type);
709 if (param.direction != ParameterDirection.IN) {
710 ctypename += "*";
713 var main_cparam = new CCodeParameter (get_variable_cname (param.name), ctypename);
715 var array_type = (ArrayType) param.variable_type;
717 generate_type_declaration (array_type.element_type, decl_space);
719 cparam_map.set (get_param_pos (get_ccode_pos (param)), main_cparam);
720 if (carg_map != null) {
721 carg_map.set (get_param_pos (get_ccode_pos (param)), get_variable_cexpression (param.name));
724 if (get_ccode_array_length (param)) {
725 string length_ctype = "int";
726 if (get_ccode_array_length_type (param) != null) {
727 length_ctype = get_ccode_array_length_type (param);
729 if (param.direction != ParameterDirection.IN) {
730 length_ctype = "%s*".printf (length_ctype);
733 for (int dim = 1; dim <= array_type.rank; dim++) {
734 var cparam = new CCodeParameter (get_parameter_array_length_cname (param, dim), length_ctype);
735 cparam_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), cparam);
736 if (carg_map != null) {
737 carg_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), get_variable_cexpression (cparam.name));
742 return main_cparam;