gtk+-3.0: Fix gtk_widget_adjust_size_* bindings
[vala-lang.git] / codegen / valaccodearraymodule.vala
blob3d9b0e9310f1ccdeb3641351406b4fb89c039dc4
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, TargetValue value) {
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));
459 ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_destroy"));
460 ccall.add_argument (get_cvalue_ (value));
461 ccall.add_argument (new CCodeConstant ("%d".printf (array_type.length)));
462 ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), "GDestroyNotify"));
464 return ccall;
467 return base.destroy_variable (variable, value);
470 public override CCodeExpression destroy_value (TargetValue value, bool is_macro_definition = false) {
471 var type = value.value_type;
473 if (type is ArrayType) {
474 var array_type = (ArrayType) type;
476 if (!array_type.fixed_length) {
477 return base.destroy_value (value, is_macro_definition);
480 requires_array_free = true;
482 var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
484 ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_destroy"));
485 ccall.add_argument (get_cvalue_ (value));
486 ccall.add_argument (new CCodeConstant ("%d".printf (array_type.length)));
487 ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), "GDestroyNotify"));
489 return ccall;
490 } else {
491 return base.destroy_value (value, is_macro_definition);
495 string generate_array_dup_wrapper (ArrayType array_type) {
496 string dup_func = "_vala_array_dup%d".printf (++next_array_dup_id);
498 if (!add_wrapper (dup_func)) {
499 // wrapper already defined
500 return dup_func;
503 // declaration
505 var function = new CCodeFunction (dup_func, array_type.get_cname ());
506 function.modifiers = CCodeModifiers.STATIC;
508 function.add_parameter (new CCodeParameter ("self", array_type.get_cname ()));
509 // total length over all dimensions
510 function.add_parameter (new CCodeParameter ("length", "int"));
511 if (array_type.element_type is GenericType) {
512 // dup function array elements
513 string func_name = "%s_dup_func".printf (array_type.element_type.type_parameter.name.down ());
514 function.add_parameter (new CCodeParameter (func_name, "GBoxedCopyFunc"));
517 // definition
519 push_context (new EmitContext ());
520 push_function (function);
522 if (requires_copy (array_type.element_type)) {
523 var cvardecl = new CCodeVariableDeclarator ("result");
524 var gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
525 gnew.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
527 CCodeExpression length_expr = new CCodeIdentifier ("length");
528 // add extra item to have array NULL-terminated for all reference types
529 if (array_type.element_type.data_type != null && array_type.element_type.data_type.is_reference_type ()) {
530 length_expr = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, length_expr, new CCodeConstant ("1"));
532 gnew.add_argument (length_expr);
534 ccode.add_declaration (array_type.get_cname (), cvardecl);
535 ccode.add_assignment (new CCodeIdentifier ("result"), gnew);
537 ccode.add_declaration ("int", new CCodeVariableDeclarator ("i"));
539 ccode.open_for (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")),
540 new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("length")),
541 new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i")));
543 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));
544 ccode.close ();
546 ccode.add_return (new CCodeIdentifier ("result"));
547 } else {
548 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup"));
549 dup_call.add_argument (new CCodeIdentifier ("self"));
551 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
552 sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
553 dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeIdentifier ("length"), sizeof_call));
555 ccode.add_return (dup_call);
558 // append to file
560 cfile.add_function_declaration (function);
561 cfile.add_function (function);
563 pop_context ();
565 return dup_func;
568 string generate_array_copy_wrapper (ArrayType array_type) {
569 string dup_func = "_vala_array_copy%d".printf (++next_array_dup_id);
571 if (!add_wrapper (dup_func)) {
572 // wrapper already defined
573 return dup_func;
576 // declaration
578 var function = new CCodeFunction (dup_func, "void");
579 function.modifiers = CCodeModifiers.STATIC;
581 function.add_parameter (new CCodeParameter ("self", array_type.get_cname () + "*"));
582 function.add_parameter (new CCodeParameter ("dest", array_type.get_cname () + "*"));
584 // definition
586 push_context (new EmitContext ());
587 push_function (function);
589 if (requires_copy (array_type.element_type)) {
590 ccode.add_declaration ("int", new CCodeVariableDeclarator ("i"));
592 ccode.open_for (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")),
593 new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeConstant ("%d".printf (array_type.length))),
594 new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i")));
597 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));
598 } else {
599 cfile.add_include ("string.h");
601 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
602 dup_call.add_argument (new CCodeIdentifier ("dest"));
603 dup_call.add_argument (new CCodeIdentifier ("self"));
605 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
606 sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
607 dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("%d".printf (array_type.length)), sizeof_call));
609 ccode.add_expression (dup_call);
612 // append to file
614 cfile.add_function_declaration (function);
615 cfile.add_function (function);
617 pop_context ();
619 return dup_func;
622 string generate_array_add_wrapper (ArrayType array_type) {
623 string add_func = "_vala_array_add%d".printf (++next_array_add_id);
625 if (!add_wrapper (add_func)) {
626 // wrapper already defined
627 return add_func;
630 var function = new CCodeFunction (add_func, "void");
631 function.modifiers = CCodeModifiers.STATIC;
633 function.add_parameter (new CCodeParameter ("array", array_type.get_cname () + "*"));
634 function.add_parameter (new CCodeParameter ("length", "int*"));
635 function.add_parameter (new CCodeParameter ("size", "int*"));
637 push_function (function);
639 string typename = array_type.element_type.get_cname ();
640 CCodeExpression value = new CCodeIdentifier ("value");
641 if (array_type.element_type.is_real_struct_type ()) {
642 if (!array_type.element_type.nullable || !array_type.element_type.value_owned) {
643 typename = "const " + typename;
645 if (!array_type.element_type.nullable) {
646 typename += "*";
647 value = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, value);
650 function.add_parameter (new CCodeParameter ("value", typename));
652 var array = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("array"));
653 var length = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("length"));
654 var size = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("size"));
656 var renew_call = new CCodeFunctionCall (new CCodeIdentifier ("g_renew"));
657 renew_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
658 renew_call.add_argument (array);
659 if (array_type.element_type.is_reference_type_or_type_parameter ()) {
660 // NULL terminate array
661 renew_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, size, new CCodeConstant ("1")));
662 } else {
663 renew_call.add_argument (size);
666 var csizecheck = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, length, size);
667 ccode.open_if (csizecheck);
668 ccode.add_assignment (size, new CCodeConditionalExpression (size, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("2"), size), new CCodeConstant ("4")));
669 ccode.add_assignment (array, renew_call);
670 ccode.close ();
672 ccode.add_assignment (new CCodeElementAccess (array, new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, length)), value);
674 if (array_type.element_type.is_reference_type_or_type_parameter ()) {
675 // NULL terminate array
676 ccode.add_assignment (new CCodeElementAccess (array, length), new CCodeConstant ("NULL"));
679 pop_function ();
681 cfile.add_function_declaration (function);
682 cfile.add_function (function);
684 return add_func;
687 bool is_array_add (Assignment assignment) {
688 var binary = assignment.right as BinaryExpression;
689 if (binary != null && binary.left.value_type is ArrayType) {
690 if (binary.operator == BinaryOperator.PLUS) {
691 if (assignment.left.symbol_reference == binary.left.symbol_reference) {
692 return true;
697 return false;
700 public override void visit_assignment (Assignment assignment) {
701 if (!is_array_add (assignment)) {
702 base.visit_assignment (assignment);
703 return;
706 var binary = (BinaryExpression) assignment.right;
708 var array = binary.left;
709 var array_type = (ArrayType) array.value_type;
710 var element = binary.right;
712 var array_var = assignment.left.symbol_reference;
713 if (array_type.rank == 1 && array_var != null && array_var.is_internal_symbol ()
714 && (array_var is LocalVariable || array_var is Field)) {
715 // valid array add
716 } else {
717 Report.error (assignment.source_reference, "Array concatenation not supported for public array variables and parameters");
718 return;
721 var value_param = new Parameter ("value", element.target_type);
723 var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_array_add_wrapper (array_type)));
724 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (array)));
725 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_length_cexpression (array)));
726 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_size_cvalue (array.target_value)));
727 ccall.add_argument (handle_struct_argument (value_param, element, get_cvalue (element)));
729 ccode.add_expression (ccall);
732 public override CCodeParameter generate_parameter (Parameter param, CCodeFile decl_space, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
733 if (!(param.variable_type is ArrayType)) {
734 return base.generate_parameter (param, decl_space, cparam_map, carg_map);
737 string ctypename = param.variable_type.get_cname ();
739 if (param.direction != ParameterDirection.IN) {
740 ctypename += "*";
743 var main_cparam = new CCodeParameter (get_variable_cname (param.name), ctypename);
745 var array_type = (ArrayType) param.variable_type;
747 generate_type_declaration (array_type.element_type, decl_space);
749 cparam_map.set (get_param_pos (param.cparameter_position), main_cparam);
750 if (carg_map != null) {
751 carg_map.set (get_param_pos (param.cparameter_position), get_variable_cexpression (param.name));
754 if (!param.no_array_length) {
755 string length_ctype = "int";
756 if (param.array_length_type != null) {
757 length_ctype = param.array_length_type;
759 if (param.direction != ParameterDirection.IN) {
760 length_ctype = "%s*".printf (length_ctype);
763 for (int dim = 1; dim <= array_type.rank; dim++) {
764 var cparam = new CCodeParameter (get_parameter_array_length_cname (param, dim), length_ctype);
765 cparam_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), cparam);
766 if (carg_map != null) {
767 carg_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), get_variable_cexpression (cparam.name));
772 return main_cparam;